mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
Builds the remaining developer-portal surfaces from the unified design and rebuilds Settings, on top of the portal scaffold merged in #6686. All tier-aware, mock-driven (MSW), componentised with Storybook coverage. Touches only `frontend/portal` + `frontend/shared` — the editor is untouched. ## New surfaces - **Policies** — org-wide governance across the five categories (Ingestion / Security / Compliance / Routing / Retention) with a designer + per-doc-type overrides - **Users** — members, roles, invite, tier-scaled SSO/SCIM access - **Components** — embeddable `@stirling/*` SDK catalogue with per-action pricing - **Getting Started** — three-step funnel (use case → analyse a document → API key + snippets) - **Agent Builder** — agent lifecycle (scenarios, tool modes, evals/golden-sets, versions), reached from Sources - **Editor deployment** — deploy/pair/operate the editor (targets, pairing, health, credential rotation, air-gapped bundle), reached from Infrastructure ## Reworks - **Documents** → review/approval queue (confidence, extractions, audit drawer, zero-standing-access elevation); the doc-type catalogue is retained as a second tab - **Pipelines** → golden-set pass column + "Promoted from the Editor" section - **Infrastructure** → new **Models** tab; deeper **Security** (managed / BYOK / HYOK + SOC 2 / ISO 27001 / HIPAA / GDPR / PCI attestations) - **Home** → "What runs on your PDFs" policy summary + tier-aware processing-status strip + pipeline-fork wizard ## Settings & shared - New shared **`SettingsShell`** (grouped left-nav + content pane), modelled on the editor's account-settings modal so both apps can converge on one layout - Portal **Settings** rebuilt on it as scoped sections — Account / Workspace / Admin (Authentication, Active sessions, Early access) ## Brand - Adopt the editor's brand mark + favicon; sidebar reads **Stirling Processor**; app-switcher labels the active app "Processor" ## Mock contract - Every surface follows the 3-layer pattern (typed `api/*` → MSW handler → fixtures); new endpoints documented in `MOCKS.md`. The read contract is backend-ready; writes are marked `// TODO(backend): <METHOD> <path>`. ## Verification - tsc (portal + shared) ✓ · eslint ✓ · dpdm (no circular) ✓ · `build:portal` ✓ · `storybook:build` ✓ · Prettier ✓ ## Deferred (noted, not in scope) - Unified shell / auth / role→surface routing / Workspace=Plan (architectural epic) - Tier rename (Editor / Processor / Bespoke) and the Usage flat-pricing + PAYG quick-amounts + Bespoke modal - Editor adopting the shared `SettingsShell`; converting marked write-stubs into live `api/` seams
77 lines
1.9 KiB
TypeScript
77 lines
1.9 KiB
TypeScript
import { useState } from "react";
|
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
import {
|
|
SettingsShell,
|
|
type SettingsNavSection,
|
|
} from "@shared/components/SettingsShell";
|
|
import { Button } from "@shared/components/Button";
|
|
|
|
const SECTIONS: SettingsNavSection[] = [
|
|
{
|
|
title: "Account",
|
|
items: [
|
|
{ key: "profile", label: "Profile" },
|
|
{ key: "appearance", label: "Appearance" },
|
|
{ key: "notifications", label: "Notifications" },
|
|
],
|
|
},
|
|
{
|
|
title: "Workspace",
|
|
items: [{ key: "general", label: "General" }],
|
|
},
|
|
{
|
|
title: "Admin",
|
|
items: [
|
|
{ key: "auth", label: "Authentication" },
|
|
{ key: "sessions", label: "Active sessions" },
|
|
{ key: "beta", label: "Early access", badge: "New" },
|
|
],
|
|
},
|
|
];
|
|
|
|
const LABELS: Record<string, string> = {
|
|
profile: "Profile",
|
|
appearance: "Appearance",
|
|
notifications: "Notifications",
|
|
general: "General",
|
|
auth: "Authentication",
|
|
sessions: "Active sessions",
|
|
beta: "Early access",
|
|
};
|
|
|
|
const meta: Meta<typeof SettingsShell> = {
|
|
title: "Shared/SettingsShell",
|
|
component: SettingsShell,
|
|
parameters: { layout: "fullscreen" },
|
|
};
|
|
export default meta;
|
|
|
|
type Story = StoryObj<typeof SettingsShell>;
|
|
|
|
export const Default: Story = {
|
|
render: () => {
|
|
const [active, setActive] = useState("profile");
|
|
return (
|
|
<div style={{ height: "36rem", border: "1px solid var(--color-border)" }}>
|
|
<SettingsShell
|
|
sections={SECTIONS}
|
|
activeKey={active}
|
|
onSelect={setActive}
|
|
title={LABELS[active]}
|
|
onClose={() => {}}
|
|
footer={
|
|
<>
|
|
<Button variant="ghost">Cancel</Button>
|
|
<Button variant="gradient">Save changes</Button>
|
|
</>
|
|
}
|
|
>
|
|
<p style={{ color: "var(--color-text-3)" }}>
|
|
Content for the “{LABELS[active]}” section renders here.
|
|
</p>
|
|
</SettingsShell>
|
|
</div>
|
|
);
|
|
},
|
|
};
|