diff --git a/site/.storybook/vitest.setup.ts b/site/.storybook/vitest.setup.ts index f11a4e41f5..358c4b4ac6 100644 --- a/site/.storybook/vitest.setup.ts +++ b/site/.storybook/vitest.setup.ts @@ -1,3 +1,4 @@ +import { preloadHighlighter } from "@pierre/diffs"; import { setProjectAnnotations } from "@storybook/react-vite"; import { beforeAll, beforeEach } from "vitest"; import * as previewAnnotations from "./preview"; @@ -6,6 +7,19 @@ const annotations = setProjectAnnotations([previewAnnotations]); beforeAll(annotations.beforeAll); +// Stories render diff viewers without the app's worker pool, so @pierre/diffs +// falls back to the shared in-page highlighter. Under StrictMode's dev-only +// remount, a cold highlighter loses the first render: the remounted instance +// re-hydrates the empty
 left behind and never schedules another render,
+// leaving the diff blank. Warming the themes here makes the first render
+// synchronous so re-hydration always finds content.
+beforeAll(async () => {
+	await preloadHighlighter({
+		themes: ["github-dark-high-contrast", "github-light"],
+		langs: [],
+	});
+});
+
 // Radix DismissableLayer sets document.body.style.pointerEvents = "none" while
 // a modal layer is active. When a story unmounts, the useEffect cleanup that
 // restores body.pointerEvents can race with the next story's play function,
