From 2a56971271938fc68b824ca2f6e4cdb1675a9fed Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 26 Apr 2026 17:26:43 -0500 Subject: [PATCH] Address UX feedback on secrets picker fixture and provider chip - Storybook fixture now seeds the company id at module load and gates child render on it, so SecretBindingPicker renders the active-bound state with a populated version dropdown instead of falling into the missing-secret branch. - Provider chip badge now reads "1 warning" with an alert glyph instead of an unlabeled "(1)", per UX feedback. - Storybook env-editor scenario renamed from "attention required" to "Mixed bindings (some need attention)" so the heading matches the per-row footer. Co-Authored-By: Paperclip --- ui/src/pages/Secrets.tsx | 9 ++++++--- ui/storybook/stories/secrets.stories.tsx | 14 +++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ui/src/pages/Secrets.tsx b/ui/src/pages/Secrets.tsx index be775e1da77..08e76203f7c 100644 --- a/ui/src/pages/Secrets.tsx +++ b/ui/src/pages/Secrets.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AlertCircle, + AlertTriangle, ArchiveRestore, Archive, Ban, @@ -801,6 +802,7 @@ function ProviderHealthBar({ {providers.map((provider) => { const entry = healthMap.get(provider.id); const status = entry?.status ?? "ok"; + const warningCount = entry?.warnings?.length ?? 0; return ( {provider.label} - {entry?.warnings && entry.warnings.length > 0 ? ( - - ({entry.warnings.length}) + {warningCount > 0 ? ( + + + {warningCount} warning{warningCount === 1 ? "" : "s"} ) : null} diff --git a/ui/storybook/stories/secrets.stories.tsx b/ui/storybook/stories/secrets.stories.tsx index bea299fedbe..5c3d09ea5b8 100644 --- a/ui/storybook/stories/secrets.stories.tsx +++ b/ui/storybook/stories/secrets.stories.tsx @@ -14,8 +14,14 @@ import { storybookCompanies, storybookSecrets } from "../fixtures/paperclipData" const COMPANY_ID = "company-storybook"; +// Seed localStorage before CompanyContext mounts so its `useState` initializer reads the right id. +if (typeof window !== "undefined") { + window.localStorage.setItem("paperclip.selectedCompanyId", COMPANY_ID); +} + function StorybookSecretsFixtures({ children }: { children: ReactNode }) { const queryClient = useQueryClient(); + // Seed query caches synchronously so children hydrate from cache on first render. queryClient.setQueryData(queryKeys.companies.all, storybookCompanies); queryClient.setQueryData(queryKeys.secrets.list(COMPANY_ID), storybookSecrets); @@ -26,6 +32,12 @@ function StorybookSecretsFixtures({ children }: { children: ReactNode }) { } }, [selectedCompanyId, setSelectedCompanyId]); + // Block render until the company id is the storybook fixture so the BindingPicker's + // useQuery never sees the production-like null state. + if (selectedCompanyId !== COMPANY_ID) { + return null; + } + return <>{children}; } @@ -154,7 +166,7 @@ export const EnvEditorWithSecrets: Story = { }} />