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 <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-05-07 18:59:05 -05:00
1 parent 181b38a070
commit 2a56971271
2 files changed
+19 -4

No files matched your search

+6 -3
View File
@@ -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 (
<span
key={provider.id}
@@ -809,9 +811,10 @@ function ProviderHealthBar({
>
<span className={cn("h-1.5 w-1.5 rounded-full", dot(status))} />
{provider.label}
{entry?.warnings && entry.warnings.length > 0 ? (
<span className="text-amber-600 dark:text-amber-400">
({entry.warnings.length})
{warningCount > 0 ? (
<span className="inline-flex items-center gap-0.5 text-amber-600 dark:text-amber-400">
<AlertTriangle className="h-2.5 w-2.5" />
{warningCount} warning{warningCount === 1 ? "" : "s"}
</span>
) : null}
</span>
+13 -1
View File
@@ -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 = {
}}
/>
<EditorDemo
label="Bindings with attention required"
label="Mixed bindings (some need attention)"
initial={{
OPENAI_API_KEY: { type: "secret_ref", secretId: "secret-openai", version: 2 },
GITHUB_APP_PEM: { type: "secret_ref", secretId: "secret-github", version: "latest" },