diff --git a/site/src/components/Paywall/PaywallPremium.stories.tsx b/site/src/components/Paywall/PaywallPremium.stories.tsx
index bb8dd000f9..a72e4fbbce 100644
--- a/site/src/components/Paywall/PaywallPremium.stories.tsx
+++ b/site/src/components/Paywall/PaywallPremium.stories.tsx
@@ -38,7 +38,9 @@ export const CanViewLicenses: Story = {
 		await expect(pricing).toHaveAttribute("target", "_blank");
 
 		await expect(
-			canvas.getByRole("heading", { name: /Workspace proxies provide/ }),
+			canvas.getByRole("heading", {
+				name: /You need a Premium license/,
+			}),
 		).toBeVisible();
 		await expect(canvas.getAllByRole("listitem")).toHaveLength(4);
 		await expect(
diff --git a/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceDeleteDialog.stories.tsx b/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceDeleteDialog.stories.tsx
index 4e13c72394..c584767199 100644
--- a/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceDeleteDialog.stories.tsx
+++ b/site/src/modules/workspaces/WorkspaceMoreActions/WorkspaceDeleteDialog.stories.tsx
@@ -1,5 +1,5 @@
 import type { Meta, StoryObj } from "@storybook/react-vite";
-import { expect, fn, userEvent, within } from "storybook/test";
+import { expect, fn, userEvent, waitFor, within } from "storybook/test";
 import {
 	MockFailedWorkspace,
 	MockTaskWorkspace,
@@ -97,9 +97,17 @@ export const FilledWrong: Story = {
 
 		await userEvent.type(confirm, "wrong-name");
 		await userEvent.tab();
-		await expect(
-			body.getByText("wrong-name does not match the name of this workspace"),
-		).toBeVisible();
+		// The validation error renders asynchronously after blur, so wait for
+		// visibility instead of asserting it once.
+		await waitFor(
+			() =>
+				expect(
+					body.getByText(
+						"wrong-name does not match the name of this workspace",
+					),
+				).toBeVisible(),
+			{ timeout: 5_000 },
+		);
 		await expect(body.getByRole("button", { name: "Delete" })).toBeDisabled();
 	},
 };
diff --git a/site/src/pages/AISettingsPage/CoderAgentsPage/CoderAgentsPageView.stories.tsx b/site/src/pages/AISettingsPage/CoderAgentsPage/CoderAgentsPageView.stories.tsx
index 2642433c0d..49aaea410e 100644
--- a/site/src/pages/AISettingsPage/CoderAgentsPage/CoderAgentsPageView.stories.tsx
+++ b/site/src/pages/AISettingsPage/CoderAgentsPage/CoderAgentsPageView.stories.tsx
@@ -225,7 +225,7 @@ const selectModelInSection = async (
 	section: HTMLElement,
 	canvasElement: HTMLElement,
 	currentSelectionName: string | RegExp,
-	optionName: string,
+	optionName: string | RegExp,
 ) => {
 	const trigger = within(section).getByRole("combobox", {
 		name: currentSelectionName,
@@ -389,7 +389,7 @@ export const EachOverrideSetToEnabledModel: Story = {
 			generalSection,
 			canvasElement,
 			/gpt 4\.1 mini/i,
-			"Claude Sonnet 4",
+			/^Claude Sonnet 4\b/,
 		);
 		const generalSaveButton = within(generalSection).getByRole("button", {
 			name: "Save",
@@ -409,7 +409,7 @@ export const EachOverrideSetToEnabledModel: Story = {
 			titleSection,
 			canvasElement,
 			/gpt 4o mini/i,
-			"Claude Sonnet 4",
+			/^Claude Sonnet 4\b/,
 		);
 		const titleSaveButton = within(titleSection).getByRole("button", {
 			name: "Save",
@@ -429,7 +429,7 @@ export const EachOverrideSetToEnabledModel: Story = {
 			compactionSection,
 			canvasElement,
 			/claude sonnet 4/i,
-			"GPT 4o Mini",
+			/^GPT 4o Mini\b/,
 		);
 		const compactionSaveButton = within(compactionSection).getByRole("button", {
 			name: "Save",
diff --git a/site/src/pages/AgentsPage/AgentChatPage.stories.tsx b/site/src/pages/AgentsPage/AgentChatPage.stories.tsx
index 983ab28cda..ae2f1b829b 100644
--- a/site/src/pages/AgentsPage/AgentChatPage.stories.tsx
+++ b/site/src/pages/AgentsPage/AgentChatPage.stories.tsx
@@ -3117,10 +3117,14 @@ export const SlashCompactYieldsToPersonalSkill: Story = {
 		await userEvent.click(editor);
 		await userEvent.keyboard("/compact");
 		// The menu offers only the personal skill (the built-in command
-		// yields); first Enter accepts it, second Enter submits.
-		expect(
-			await within(document.body).findByText("Personal compact skill"),
-		).toBeVisible();
+		// yields); first Enter accepts it, second Enter submits. The menu item
+		// exists before the popover finishes positioning, so wait for
+		// visibility rather than asserting it once.
+		await waitFor(() => {
+			expect(
+				within(document.body).getByText("Personal compact skill"),
+			).toBeVisible();
+		});
 		await userEvent.keyboard("{Enter}");
 		await userEvent.keyboard("{Enter}");
 
@@ -3309,7 +3313,13 @@ export const SendResponseAfterChatSwitch: Story = {
 
 		await userEvent.click(canvas.getByRole("button", { name: "Switch chat" }));
 		const timeline = within(await canvas.findByTestId("conversation-timeline"));
-		expect(await timeline.findByText("Current chat message")).toBeVisible();
+		// The switched chat's messages render slowly under pixel's parallel
+		// load, so extend the default 1s lookup timeout.
+		expect(
+			await timeline.findByText("Current chat message", undefined, {
+				timeout: 10_000,
+			}),
+		).toBeVisible();
 
 		releaseSend?.();
 		await waitFor(() => {
diff --git a/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AppearanceSettingsPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AppearanceSettingsPageView.stories.tsx
index e9ec91cccc..c917ccd729 100644
--- a/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AppearanceSettingsPageView.stories.tsx
+++ b/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AppearanceSettingsPageView.stories.tsx
@@ -45,7 +45,7 @@ export const Entitled: Story = {
 			canvas.getByRole("heading", { name: "Announcement Banners" }),
 		).toBeVisible();
 		await expect(
-			canvas.queryByRole("link", { name: "Learn about Premium" }),
+			canvas.queryByRole("link", { name: "Start trial for free" }),
 		).not.toBeInTheDocument();
 	},
 };
@@ -54,7 +54,7 @@ export const NotEntitled: Story = {
 	play: async ({ canvasElement }) => {
 		const canvas = within(canvasElement);
 
-		const cta = canvas.getByRole("link", { name: "Learn about Premium" });
+		const cta = canvas.getByRole("link", { name: "Start trial for free" });
 		await expect(cta).toHaveAttribute("href", "/deployment/premium");
 		await expect(
 			canvas.queryByRole("form", { name: "Appearance settings" }),
@@ -76,7 +76,7 @@ export const NotEntitledWithoutLicenseAccess: Story = {
 			canvas.getByText(/contact your deployment administrator/i),
 		).toBeVisible();
 		await expect(
-			canvas.queryByRole("link", { name: "Learn about Premium" }),
+			canvas.queryByRole("link", { name: "Start trial for free" }),
 		).not.toBeInTheDocument();
 	},
 };
diff --git a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPage.tsx b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPage.tsx
index 3f72521c33..b39abb6910 100644
--- a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPage.tsx
+++ b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPage.tsx
@@ -36,16 +36,10 @@ const SecretsPage: FC = () => {
 			secrets={secretsQuery.data}
 			isLoading={!secretsQuery.isFetched && secretsQuery.isFetching}
 			hasLoaded={secretsQuery.isSuccess}
-			isRefreshing={secretsQuery.isFetching && secretsQuery.isFetched}
 			isCreating={createSecretMutation.isPending}
 			isUpdating={updateSecretMutation.isPending}
 			isDeleting={deleteSecretMutation.isPending}
 			getSecretsError={secretsQuery.error}
-			onRefresh={() => {
-				void queryClient.invalidateQueries({
-					queryKey: secretsQueryOptions.queryKey,
-				});
-			}}
 			onCreateSecret={async (request) => {
 				const secret = await createSecretMutation.mutateAsync(request);
 				toast.success(`Created secret "${secret.name}" successfully.`);
diff --git a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.stories.tsx b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.stories.tsx
index 2668ca7e62..87e616027d 100644
--- a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.stories.tsx
+++ b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.stories.tsx
@@ -28,11 +28,9 @@ const meta: Meta = {
 		secrets: visibleSecrets,
 		isLoading: false,
 		hasLoaded: true,
-		isRefreshing: false,
 		isCreating: false,
 		isUpdating: false,
 		isDeleting: false,
-		onRefresh: fn(),
 		onCreateSecret: fn(),
 		onUpdateSecret: fn(),
 		onImportSecrets: fn(),
@@ -111,7 +109,7 @@ export const Loaded: Story = {
 		await expect(canvas.getByText("env var + file")).toBeInTheDocument();
 		await expect(canvas.getByText("not injected")).toBeInTheDocument();
 
-		const docsLink = canvas.getByRole("link", { name: "View docs" });
+		const docsLink = canvas.getByRole("link", { name: "Read the docs" });
 		await expect(docsLink).toHaveAttribute(
 			"href",
 			expect.stringContaining("/user-guides/user-secrets"),
@@ -135,25 +133,9 @@ export const Loading: Story = {
 		const canvas = within(canvasElement);
 
 		await expect(
-			canvas.getByRole("button", { name: /Refresh/ }),
-		).toBeDisabled();
-	},
-};
-
-export const RefreshingWithRows: Story = {
-	args: {
-		secrets: visibleSecrets,
-		isLoading: false,
-		hasLoaded: true,
-		isRefreshing: true,
-	},
-	play: async ({ canvasElement }) => {
-		const canvas = within(canvasElement);
-
-		await expect(canvas.getAllByText(visibleSecrets[0].name)[0]).toBeVisible();
-		await expect(
-			canvas.getByRole("button", { name: /Refresh/ }),
-		).toBeDisabled();
+			canvas.getByRole("status", { name: "Loading" }),
+		).toBeInTheDocument();
+		await expect(canvas.queryByText("No secrets yet")).not.toBeInTheDocument();
 	},
 };
 
diff --git a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.tsx b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.tsx
index 93d314699c..cfac6530ab 100644
--- a/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.tsx
+++ b/site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.tsx
@@ -21,12 +21,10 @@ type SecretsPageViewProps = {
 	secrets?: readonly UserSecret[];
 	isLoading: boolean;
 	hasLoaded: boolean;
-	isRefreshing: boolean;
 	isCreating: boolean;
 	isUpdating: boolean;
 	isDeleting: boolean;
 	getSecretsError?: unknown;
-	onRefresh: () => void;
 	onCreateSecret: (
 		request: CreateUserSecretRequest,
 	) => Promise | UserSecret;
diff --git a/site/src/pages/UserSettingsPage/SecretsPage/SecretsTable.tsx b/site/src/pages/UserSettingsPage/SecretsPage/SecretsTable.tsx
index 2fb48ca214..4e17976f5b 100644
--- a/site/src/pages/UserSettingsPage/SecretsPage/SecretsTable.tsx
+++ b/site/src/pages/UserSettingsPage/SecretsPage/SecretsTable.tsx
@@ -217,7 +217,6 @@ const EnabledToggle: FC = ({
 	// An enabled secret must have at least one injection target. Prevent
 	// enabling a target-less secret; the user must add a target first.
 	const cannotEnable = !secret.enabled && !hasTarget;
-	const stateLabel = secret.enabled ? "Enabled" : "Disabled";
 
 	return (
 		
@@ -230,7 +229,7 @@ const EnabledToggle: FC = ({
 				 */}
 				
 					 onToggle(secret, checked)}