From 34a51012f6773470f586ba6f4d510b403965857d Mon Sep 17 00:00:00 2001 From: tsukaska <16710830+tsukaska@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:23:07 -0600 Subject: [PATCH 1/4] fix(web): allow adding the displayed provider accent color --- ...nstanceDialog.environment.browser.test.tsx | 19 ++++ .../settings/ProviderAccentColorPicker.tsx | 11 +++ .../settings/colorPickers.browser.test.tsx | 88 ++++++++++++++++++- 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/settings/AddProviderInstanceDialog.environment.browser.test.tsx b/apps/web/src/components/settings/AddProviderInstanceDialog.environment.browser.test.tsx index e3ff5bb8d02e6..b4207a37185e6 100644 --- a/apps/web/src/components/settings/AddProviderInstanceDialog.environment.browser.test.tsx +++ b/apps/web/src/components/settings/AddProviderInstanceDialog.environment.browser.test.tsx @@ -166,6 +166,25 @@ describe("AddProviderInstanceDialog environment routing", () => { }); }); + it("includes the explicitly added default accent color when creating a provider", async () => { + setup(); + await using _screen = await render(dialog()); + await click("Use Kilo Code"); + await act(async () => + document + .querySelector('button[aria-label="Add accent color for Kilo Code"]')! + .click(), + ); + await click("Add color"); + await click("Continue to sign-in"); + + expect(settingsHooks.mutate).toHaveBeenCalledWith({ + operation: "create", + instanceId: "acpRegistry_kilo_code", + instance: expect.objectContaining({ accentColor: "#2563eb" }), + }); + }); + it("awaits an atomic create before closing and retains prepared ACP metadata", async () => { setup(); const mutation = deferred<{ readonly _tag: "Success"; readonly value: unknown }>(); diff --git a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx index 00759dad856ee..7f8a71345d278 100644 --- a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx +++ b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx @@ -13,6 +13,7 @@ const FALLBACK_ACCENT_COLOR = "#2563eb"; function ProviderCustomColorPanel(props: { readonly value: string; readonly onCommit: (value: string) => void; + readonly showAddButton: boolean; }) { const { onCommit } = props; const [hsv, setHsv] = useState(() => hexToHsv(props.value)); @@ -54,6 +55,15 @@ function ProviderCustomColorPanel(props: { aria-label="Custom hex accent color" spellCheck={false} /> + {props.showAddButton ? ( + onCommit(currentColor)}> + Add color + + } + /> + ) : null} ); @@ -90,6 +100,7 @@ function ProviderCustomColorPicker(props: { {normalized ? (
diff --git a/apps/web/src/components/settings/colorPickers.browser.test.tsx b/apps/web/src/components/settings/colorPickers.browser.test.tsx index 1f4915bd9ca73..4eb6f4c107ead 100644 --- a/apps/web/src/components/settings/colorPickers.browser.test.tsx +++ b/apps/web/src/components/settings/colorPickers.browser.test.tsx @@ -1,10 +1,11 @@ import { describe, expect, it, vi } from "vite-plus/test"; -import { userEvent } from "vite-plus/test/browser"; +import { page, userEvent } from "vite-plus/test/browser"; import type { ReactNode } from "react"; import { act, render } from "../../../test/render"; import { ThemeColorField } from "./ThemeColorPicker"; +import { ProviderAccentColorPicker } from "./ProviderAccentColorPicker"; const HUE = "Accent color hue"; const PLANE = "Accent color saturation and brightness"; @@ -82,3 +83,88 @@ describe("theme color field", () => { expect(slider(HUE).getAttribute("aria-valuenow")).toBe("10"); }); }); + +describe("provider accent color picker", () => { + it("leaves the optional color unset when the preview is dismissed", async () => { + const onCommit = vi.fn(); + await using _screen = await renderPicker( + , + ); + + await open("Add accent color for Example provider"); + expect(byLabel("Custom hex accent color").value).toBe("#2563eb"); + expect(onCommit).not.toHaveBeenCalled(); + await userEvent.keyboard("{Escape}"); + expect(onCommit).not.toHaveBeenCalled(); + }); + + it("adds the displayed default without adjusting a color control", async () => { + const onCommit = vi.fn(); + await using screen = await renderPicker( + , + ); + + await open("Add accent color for Example provider"); + await userEvent.click(page.getByRole("button", { name: "Add color", exact: true })); + + expect(onCommit).toHaveBeenCalledExactlyOnceWith("#2563eb"); + await expect + .element(screen.getByRole("button", { name: "Change accent color for Example provider" })) + .toBeVisible(); + await vi.waitFor(() => + expect(document.querySelector('[aria-label="Custom hex accent color"]')).toBeNull(), + ); + }); + + it("lets keyboard users add the displayed default", async () => { + const onCommit = vi.fn(); + await using screen = await renderPicker( + , + ); + + await open("Add accent color for Example provider"); + await act(async () => byLabel("Accent color saturation").focus()); + await userEvent.tab(); + await userEvent.tab(); + await userEvent.tab(); + await userEvent.tab(); + await userEvent.keyboard("{Enter}"); + + expect(onCommit).toHaveBeenCalledExactlyOnceWith("#2563eb"); + await expect + .element(screen.getByRole("button", { name: "Change accent color for Example provider" })) + .toBeVisible(); + }); + + it("keeps live color editing and allows clearing back to unset", async () => { + const onCommit = vi.fn(); + await using screen = await renderPicker( + , + ); + + await open("Change accent color for Example provider"); + await press(HUE, "ArrowRight", true); + expect(onCommit).toHaveBeenLastCalledWith("#ff2a00"); + await userEvent.click(page.getByRole("button", { name: "Clear color", exact: true })); + expect(onCommit).toHaveBeenLastCalledWith(""); + await expect + .element(screen.getByRole("button", { name: "Add accent color for Example provider" })) + .toBeVisible(); + }); +}); From 04bbfd55e825189a16f7536a6fd5b86ddf88b0a9 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 00:44:24 +0000 Subject: [PATCH 2/4] fix(web): refresh provider accent draft after settings updates --- .../src/components/settings/ProviderAccentColorPicker.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx index 093541c3ea058..514878fb9e243 100644 --- a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx +++ b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx @@ -20,6 +20,14 @@ function ProviderCustomColorPanel(props: { const [hsv, setHsv] = useState(() => hexToHsv(props.value)); const currentColor = hsvToHex(hsv.h, hsv.s, hsv.v); const [hexDraft, setHexDraft] = useState(null); + const [syncedValue, setSyncedValue] = useState(props.value); + if (syncedValue !== props.value) { + setSyncedValue(props.value); + if (currentColor !== props.value) { + setHsv(hexToHsv(props.value)); + setHexDraft(null); + } + } // Pointer drags only preview and commit once on release, so a drag writes // settings once instead of on every pointer move. Keyboard steps commit // immediately because they have no release to wait for. Holds the latest From 91d561888d1f783455854d4ad6e6bb0655108afb Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 00:51:27 +0000 Subject: [PATCH 3/4] fix(web): preserve uppercase provider accent edits --- .../web/src/components/settings/ProviderAccentColorPicker.tsx | 2 +- .../web/src/components/settings/colorPickers.browser.test.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx index 514878fb9e243..21388d5148375 100644 --- a/apps/web/src/components/settings/ProviderAccentColorPicker.tsx +++ b/apps/web/src/components/settings/ProviderAccentColorPicker.tsx @@ -23,7 +23,7 @@ function ProviderCustomColorPanel(props: { const [syncedValue, setSyncedValue] = useState(props.value); if (syncedValue !== props.value) { setSyncedValue(props.value); - if (currentColor !== props.value) { + if (currentColor !== props.value.toLowerCase()) { setHsv(hexToHsv(props.value)); setHexDraft(null); } diff --git a/apps/web/src/components/settings/colorPickers.browser.test.tsx b/apps/web/src/components/settings/colorPickers.browser.test.tsx index 28d2aff081a72..972c77347d1f9 100644 --- a/apps/web/src/components/settings/colorPickers.browser.test.tsx +++ b/apps/web/src/components/settings/colorPickers.browser.test.tsx @@ -202,7 +202,9 @@ describe("provider accent color picker", () => { it("saves a change back to the saved color while the first change is still saving", async () => { await using screen = await renderAccentPicker("#ff0000"); - await userEvent.fill(byLabel("Custom hex accent color"), "#00ff00"); + await userEvent.fill(byLabel("Custom hex accent color"), "#00FF00"); + await screen.echo("#00FF00"); + expect(byLabel("Custom hex accent color").value).toBe("#00FF00"); await userEvent.fill(byLabel("Custom hex accent color"), "#ff0000"); expect(screen.onCommit).toHaveBeenLastCalledWith("#ff0000"); From 831fb5d8a854586690997f3962b4484128537391 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 00:55:14 +0000 Subject: [PATCH 4/4] test(web): retain pending provider accent save coverage --- .../src/components/settings/colorPickers.browser.test.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/settings/colorPickers.browser.test.tsx b/apps/web/src/components/settings/colorPickers.browser.test.tsx index 972c77347d1f9..7da9dd32a6586 100644 --- a/apps/web/src/components/settings/colorPickers.browser.test.tsx +++ b/apps/web/src/components/settings/colorPickers.browser.test.tsx @@ -202,12 +202,13 @@ describe("provider accent color picker", () => { it("saves a change back to the saved color while the first change is still saving", async () => { await using screen = await renderAccentPicker("#ff0000"); - await userEvent.fill(byLabel("Custom hex accent color"), "#00FF00"); - await screen.echo("#00FF00"); - expect(byLabel("Custom hex accent color").value).toBe("#00FF00"); + await userEvent.fill(byLabel("Custom hex accent color"), "#00ff00"); await userEvent.fill(byLabel("Custom hex accent color"), "#ff0000"); expect(screen.onCommit).toHaveBeenLastCalledWith("#ff0000"); + await userEvent.fill(byLabel("Custom hex accent color"), "#00FF00"); + await screen.echo("#00FF00"); + expect(byLabel("Custom hex accent color").value).toBe("#00FF00"); }); it("shows the saved color again when it is reverted outside the picker", async () => {