diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts index 4eb9a2a8ede5..18da902c81fd 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts @@ -3522,14 +3522,7 @@ describe("ProviderCommandReactor", () => { }), ); - await waitFor(async () => { - const readModel = await harness.readModel(); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); - if (!thread) return false; - return thread.activities.some( - (activity) => activity.kind === "provider.approval.respond.failed", - ); - }); + await harness.drain(); const readModel = await harness.readModel(); const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); @@ -3641,14 +3634,7 @@ describe("ProviderCommandReactor", () => { }), ); - await waitFor(async () => { - const readModel = await harness.readModel(); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); - if (!thread) return false; - return thread.activities.some( - (activity) => activity.kind === "provider.user-input.respond.failed", - ); - }); + await harness.drain(); const readModel = await harness.readModel(); const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); diff --git a/apps/web/src/components/ProviderUpdateEnvironmentRows.tsx b/apps/web/src/components/ProviderUpdateEnvironmentRows.tsx index 28242b88fd3a..56aaa9e96ff0 100644 --- a/apps/web/src/components/ProviderUpdateEnvironmentRows.tsx +++ b/apps/web/src/components/ProviderUpdateEnvironmentRows.tsx @@ -133,7 +133,7 @@ function EnvironmentUpdateRow({ break; default: trailing = ( - ); diff --git a/apps/web/src/components/ProviderUpdatePrimaryNotification.test.tsx b/apps/web/src/components/ProviderUpdatePrimaryNotification.test.tsx index 531223f24181..a9423979a4a5 100644 --- a/apps/web/src/components/ProviderUpdatePrimaryNotification.test.tsx +++ b/apps/web/src/components/ProviderUpdatePrimaryNotification.test.tsx @@ -129,6 +129,12 @@ describe("ProviderUpdatePrimaryNotification", () => { state.notificationVersion += 1; }); + it("uses an outline action for routine update notices", () => { + renderNotification(); + + expect(state.toasts[0]).toMatchObject({ actionVariant: "outline" }); + }); + it("opens repair settings for the environment where the update started", async () => { let finishUpdate!: () => void; state.updateProvider.mockImplementation( diff --git a/apps/web/src/components/ProviderUpdatePrimaryNotification.tsx b/apps/web/src/components/ProviderUpdatePrimaryNotification.tsx index 8766ed8a7de5..7ab94f44b499 100644 --- a/apps/web/src/components/ProviderUpdatePrimaryNotification.tsx +++ b/apps/web/src/components/ProviderUpdatePrimaryNotification.tsx @@ -301,7 +301,7 @@ export function ProviderUpdatePrimaryNotification() { children: "Settings", onClick: openSettings, }, - actionVariant: oneClickProviders.length > 0 ? "default" : "outline", + actionVariant: "outline", data: { leadingIcon: updateProviders.length === 1 ? ( diff --git a/apps/web/src/components/ServerUpdateAction.tsx b/apps/web/src/components/ServerUpdateAction.tsx index 6fdf89f92e16..c7a46f4b6ba7 100644 --- a/apps/web/src/components/ServerUpdateAction.tsx +++ b/apps/web/src/components/ServerUpdateAction.tsx @@ -154,7 +154,7 @@ export function ServerUpdateAction({ } return ( - ); diff --git a/apps/web/src/components/chat/ComposerBanner.tsx b/apps/web/src/components/chat/ComposerBanner.tsx index f81565718c14..d222972b4151 100644 --- a/apps/web/src/components/chat/ComposerBanner.tsx +++ b/apps/web/src/components/chat/ComposerBanner.tsx @@ -27,9 +27,8 @@ const variantColors: Record = { default: neutralOutline, error: "[--chat-composer-attached-outline:color-mix(in_srgb,var(--error)_32%,transparent)] [--chat-composer-attached-tint:color-mix(in_srgb,var(--error)_8%,transparent)]", - info: "[--chat-composer-attached-outline:color-mix(in_srgb,var(--info)_32%,transparent)] [--chat-composer-attached-tint:color-mix(in_srgb,var(--info)_4%,transparent)]", - success: - "[--chat-composer-attached-outline:color-mix(in_srgb,var(--success)_32%,transparent)] [--chat-composer-attached-tint:color-mix(in_srgb,var(--success)_4%,transparent)]", + info: neutralOutline, + success: neutralOutline, warning: "[--chat-composer-attached-outline:color-mix(in_srgb,var(--warning)_28%,transparent)] [--chat-composer-attached-tint:color-mix(in_srgb,var(--warning)_8%,transparent)]", }; @@ -71,8 +70,8 @@ function Surface({ const peekBorder: Record = { default: "border-(--chat-composer-attached-outline)", error: "border-destructive/24", - info: "border-info/24", - success: "border-success/24", + info: "border-(--chat-composer-attached-outline)", + success: "border-(--chat-composer-attached-outline)", warning: "border-warning/24", }; diff --git a/apps/web/src/components/chat/ComposerBannerStack.test.tsx b/apps/web/src/components/chat/ComposerBannerStack.test.tsx index 33d0d17eed7d..c75ad3aed646 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.test.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.test.tsx @@ -2,6 +2,7 @@ import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vite-plus/test"; import { ComposerBannerStack, type ComposerBannerStackItem } from "./ComposerBannerStack"; +import { ComposerBanner } from "./ComposerBanner"; const banner = ( id: string, @@ -47,6 +48,25 @@ describe("ComposerBannerStack", () => { expect(warningBehind).toContain("border-warning/24"); }); + it("keeps routine info and success banners neutral", () => { + const infoRoot = renderToStaticMarkup(); + const successRoot = renderToStaticMarkup(); + + for (const markup of [infoRoot, successRoot]) { + expect(markup).toContain("--chat-composer-attached-outline:var(--chat-composer-outline"); + expect(markup).not.toContain("--chat-composer-attached-tint:color-mix"); + } + + for (const variant of ["info", "success"] as const) { + const stack = renderToStaticMarkup( + , + ); + expect(stack).toContain('data-variant="default"'); + expect(stack).not.toContain(`border-${variant}/32`); + expect(stack).not.toContain(`bg-${variant}/4`); + } + }); + it("does not render an expandable region for a single banner", () => { const markup = renderToStaticMarkup(); diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index d8b8761447cb..e4b0874c7828 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -193,17 +193,19 @@ function ComposerBannerStackAlert({ readonly onDismissRequest: () => void; }) { const dismissOnly = item.onDismiss && !item.actions; + const visualVariant = + item.variant === "info" || item.variant === "success" ? "default" : item.variant; return ( {item.icon} {item.title} diff --git a/apps/web/src/components/settings/ProviderInstanceCard.tsx b/apps/web/src/components/settings/ProviderInstanceCard.tsx index a663aa90990d..c232c454b024 100644 --- a/apps/web/src/components/settings/ProviderInstanceCard.tsx +++ b/apps/web/src/components/settings/ProviderInstanceCard.tsx @@ -618,7 +618,7 @@ export function ProviderInstanceCard({ "size-5 rounded-sm p-0", versionAdvisory.emphasis === "strong" ? "text-warning hover:text-warning" - : "text-update-foreground hover:text-update-foreground", + : "text-muted-foreground hover:text-foreground", )} aria-label="Update available — view details" > @@ -651,7 +651,7 @@ export function ProviderInstanceCard({ } /> - + {tooltip}