From 03dfdeb0cdfed398eab752dc9959885bc24b5663 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 24 Sep 2026 14:26:14 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=ED=96=A5=EC=83=81=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EB=84=A4=EC=9D=B4=ED=8B=B0=EB=B8=8C=20title=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=EC=9D=84=20Tooltip=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 4 + apps/desktop/src/App.test.tsx | 4 +- apps/desktop/src/App.tsx | 141 ++++++++++++++++++---------------- 3 files changed, 81 insertions(+), 68 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index c05638899..ecba8a642 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,7 @@ ## 2024-05-19 - Replace HTML disabled with aria-disabled="true" for Accessible Tooltips **Learning:** Native HTML `disabled` attributes completely hide elements from screen readers and block all pointer/hover events, preventing tooltips from functioning for disabled elements. **Action:** Replace `disabled` with `aria-disabled="true"`, enforce block click handlers via `e.preventDefault()`, and add a title tooltip directly to the element to maintain full tooltip accessibility and keyboard focus support for visually impaired and mouse users. +## 2026-09-24 - Accessible tooltips instead of title + +**Learning:** When adding tooltips to icon-only buttons, especially those using `aria-disabled={true}`, do not use the native HTML title attribute as it lacks keyboard/touch support. +**Action:** Wrap the element in the custom Tooltip components (@/components/ui/tooltip). diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 3eed386f8..58d217e7e 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -225,7 +225,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(primaryNav).getByRole("button", { name }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(primaryNav).getByRole("button", { name: "Import" })); @@ -236,7 +236,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(compactNav).getByRole("button", { name: `${name} compact view` }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(compactNav).getByRole("button", { name: "Import compact view" })); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index f3d678454..720966791 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -51,6 +51,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Progress } from "@/components/ui/progress"; import { Toaster } from "@/components/ui/sonner"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; const ANALYSIS_POLL_INTERVAL_MS = 250; const MAX_ERROR_DETAIL_LENGTH = 220; @@ -566,24 +567,25 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white shadow-[0_12px_30px_rgba(37,99,235,0.32)]" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -611,26 +613,30 @@ export function App() {
- - + + + + {t("settingsComingSoon")} + + + + + {t("helpComingSoon")} +
@@ -642,25 +648,26 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`inline-flex min-h-10 shrink-0 items-center gap-2 rounded-xl px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -709,15 +716,17 @@ export function App() { aria-describedby={selectionError && selectionErrorSource === "youtube" ? "selection-error" : undefined} /> {youtubeUrl && !analysisInFlight && !isStarting && !isImporting ? ( - + + + + {t("clearYoutubeUrl")} + ) : null} From d1851d0ae9ba4a2f61600569f6a507a0204091ee Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 24 Sep 2026 23:58:52 +0900 Subject: [PATCH 2/5] preserve(ui): route duplicate App tooltip delta to canonical #1193 --- .jules/palette.md | 4 - apps/desktop/src/App.test.tsx | 4 +- apps/desktop/src/App.tsx | 141 ++++++++++++++++------------------ 3 files changed, 68 insertions(+), 81 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index ecba8a642..c05638899 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,7 +1,3 @@ ## 2024-05-19 - Replace HTML disabled with aria-disabled="true" for Accessible Tooltips **Learning:** Native HTML `disabled` attributes completely hide elements from screen readers and block all pointer/hover events, preventing tooltips from functioning for disabled elements. **Action:** Replace `disabled` with `aria-disabled="true"`, enforce block click handlers via `e.preventDefault()`, and add a title tooltip directly to the element to maintain full tooltip accessibility and keyboard focus support for visually impaired and mouse users. -## 2026-09-24 - Accessible tooltips instead of title - -**Learning:** When adding tooltips to icon-only buttons, especially those using `aria-disabled={true}`, do not use the native HTML title attribute as it lacks keyboard/touch support. -**Action:** Wrap the element in the custom Tooltip components (@/components/ui/tooltip). diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 58d217e7e..3eed386f8 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -225,7 +225,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(primaryNav).getByRole("button", { name }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).not.toHaveAttribute("title"); + expect(navButton).toHaveAttribute("title", "Coming soon"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(primaryNav).getByRole("button", { name: "Import" })); @@ -236,7 +236,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(compactNav).getByRole("button", { name: `${name} compact view` }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).not.toHaveAttribute("title"); + expect(navButton).toHaveAttribute("title", "Coming soon"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(compactNav).getByRole("button", { name: "Import compact view" })); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 720966791..f3d678454 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -51,7 +51,6 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Progress } from "@/components/ui/progress"; import { Toaster } from "@/components/ui/sonner"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; const ANALYSIS_POLL_INTERVAL_MS = 250; const MAX_ERROR_DETAIL_LENGTH = 220; @@ -567,25 +566,24 @@ export function App() { const { icon: Icon, view } = item; return ( - - handleNavSelect(view) : blockInactiveNavActivation} - className={`flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ - active - ? "bg-blue-600/70 text-white shadow-[0_12px_30px_rgba(37,99,235,0.32)]" - : enabled - ? "text-slate-200 hover:bg-white/5" - : "cursor-not-allowed text-slate-500 opacity-70" - }`} - > - - {title ? {title} : null} - + ); })} @@ -613,30 +611,26 @@ export function App() {
- - - - {t("settingsComingSoon")} - - - - - {t("helpComingSoon")} - + +
@@ -648,26 +642,25 @@ export function App() { const { icon: Icon, view } = item; return ( - - handleNavSelect(view) : blockInactiveNavActivation} - className={`inline-flex min-h-10 shrink-0 items-center gap-2 rounded-xl px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ - active - ? "bg-blue-600/70 text-white" - : enabled - ? "text-slate-200 hover:bg-white/5" - : "cursor-not-allowed text-slate-500 opacity-70" - }`} - > - - {title ? {title} : null} - + ); })} @@ -716,17 +709,15 @@ export function App() { aria-describedby={selectionError && selectionErrorSource === "youtube" ? "selection-error" : undefined} /> {youtubeUrl && !analysisInFlight && !isStarting && !isImporting ? ( - - - - {t("clearYoutubeUrl")} - + ) : null} From 8b01c1a03728456e3408b3ab18c564f3c98c313d Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 25 Sep 2026 00:33:22 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=ED=96=A5=EC=83=81=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EB=84=A4=EC=9D=B4=ED=8B=B0=EB=B8=8C=20title=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=EC=9D=84=20Tooltip=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 4 + apps/desktop/src/App.test.tsx | 4 +- apps/desktop/src/App.tsx | 141 ++++++++++++++++++---------------- 3 files changed, 81 insertions(+), 68 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index c05638899..ecba8a642 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,7 @@ ## 2024-05-19 - Replace HTML disabled with aria-disabled="true" for Accessible Tooltips **Learning:** Native HTML `disabled` attributes completely hide elements from screen readers and block all pointer/hover events, preventing tooltips from functioning for disabled elements. **Action:** Replace `disabled` with `aria-disabled="true"`, enforce block click handlers via `e.preventDefault()`, and add a title tooltip directly to the element to maintain full tooltip accessibility and keyboard focus support for visually impaired and mouse users. +## 2026-09-24 - Accessible tooltips instead of title + +**Learning:** When adding tooltips to icon-only buttons, especially those using `aria-disabled={true}`, do not use the native HTML title attribute as it lacks keyboard/touch support. +**Action:** Wrap the element in the custom Tooltip components (@/components/ui/tooltip). diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 3eed386f8..58d217e7e 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -225,7 +225,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(primaryNav).getByRole("button", { name }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(primaryNav).getByRole("button", { name: "Import" })); @@ -236,7 +236,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(compactNav).getByRole("button", { name: `${name} compact view` }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(compactNav).getByRole("button", { name: "Import compact view" })); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index f3d678454..720966791 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -51,6 +51,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Progress } from "@/components/ui/progress"; import { Toaster } from "@/components/ui/sonner"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; const ANALYSIS_POLL_INTERVAL_MS = 250; const MAX_ERROR_DETAIL_LENGTH = 220; @@ -566,24 +567,25 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white shadow-[0_12px_30px_rgba(37,99,235,0.32)]" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -611,26 +613,30 @@ export function App() {
- - + + + + {t("settingsComingSoon")} + + + + + {t("helpComingSoon")} +
@@ -642,25 +648,26 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`inline-flex min-h-10 shrink-0 items-center gap-2 rounded-xl px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -709,15 +716,17 @@ export function App() { aria-describedby={selectionError && selectionErrorSource === "youtube" ? "selection-error" : undefined} /> {youtubeUrl && !analysisInFlight && !isStarting && !isImporting ? ( - + + + + {t("clearYoutubeUrl")} + ) : null} From 70bb7db36244decbc1a4c66f6ef6a155e2170d12 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 25 Sep 2026 09:59:43 +0900 Subject: [PATCH 4/5] preserve(ui): remove recurring duplicate App tooltip delta --- .jules/palette.md | 4 - apps/desktop/src/App.test.tsx | 4 +- apps/desktop/src/App.tsx | 141 ++++++++++++++++------------------ 3 files changed, 68 insertions(+), 81 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index ecba8a642..c05638899 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,7 +1,3 @@ ## 2024-05-19 - Replace HTML disabled with aria-disabled="true" for Accessible Tooltips **Learning:** Native HTML `disabled` attributes completely hide elements from screen readers and block all pointer/hover events, preventing tooltips from functioning for disabled elements. **Action:** Replace `disabled` with `aria-disabled="true"`, enforce block click handlers via `e.preventDefault()`, and add a title tooltip directly to the element to maintain full tooltip accessibility and keyboard focus support for visually impaired and mouse users. -## 2026-09-24 - Accessible tooltips instead of title - -**Learning:** When adding tooltips to icon-only buttons, especially those using `aria-disabled={true}`, do not use the native HTML title attribute as it lacks keyboard/touch support. -**Action:** Wrap the element in the custom Tooltip components (@/components/ui/tooltip). diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 58d217e7e..3eed386f8 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -225,7 +225,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(primaryNav).getByRole("button", { name }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).not.toHaveAttribute("title"); + expect(navButton).toHaveAttribute("title", "Coming soon"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(primaryNav).getByRole("button", { name: "Import" })); @@ -236,7 +236,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(compactNav).getByRole("button", { name: `${name} compact view` }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).not.toHaveAttribute("title"); + expect(navButton).toHaveAttribute("title", "Coming soon"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(compactNav).getByRole("button", { name: "Import compact view" })); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 720966791..f3d678454 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -51,7 +51,6 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Progress } from "@/components/ui/progress"; import { Toaster } from "@/components/ui/sonner"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; const ANALYSIS_POLL_INTERVAL_MS = 250; const MAX_ERROR_DETAIL_LENGTH = 220; @@ -567,25 +566,24 @@ export function App() { const { icon: Icon, view } = item; return ( - - handleNavSelect(view) : blockInactiveNavActivation} - className={`flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ - active - ? "bg-blue-600/70 text-white shadow-[0_12px_30px_rgba(37,99,235,0.32)]" - : enabled - ? "text-slate-200 hover:bg-white/5" - : "cursor-not-allowed text-slate-500 opacity-70" - }`} - > - - {title ? {title} : null} - + ); })} @@ -613,30 +611,26 @@ export function App() {
- - - - {t("settingsComingSoon")} - - - - - {t("helpComingSoon")} - + +
@@ -648,26 +642,25 @@ export function App() { const { icon: Icon, view } = item; return ( - - handleNavSelect(view) : blockInactiveNavActivation} - className={`inline-flex min-h-10 shrink-0 items-center gap-2 rounded-xl px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ - active - ? "bg-blue-600/70 text-white" - : enabled - ? "text-slate-200 hover:bg-white/5" - : "cursor-not-allowed text-slate-500 opacity-70" - }`} - > - - {title ? {title} : null} - + ); })} @@ -716,17 +709,15 @@ export function App() { aria-describedby={selectionError && selectionErrorSource === "youtube" ? "selection-error" : undefined} /> {youtubeUrl && !analysisInFlight && !isStarting && !isImporting ? ( - - - - {t("clearYoutubeUrl")} - + ) : null} From a154a0f22049477c6f03c8400234e79f374b0d7e Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 25 Sep 2026 12:19:43 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Fix=20act=20warni?= =?UTF-8?q?ng=20in=20tooltip=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 4 + apps/desktop/src/App.test.tsx | 10 +- apps/desktop/src/App.tsx | 141 ++++++++++-------- .../tests/test_supply_chain_policy.py | 4 +- 4 files changed, 86 insertions(+), 73 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index c05638899..ecba8a642 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -1,3 +1,7 @@ ## 2024-05-19 - Replace HTML disabled with aria-disabled="true" for Accessible Tooltips **Learning:** Native HTML `disabled` attributes completely hide elements from screen readers and block all pointer/hover events, preventing tooltips from functioning for disabled elements. **Action:** Replace `disabled` with `aria-disabled="true"`, enforce block click handlers via `e.preventDefault()`, and add a title tooltip directly to the element to maintain full tooltip accessibility and keyboard focus support for visually impaired and mouse users. +## 2026-09-24 - Accessible tooltips instead of title + +**Learning:** When adding tooltips to icon-only buttons, especially those using `aria-disabled={true}`, do not use the native HTML title attribute as it lacks keyboard/touch support. +**Action:** Wrap the element in the custom Tooltip components (@/components/ui/tooltip). diff --git a/apps/desktop/src/App.test.tsx b/apps/desktop/src/App.test.tsx index 3eed386f8..a454a3e58 100644 --- a/apps/desktop/src/App.test.tsx +++ b/apps/desktop/src/App.test.tsx @@ -225,7 +225,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(primaryNav).getByRole("button", { name }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(primaryNav).getByRole("button", { name: "Import" })); @@ -236,7 +236,7 @@ describe("App", () => { for (const name of ["Import", "Export"]) { const navButton = within(compactNav).getByRole("button", { name: `${name} compact view` }); expect(navButton).toHaveAttribute("aria-disabled", "true"); - expect(navButton).toHaveAttribute("title", "Coming soon"); + expect(navButton).not.toHaveAttribute("title"); expect(navButton).not.toBeDisabled(); } fireEvent.click(within(compactNav).getByRole("button", { name: "Import compact view" })); @@ -1139,11 +1139,13 @@ describe("App", () => { fireEvent.change(input, { target: { value: "https://youtube.com/watch?v=abc123DEF45" } }); const clearButton = screen.getByRole("button", { name: /Clear YouTube URL/i }); - clearButton.focus(); + act(() => clearButton.focus()); fireEvent.click(clearButton); expect(input).toHaveValue(""); - expect(document.activeElement).toBe(input); + await waitFor(() => { + expect(document.activeElement).toBe(input); + }); expect(screen.queryByRole("button", { name: /Clear YouTube URL/i })).toBeNull(); expect(screen.getByRole("alert")).toHaveTextContent(/choose a wav, mp3, flac, or m4a file/i); expect(input).not.toHaveAttribute("aria-invalid"); diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index f3d678454..720966791 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -51,6 +51,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Progress } from "@/components/ui/progress"; import { Toaster } from "@/components/ui/sonner"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; const ANALYSIS_POLL_INTERVAL_MS = 250; const MAX_ERROR_DETAIL_LENGTH = 220; @@ -566,24 +567,25 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white shadow-[0_12px_30px_rgba(37,99,235,0.32)]" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -611,26 +613,30 @@ export function App() {
- - + + + + {t("settingsComingSoon")} + + + + + {t("helpComingSoon")} +
@@ -642,25 +648,26 @@ export function App() { const { icon: Icon, view } = item; return ( - + + handleNavSelect(view) : blockInactiveNavActivation} + className={`inline-flex min-h-10 shrink-0 items-center gap-2 rounded-xl px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-300 ${ + active + ? "bg-blue-600/70 text-white" + : enabled + ? "text-slate-200 hover:bg-white/5" + : "cursor-not-allowed text-slate-500 opacity-70" + }`} + > + + {title ? {title} : null} + ); })} @@ -709,15 +716,17 @@ export function App() { aria-describedby={selectionError && selectionErrorSource === "youtube" ? "selection-error" : undefined} /> {youtubeUrl && !analysisInFlight && !isStarting && !isImporting ? ( - + + + + {t("clearYoutubeUrl")} + ) : null} diff --git a/services/analysis-engine/tests/test_supply_chain_policy.py b/services/analysis-engine/tests/test_supply_chain_policy.py index 1d8224c5a..6a0853944 100644 --- a/services/analysis-engine/tests/test_supply_chain_policy.py +++ b/services/analysis-engine/tests/test_supply_chain_policy.py @@ -1275,9 +1275,7 @@ def test_workflow_concurrency_cancels_only_superseded_pr_heads() -> None: workflow = (workflows_dir / workflow_name).read_text(encoding="utf-8") assert "concurrency:" in workflow, workflow_name assert "cancel-in-progress: false" in workflow, workflow_name - assert "contents: read" in workflow or "permissions: read-all" in workflow, ( - workflow_name - ) + assert "contents: read" in workflow or "permissions: read-all" in workflow, workflow_name assert "pull_request:" not in (workflows_dir / "release.yml").read_text(encoding="utf-8")