paperclip/ui/storybook/stories/forms-editors.stories.tsx

814 lines
29 KiB
TypeScript
Raw Normal View History

[codex] add comprehensive UI Storybook coverage (#4132) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - The board UI is the main operator surface, so its component and workflow coverage needs to stay reviewable as the product grows. > - This branch adds Storybook as a dedicated UI reference surface for core Paperclip screens and interaction patterns. > - That work spans Storybook infrastructure, app-level provider wiring, and a large fixture set that can render real control-plane states without a live backend. > - The branch also expands coverage across agents, budgets, issues, chat, dialogs, navigation, projects, and data visualization so future UI changes have a concrete visual baseline. > - This pull request packages that Storybook work on top of the latest `master`, excludes the lockfile from the final diff per repo policy, and fixes one fixture contract drift caught during verification. > - The benefit is a single reviewable PR that adds broad UI documentation and regression-surfacing coverage without losing the existing branch work. ## What Changed - Added Storybook 10 wiring for the UI package, including root scripts, UI package scripts, Storybook config, preview wrappers, Tailwind entrypoints, and setup docs. - Added a large fixture-backed data source for Storybook so complex board states can render without a live server. - Added story suites covering foundations, status language, control-plane surfaces, overview, UX labs, agent management, budget and finance, forms and editors, issue management, navigation and layout, chat and comments, data visualization, dialogs and modals, and projects/goals/workspaces. - Adjusted several UI components for Storybook parity so dialogs, menus, keyboard shortcuts, budget markers, markdown editing, and related surfaces render correctly in isolation. - Rebasing work for PR assembly: replayed the branch onto current `master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned the dashboard fixture with the current `DashboardSummary.runActivity` API contract. ## Verification - `pnpm --filter @paperclipai/ui typecheck` - `pnpm --filter @paperclipai/ui build-storybook` - Manual diff audit after rebase: verified the PR no longer includes `pnpm-lock.yaml` and now cleanly targets current `master`. - Before/after UI note: before this branch there was no dedicated Storybook surface for these Paperclip views; after this branch the local Storybook build includes the new overview and domain story suites in `ui/storybook-static`. ## Risks - Large static fixture files can drift from shared types as dashboard and UI contracts evolve; this PR already needed one fixture correction for `runActivity`. - Storybook bundle output includes some large chunks, so future growth may need chunking work if build performance becomes an issue. - Several component tweaks were made for isolated rendering parity, so reviewers should spot-check key board surfaces against the live app behavior. ## Model Used - OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact serving model ID is not exposed in-runtime to the agent. - Tool-assisted workflow with terminal execution, git operations, local typecheck/build verification, and GitHub CLI PR creation. - Context window/reasoning mode not surfaced by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
import { useMemo, useState, type ReactNode } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import type { Agent, CompanySecret, EnvBinding, Project, RoutineVariable } from "@paperclipai/shared";
import { Code2, FileText, ListPlus, RotateCcw, Table2 } from "lucide-react";
import { EnvVarEditor } from "@/components/EnvVarEditor";
import { ExecutionParticipantPicker } from "@/components/ExecutionParticipantPicker";
[codex] Polish issue composer and long document display (#4420) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Issue comments and documents are the main working surface where operators and agents collaborate > - File drops, markdown editing, and long issue descriptions need to feel predictable because they sit directly in the task execution loop > - The composer had edge cases around drag targets, attachment feedback, image drops, and long markdown content crowding the page > - This pull request polishes the issue composer, hardens markdown editor regressions, and adds a fold curtain for long issue descriptions/documents > - The benefit is a calmer issue detail surface that handles uploads and long work products without hiding state or breaking layout ## What Changed - Scoped issue-composer drag/drop behavior so the composer owns file drops without turning the whole thread into a competing drop target. - Added clearer attachment upload feedback for non-image files and image-drop stability coverage. - Hardened markdown editor and markdown body handling around HTML-like tag regressions. - Added `FoldCurtain` and wired it into issue descriptions and issue documents so long markdown previews can expand/collapse. - Added Storybook coverage for the fold curtain state. ## Verification - `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx ui/src/components/MarkdownEditor.test.tsx ui/src/components/MarkdownBody.test.tsx --config ui/vitest.config.ts` passed: 3 files, 75 tests. - `git diff --check public-gh/master..pap-2228-editor-composer-polish -- . ':(exclude)ui/storybook-static'` passed. - Confirmed this PR does not include `pnpm-lock.yaml`. ## Risks - Low-to-medium risk: this changes user-facing composer/drop behavior and long markdown display. - The fold curtain uses DOM measurement and `ResizeObserver`; reviewers should check browser behavior for very long descriptions and documents. - No database migrations. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex coding agent based on GPT-5, with shell, git, Paperclip API, and GitHub CLI tool use in the local Paperclip workspace. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge Note: screenshots were not newly captured during branch splitting; the UI states are covered by component tests and a Storybook story. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 14:12:41 -05:00
import { FoldCurtain } from "@/components/FoldCurtain";
[codex] add comprehensive UI Storybook coverage (#4132) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - The board UI is the main operator surface, so its component and workflow coverage needs to stay reviewable as the product grows. > - This branch adds Storybook as a dedicated UI reference surface for core Paperclip screens and interaction patterns. > - That work spans Storybook infrastructure, app-level provider wiring, and a large fixture set that can render real control-plane states without a live backend. > - The branch also expands coverage across agents, budgets, issues, chat, dialogs, navigation, projects, and data visualization so future UI changes have a concrete visual baseline. > - This pull request packages that Storybook work on top of the latest `master`, excludes the lockfile from the final diff per repo policy, and fixes one fixture contract drift caught during verification. > - The benefit is a single reviewable PR that adds broad UI documentation and regression-surfacing coverage without losing the existing branch work. ## What Changed - Added Storybook 10 wiring for the UI package, including root scripts, UI package scripts, Storybook config, preview wrappers, Tailwind entrypoints, and setup docs. - Added a large fixture-backed data source for Storybook so complex board states can render without a live server. - Added story suites covering foundations, status language, control-plane surfaces, overview, UX labs, agent management, budget and finance, forms and editors, issue management, navigation and layout, chat and comments, data visualization, dialogs and modals, and projects/goals/workspaces. - Adjusted several UI components for Storybook parity so dialogs, menus, keyboard shortcuts, budget markers, markdown editing, and related surfaces render correctly in isolation. - Rebasing work for PR assembly: replayed the branch onto current `master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned the dashboard fixture with the current `DashboardSummary.runActivity` API contract. ## Verification - `pnpm --filter @paperclipai/ui typecheck` - `pnpm --filter @paperclipai/ui build-storybook` - Manual diff audit after rebase: verified the PR no longer includes `pnpm-lock.yaml` and now cleanly targets current `master`. - Before/after UI note: before this branch there was no dedicated Storybook surface for these Paperclip views; after this branch the local Storybook build includes the new overview and domain story suites in `ui/storybook-static`. ## Risks - Large static fixture files can drift from shared types as dashboard and UI contracts evolve; this PR already needed one fixture correction for `runActivity`. - Storybook bundle output includes some large chunks, so future growth may need chunking work if build performance becomes an issue. - Several component tweaks were made for isolated rendering parity, so reviewers should spot-check key board surfaces against the live app behavior. ## Model Used - OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact serving model ID is not exposed in-runtime to the agent. - Tool-assisted workflow with terminal execution, git operations, local typecheck/build verification, and GitHub CLI PR creation. - Context window/reasoning mode not surfaced by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
import { InlineEditor } from "@/components/InlineEditor";
import { InlineEntitySelector, type InlineEntityOption } from "@/components/InlineEntitySelector";
import { JsonSchemaForm, type JsonSchemaNode, getDefaultValues } from "@/components/JsonSchemaForm";
import { MarkdownBody } from "@/components/MarkdownBody";
import { MarkdownEditor, type MentionOption } from "@/components/MarkdownEditor";
import { ReportsToPicker } from "@/components/ReportsToPicker";
import {
RoutineRunVariablesDialog,
type RoutineRunDialogSubmitData,
} from "@/components/RoutineRunVariablesDialog";
import { RoutineVariablesEditor, RoutineVariablesHint } from "@/components/RoutineVariablesEditor";
import { ScheduleEditor, describeSchedule } from "@/components/ScheduleEditor";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { buildExecutionPolicy } from "@/lib/issue-execution-policy";
import { createIssue, storybookAgents } from "../fixtures/paperclipData";
function Section({
eyebrow,
title,
description,
children,
}: {
eyebrow: string;
title: string;
description?: string;
children: ReactNode;
}) {
return (
<section className="paperclip-story__frame overflow-hidden">
<div className="border-b border-border px-5 py-4">
<div className="paperclip-story__label">{eyebrow}</div>
<div className="mt-1 flex flex-wrap items-end justify-between gap-3">
<div>
<h2 className="text-xl font-semibold">{title}</h2>
{description ? (
<p className="mt-2 max-w-3xl text-sm leading-6 text-muted-foreground">{description}</p>
) : null}
</div>
</div>
</div>
<div className="p-5">{children}</div>
</section>
);
}
function StatePanel({
label,
detail,
children,
disabled = false,
}: {
label: string;
detail?: string;
children: ReactNode;
disabled?: boolean;
}) {
return (
<div className="min-w-0 rounded-lg border border-border bg-background/70 p-4">
<div className="mb-3 flex min-h-6 flex-wrap items-start justify-between gap-2">
<div>
<div className="text-sm font-medium">{label}</div>
{detail ? <div className="mt-1 text-xs leading-5 text-muted-foreground">{detail}</div> : null}
</div>
{disabled ? <Badge variant="outline">disabled</Badge> : null}
</div>
<div className={disabled ? "pointer-events-none opacity-55" : undefined}>{children}</div>
</div>
);
}
function StoryShell({ children }: { children: ReactNode }) {
return (
<div className="paperclip-story">
<main className="paperclip-story__inner space-y-6">{children}</main>
</div>
);
}
const reviewMarkdown = `# Release review
Ship criteria for the board UI refresh:
- [x] Preserve company-scoped routes
- [x] Keep comments and task updates auditable
- [ ] Attach screenshots after QA
[codex] Split PR #4692 UI/QoL updates (#4701) ## Thinking Path > - Paperclip orchestrates AI agents through a company-scoped control plane. > - The affected surface is the board UI for issue threads, issue lists, routines, dialogs, navigation, and issue review indicators. > - Closed PR #4692 bundled backend, schema, docs, workflow, and UI/QoL work into one oversized change set. > - Greptile could not keep reviewing that broad PR because it exceeded the 100-file review limit and mixed unrelated concerns. > - This pull request extracts the UI/QoL slice into a fresh branch under the review limit while leaving workflow and lockfile churn out. > - The benefit is a focused review path for the board UI performance and workflow improvements without reopening the oversized PR. ## What Changed - Added long issue-thread virtualization, scroll-container binding, anchor preservation, latest-comment jump targeting, and related regression/perf fixtures. - Improved issue list scalability with scroll-based loading, server offset parameters, and pagination-focused UI tests. - Reduced new issue dialog typing churn and split dialog action subscriptions so broad layout/nav surfaces avoid unnecessary renders. - Added routine variables help and routine description mention options for users, agents, and projects. - Added productivity review badge/link UI and fixed the badge to use Paperclip's company-prefixed router link. - Kept the split PR below Greptile's review limit and excluded `.github/workflows/pr.yml` and `pnpm-lock.yaml`. ## Verification - `pnpm install --no-frozen-lockfile` in the clean worktree to install `@tanstack/react-virtual` locally without committing lockfile churn. - `pnpm --filter @paperclipai/ui exec vitest run --config vitest.config.ts src/components/IssueChatThread.test.tsx src/components/IssuesList.test.tsx src/components/NewIssueDialog.test.tsx src/pages/Routines.test.tsx src/pages/Issues.test.tsx` passed: 5 files, 83 tests. - `pnpm --filter @paperclipai/ui typecheck` passed. - `git diff --check origin/master..HEAD` passed. - Split-scope checks: 53 changed files; no `.github/workflows/pr.yml`; no `pnpm-lock.yaml`. - Screenshots were not captured in this heartbeat; the changes are primarily virtualization, routing, pagination, and editor behavior covered by focused regression tests. ## Risks - Moderate UI risk because issue-thread virtualization changes scroll behavior on long conversations; regression tests cover anchor jumps, latest-comment targeting, row metadata, and short-thread fallback. - Moderate integration risk because the issue-list offset parameter and productivity review field depend on matching API behavior. - Dependency risk: the UI package adds `@tanstack/react-virtual` while repository policy keeps `pnpm-lock.yaml` out of PRs, so CI must resolve dependency changes through the repo's normal lockfile policy. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 coding agent, tool-enabled local repository and GitHub workflow. Exact runtime context window was not exposed by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-28 17:18:58 -05:00
Tooling: lean on [/react-perf-optimizer](skill://skill-react-perf?s=react-perf-optimizer) and [/vercel-react-best-practices](skill://skill-vercel-react?s=vercel-react-best-practices) so we don't regress render performance on the page it's open to. Inline skill chips like [/release-changelog](skill://skill-release?s=release-changelog) must sit on the surrounding text line, not hang below it.
[codex] add comprehensive UI Storybook coverage (#4132) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - The board UI is the main operator surface, so its component and workflow coverage needs to stay reviewable as the product grows. > - This branch adds Storybook as a dedicated UI reference surface for core Paperclip screens and interaction patterns. > - That work spans Storybook infrastructure, app-level provider wiring, and a large fixture set that can render real control-plane states without a live backend. > - The branch also expands coverage across agents, budgets, issues, chat, dialogs, navigation, projects, and data visualization so future UI changes have a concrete visual baseline. > - This pull request packages that Storybook work on top of the latest `master`, excludes the lockfile from the final diff per repo policy, and fixes one fixture contract drift caught during verification. > - The benefit is a single reviewable PR that adds broad UI documentation and regression-surfacing coverage without losing the existing branch work. ## What Changed - Added Storybook 10 wiring for the UI package, including root scripts, UI package scripts, Storybook config, preview wrappers, Tailwind entrypoints, and setup docs. - Added a large fixture-backed data source for Storybook so complex board states can render without a live server. - Added story suites covering foundations, status language, control-plane surfaces, overview, UX labs, agent management, budget and finance, forms and editors, issue management, navigation and layout, chat and comments, data visualization, dialogs and modals, and projects/goals/workspaces. - Adjusted several UI components for Storybook parity so dialogs, menus, keyboard shortcuts, budget markers, markdown editing, and related surfaces render correctly in isolation. - Rebasing work for PR assembly: replayed the branch onto current `master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned the dashboard fixture with the current `DashboardSummary.runActivity` API contract. ## Verification - `pnpm --filter @paperclipai/ui typecheck` - `pnpm --filter @paperclipai/ui build-storybook` - Manual diff audit after rebase: verified the PR no longer includes `pnpm-lock.yaml` and now cleanly targets current `master`. - Before/after UI note: before this branch there was no dedicated Storybook surface for these Paperclip views; after this branch the local Storybook build includes the new overview and domain story suites in `ui/storybook-static`. ## Risks - Large static fixture files can drift from shared types as dashboard and UI contracts evolve; this PR already needed one fixture correction for `runActivity`. - Storybook bundle output includes some large chunks, so future growth may need chunking work if build performance becomes an issue. - Several component tweaks were made for isolated rendering parity, so reviewers should spot-check key board surfaces against the live app behavior. ## Model Used - OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact serving model ID is not exposed in-runtime to the agent. - Tool-assisted workflow with terminal execution, git operations, local typecheck/build verification, and GitHub CLI PR creation. - Context window/reasoning mode not surfaced by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
| Surface | Owner | State |
| --- | --- | --- |
| Issues | CodexCoder | In progress |
| Approvals | CTO | Ready |
\`\`\`ts
const shouldRun = issue.status === "in_progress" && issue.companyId === company.id;
\`\`\`
See [the implementation notes](https://github.com/paperclipai/paperclip).`;
const editorMentions: MentionOption[] = [
{ id: "agent-codex", name: "CodexCoder", kind: "agent", agentId: "agent-codex", agentIcon: "code" },
{ id: "agent-qa", name: "QAChecker", kind: "agent", agentId: "agent-qa", agentIcon: "shield" },
{ id: "project-board-ui", name: "Board UI", kind: "project", projectId: "project-board-ui", projectColor: "#0f766e" },
{ id: "user-board", name: "Board Operator", kind: "user", userId: "user-board" },
];
const adapterSchema: JsonSchemaNode = {
type: "object",
required: ["adapterName", "apiKey", "concurrency"],
properties: {
adapterName: {
type: "string",
title: "Adapter name",
description: "Human-readable name shown in the adapter manager.",
minLength: 3,
default: "Codex local",
},
mode: {
type: "string",
title: "Run mode",
enum: ["review", "implementation", "maintenance"],
default: "implementation",
},
apiKey: {
type: "string",
title: "API key",
format: "secret-ref",
description: "Stored with the active Paperclip secret provider.",
},
concurrency: {
type: "integer",
title: "Max concurrent runs",
minimum: 1,
maximum: 6,
default: 2,
},
dryRun: {
type: "boolean",
title: "Dry run first",
description: "Require a preview run before mutating company data.",
default: true,
},
notes: {
type: "string",
title: "Operator notes",
format: "textarea",
maxLength: 500,
description: "Shown to the agent before checkout.",
},
allowedCommands: {
type: "array",
title: "Allowed commands",
description: "Commands this adapter can run without extra approval.",
items: { type: "string", default: "pnpm test" },
minItems: 1,
},
advanced: {
type: "object",
title: "Advanced guardrails",
properties: {
timeoutSeconds: { type: "integer", title: "Timeout seconds", minimum: 60, default: 900 },
requireApproval: { type: "boolean", title: "Require board approval", default: false },
},
},
},
};
const validAdapterValues = {
...getDefaultValues(adapterSchema),
adapterName: "Codex local",
mode: "implementation",
apiKey: "secret:openai-api-key",
concurrency: 2,
dryRun: true,
notes: "Use the project worktree and post a concise task update before handoff.",
allowedCommands: ["pnpm --filter @paperclipai/ui typecheck", "pnpm build-storybook"],
advanced: { timeoutSeconds: 900, requireApproval: false },
};
const invalidAdapterValues = {
...validAdapterValues,
adapterName: "AI",
apiKey: "",
concurrency: 9,
};
const adapterErrors = {
"/adapterName": "Must be at least 3 characters",
"/apiKey": "This field is required",
"/concurrency": "Must be at most 6",
};
const storybookSecrets: CompanySecret[] = [
Add secrets provider vaults and remote import (#5429) ## Thinking Path > - Paperclip orchestrates AI-agent companies and needs secrets handling to work across local development, hosted operators, and governed agent execution. > - The affected subsystem is the company-scoped secrets control plane: database schema, server services/routes, CLI workflows, and the Secrets settings UI. > - The gap was that secrets were local-only and operators could not manage provider vaults or import existing remote references without exposing plaintext. > - This branch adds provider vault configuration plus an AWS Secrets Manager remote-import path while preserving company boundaries, binding context, and audit trails. > - I kept the PR to a single branch PR, removed unrelated lockfile/package drift, rebased the full branch onto the current `public-gh/master`, and addressed fresh Greptile findings. > - The benefit is a reviewable implementation of provider-backed secrets with focused tests covering provider selection, import conflicts, deleted secret reuse, rotation guards, and AWS signing behavior. ## What Changed - Added provider vault support for company secrets, including provider config storage, default vault handling, health checks, binding usage, access events, and remote import preview/commit. - Added an AWS Secrets Manager provider using SigV4 request signing, bounded request timeouts, namespace guardrails, cached runtime credential resolution, and external-reference linking without plaintext reads. - Added Secrets UI surfaces for vault management and remote import, plus CLI/API documentation for setup and operations. - Stabilized routine webhook secret binding paths and SSH environment-driver fixture bindings discovered during verification. - Addressed Greptile and CI findings: no lockfile/package drift, monotonic migration metadata, disabled-vault default races, soft-deleted secret hiding/recreate behavior, remove behavior with disabled vaults, soft-deleted external-reference re-import, non-active rotation guards, managed-secret soft deletion through PATCH, and per-call AWS SDK credential client churn. - Rebased this branch onto `public-gh/master` at `0e1a5828` and force-pushed with lease to keep this as the single PR for the branch. ## Verification - `git fetch public-gh master` - `git rebase public-gh/master` - `git diff --name-only public-gh/master...HEAD | grep '^pnpm-lock\.yaml$' || true` confirmed `pnpm-lock.yaml` is not in the PR diff. - Confirmed migration ordering: master ends at `0081_optimal_dormammu`; this PR adds `0082_dry_vision` and `0083_company_secret_provider_configs`. - Inspected migrations for repeat safety: new tables/indexes use `IF NOT EXISTS`; foreign keys are guarded by `DO $$ ... IF NOT EXISTS`; column additions use `ADD COLUMN IF NOT EXISTS`. - `pnpm -r typecheck` passed before the Greptile follow-up commits. - `pnpm test:run` ran the full stable Vitest path before the Greptile follow-up commits; it completed with 3 timing-related failures under parallel load: `codex-local-execute.test.ts`, `cursor-local-execute.test.ts`, and `environment-service.test.ts`. - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/codex-local-execute.test.ts src/__tests__/cursor-local-execute.test.ts src/__tests__/environment-service.test.ts` passed on targeted rerun (`24/24`). - `pnpm build` passed before the Greptile follow-up commits. Vite reported existing chunk-size/dynamic-import warnings. - After Greptile follow-up commits: `pnpm --filter @paperclipai/server exec vitest run src/__tests__/secrets-service.test.ts` passed (`26/26`). - After Greptile follow-up commits: `pnpm --filter @paperclipai/server exec vitest run src/__tests__/aws-secrets-manager-provider.test.ts src/__tests__/secrets-service.test.ts` passed (`39/39`). - After Greptile follow-up commits: `pnpm --filter @paperclipai/server typecheck` passed. - Captured Storybook screenshots from `ui/storybook-static` for visual review. - Latest PR checks on `5ca3a5cf`: `policy`, serialized server suites 1/4-4/4, `Canary Dry Run`, `e2e`, `security/snyk`, and `Greptile Review` pass; aggregate `verify` is still registering the completed child checks. - Greptile review loop continued through the latest requested pass; all Greptile review threads are resolved and the latest `Greptile Review` check on `5ca3a5cf` passed with 0 comments added. ## Screenshots Before: the provider-vault and remote-import surfaces did not exist on `master`; these are after-state screenshots from the Storybook fixtures. ![Secrets inventory](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/secrets-inventory.png) ![Secret binding picker](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/secret-binding-picker.png) ![Environment editor with secrets](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/env-editor-with-secrets.png) ## Risks - Migration risk: this adds new secret provider tables and extends existing secret rows. The migrations were checked for monotonic ordering and idempotent guards, but reviewers should still inspect upgrade behavior carefully. - Provider risk: AWS support uses direct SigV4 requests. Automated tests cover signing, request timeouts, vault-config selection, namespace guardrails, pending-version archival, sanitized provider errors, and service-level cleanup paths. A real-vault AWS smoke test remains deployment validation for an operator with AWS credentials rather than an unverified merge blocker in this local branch. - UI risk: the Secrets page and import dialog are large new surfaces; screenshots are included above for reviewer inspection. - Verification risk: the full local stable test command hit parallel-load timing failures, although the exact failed files passed when rerun directly. - Operational risk: remote import intentionally avoids plaintext reads; operators must understand that imported external references resolve at runtime and may fail if AWS permissions change. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 coding agent with local shell/tool use in the Paperclip worktree. Exact context-window size was not exposed by the runtime. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 18:22:17 -05:00
{
id: "secret-openai",
companyId: "company-storybook",
key: "openai-api-key",
name: "OPENAI_API_KEY",
provider: "local_encrypted",
status: "active",
managedMode: "paperclip_managed",
externalRef: null,
providerConfigId: null,
providerMetadata: null,
latestVersion: 3,
description: null,
lastResolvedAt: new Date("2026-04-20T09:00:00.000Z"),
lastRotatedAt: new Date("2026-04-18T10:00:00.000Z"),
deletedAt: null,
createdByAgentId: null,
[codex] add comprehensive UI Storybook coverage (#4132) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - The board UI is the main operator surface, so its component and workflow coverage needs to stay reviewable as the product grows. > - This branch adds Storybook as a dedicated UI reference surface for core Paperclip screens and interaction patterns. > - That work spans Storybook infrastructure, app-level provider wiring, and a large fixture set that can render real control-plane states without a live backend. > - The branch also expands coverage across agents, budgets, issues, chat, dialogs, navigation, projects, and data visualization so future UI changes have a concrete visual baseline. > - This pull request packages that Storybook work on top of the latest `master`, excludes the lockfile from the final diff per repo policy, and fixes one fixture contract drift caught during verification. > - The benefit is a single reviewable PR that adds broad UI documentation and regression-surfacing coverage without losing the existing branch work. ## What Changed - Added Storybook 10 wiring for the UI package, including root scripts, UI package scripts, Storybook config, preview wrappers, Tailwind entrypoints, and setup docs. - Added a large fixture-backed data source for Storybook so complex board states can render without a live server. - Added story suites covering foundations, status language, control-plane surfaces, overview, UX labs, agent management, budget and finance, forms and editors, issue management, navigation and layout, chat and comments, data visualization, dialogs and modals, and projects/goals/workspaces. - Adjusted several UI components for Storybook parity so dialogs, menus, keyboard shortcuts, budget markers, markdown editing, and related surfaces render correctly in isolation. - Rebasing work for PR assembly: replayed the branch onto current `master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned the dashboard fixture with the current `DashboardSummary.runActivity` API contract. ## Verification - `pnpm --filter @paperclipai/ui typecheck` - `pnpm --filter @paperclipai/ui build-storybook` - Manual diff audit after rebase: verified the PR no longer includes `pnpm-lock.yaml` and now cleanly targets current `master`. - Before/after UI note: before this branch there was no dedicated Storybook surface for these Paperclip views; after this branch the local Storybook build includes the new overview and domain story suites in `ui/storybook-static`. ## Risks - Large static fixture files can drift from shared types as dashboard and UI contracts evolve; this PR already needed one fixture correction for `runActivity`. - Storybook bundle output includes some large chunks, so future growth may need chunking work if build performance becomes an issue. - Several component tweaks were made for isolated rendering parity, so reviewers should spot-check key board surfaces against the live app behavior. ## Model Used - OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact serving model ID is not exposed in-runtime to the agent. - Tool-assisted workflow with terminal execution, git operations, local typecheck/build verification, and GitHub CLI PR creation. - Context window/reasoning mode not surfaced by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
createdByUserId: "user-board",
createdAt: new Date("2026-04-18T10:00:00.000Z"),
updatedAt: new Date("2026-04-20T10:00:00.000Z"),
},
Add secrets provider vaults and remote import (#5429) ## Thinking Path > - Paperclip orchestrates AI-agent companies and needs secrets handling to work across local development, hosted operators, and governed agent execution. > - The affected subsystem is the company-scoped secrets control plane: database schema, server services/routes, CLI workflows, and the Secrets settings UI. > - The gap was that secrets were local-only and operators could not manage provider vaults or import existing remote references without exposing plaintext. > - This branch adds provider vault configuration plus an AWS Secrets Manager remote-import path while preserving company boundaries, binding context, and audit trails. > - I kept the PR to a single branch PR, removed unrelated lockfile/package drift, rebased the full branch onto the current `public-gh/master`, and addressed fresh Greptile findings. > - The benefit is a reviewable implementation of provider-backed secrets with focused tests covering provider selection, import conflicts, deleted secret reuse, rotation guards, and AWS signing behavior. ## What Changed - Added provider vault support for company secrets, including provider config storage, default vault handling, health checks, binding usage, access events, and remote import preview/commit. - Added an AWS Secrets Manager provider using SigV4 request signing, bounded request timeouts, namespace guardrails, cached runtime credential resolution, and external-reference linking without plaintext reads. - Added Secrets UI surfaces for vault management and remote import, plus CLI/API documentation for setup and operations. - Stabilized routine webhook secret binding paths and SSH environment-driver fixture bindings discovered during verification. - Addressed Greptile and CI findings: no lockfile/package drift, monotonic migration metadata, disabled-vault default races, soft-deleted secret hiding/recreate behavior, remove behavior with disabled vaults, soft-deleted external-reference re-import, non-active rotation guards, managed-secret soft deletion through PATCH, and per-call AWS SDK credential client churn. - Rebased this branch onto `public-gh/master` at `0e1a5828` and force-pushed with lease to keep this as the single PR for the branch. ## Verification - `git fetch public-gh master` - `git rebase public-gh/master` - `git diff --name-only public-gh/master...HEAD | grep '^pnpm-lock\.yaml$' || true` confirmed `pnpm-lock.yaml` is not in the PR diff. - Confirmed migration ordering: master ends at `0081_optimal_dormammu`; this PR adds `0082_dry_vision` and `0083_company_secret_provider_configs`. - Inspected migrations for repeat safety: new tables/indexes use `IF NOT EXISTS`; foreign keys are guarded by `DO $$ ... IF NOT EXISTS`; column additions use `ADD COLUMN IF NOT EXISTS`. - `pnpm -r typecheck` passed before the Greptile follow-up commits. - `pnpm test:run` ran the full stable Vitest path before the Greptile follow-up commits; it completed with 3 timing-related failures under parallel load: `codex-local-execute.test.ts`, `cursor-local-execute.test.ts`, and `environment-service.test.ts`. - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/codex-local-execute.test.ts src/__tests__/cursor-local-execute.test.ts src/__tests__/environment-service.test.ts` passed on targeted rerun (`24/24`). - `pnpm build` passed before the Greptile follow-up commits. Vite reported existing chunk-size/dynamic-import warnings. - After Greptile follow-up commits: `pnpm --filter @paperclipai/server exec vitest run src/__tests__/secrets-service.test.ts` passed (`26/26`). - After Greptile follow-up commits: `pnpm --filter @paperclipai/server exec vitest run src/__tests__/aws-secrets-manager-provider.test.ts src/__tests__/secrets-service.test.ts` passed (`39/39`). - After Greptile follow-up commits: `pnpm --filter @paperclipai/server typecheck` passed. - Captured Storybook screenshots from `ui/storybook-static` for visual review. - Latest PR checks on `5ca3a5cf`: `policy`, serialized server suites 1/4-4/4, `Canary Dry Run`, `e2e`, `security/snyk`, and `Greptile Review` pass; aggregate `verify` is still registering the completed child checks. - Greptile review loop continued through the latest requested pass; all Greptile review threads are resolved and the latest `Greptile Review` check on `5ca3a5cf` passed with 0 comments added. ## Screenshots Before: the provider-vault and remote-import surfaces did not exist on `master`; these are after-state screenshots from the Storybook fixtures. ![Secrets inventory](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/secrets-inventory.png) ![Secret binding picker](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/secret-binding-picker.png) ![Environment editor with secrets](https://raw.githubusercontent.com/paperclipai/paperclip/PAP-2339-secrets-make-a-plan/doc/pr/5429/env-editor-with-secrets.png) ## Risks - Migration risk: this adds new secret provider tables and extends existing secret rows. The migrations were checked for monotonic ordering and idempotent guards, but reviewers should still inspect upgrade behavior carefully. - Provider risk: AWS support uses direct SigV4 requests. Automated tests cover signing, request timeouts, vault-config selection, namespace guardrails, pending-version archival, sanitized provider errors, and service-level cleanup paths. A real-vault AWS smoke test remains deployment validation for an operator with AWS credentials rather than an unverified merge blocker in this local branch. - UI risk: the Secrets page and import dialog are large new surfaces; screenshots are included above for reviewer inspection. - Verification risk: the full local stable test command hit parallel-load timing failures, although the exact failed files passed when rerun directly. - Operational risk: remote import intentionally avoids plaintext reads; operators must understand that imported external references resolve at runtime and may fail if AWS permissions change. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 coding agent with local shell/tool use in the Paperclip worktree. Exact context-window size was not exposed by the runtime. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 18:22:17 -05:00
{
id: "secret-github",
companyId: "company-storybook",
key: "github-token",
name: "GITHUB_TOKEN",
provider: "local_encrypted",
status: "active",
managedMode: "paperclip_managed",
externalRef: null,
providerConfigId: null,
providerMetadata: null,
latestVersion: 1,
description: null,
lastResolvedAt: null,
lastRotatedAt: new Date("2026-04-19T10:00:00.000Z"),
deletedAt: null,
createdByAgentId: null,
[codex] add comprehensive UI Storybook coverage (#4132) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies. > - The board UI is the main operator surface, so its component and workflow coverage needs to stay reviewable as the product grows. > - This branch adds Storybook as a dedicated UI reference surface for core Paperclip screens and interaction patterns. > - That work spans Storybook infrastructure, app-level provider wiring, and a large fixture set that can render real control-plane states without a live backend. > - The branch also expands coverage across agents, budgets, issues, chat, dialogs, navigation, projects, and data visualization so future UI changes have a concrete visual baseline. > - This pull request packages that Storybook work on top of the latest `master`, excludes the lockfile from the final diff per repo policy, and fixes one fixture contract drift caught during verification. > - The benefit is a single reviewable PR that adds broad UI documentation and regression-surfacing coverage without losing the existing branch work. ## What Changed - Added Storybook 10 wiring for the UI package, including root scripts, UI package scripts, Storybook config, preview wrappers, Tailwind entrypoints, and setup docs. - Added a large fixture-backed data source for Storybook so complex board states can render without a live server. - Added story suites covering foundations, status language, control-plane surfaces, overview, UX labs, agent management, budget and finance, forms and editors, issue management, navigation and layout, chat and comments, data visualization, dialogs and modals, and projects/goals/workspaces. - Adjusted several UI components for Storybook parity so dialogs, menus, keyboard shortcuts, budget markers, markdown editing, and related surfaces render correctly in isolation. - Rebasing work for PR assembly: replayed the branch onto current `master`, removed `pnpm-lock.yaml` from the final PR diff, and aligned the dashboard fixture with the current `DashboardSummary.runActivity` API contract. ## Verification - `pnpm --filter @paperclipai/ui typecheck` - `pnpm --filter @paperclipai/ui build-storybook` - Manual diff audit after rebase: verified the PR no longer includes `pnpm-lock.yaml` and now cleanly targets current `master`. - Before/after UI note: before this branch there was no dedicated Storybook surface for these Paperclip views; after this branch the local Storybook build includes the new overview and domain story suites in `ui/storybook-static`. ## Risks - Large static fixture files can drift from shared types as dashboard and UI contracts evolve; this PR already needed one fixture correction for `runActivity`. - Storybook bundle output includes some large chunks, so future growth may need chunking work if build performance becomes an issue. - Several component tweaks were made for isolated rendering parity, so reviewers should spot-check key board surfaces against the live app behavior. ## Model Used - OpenAI Codex, GPT-5-based coding agent in the Paperclip harness; exact serving model ID is not exposed in-runtime to the agent. - Tool-assisted workflow with terminal execution, git operations, local typecheck/build verification, and GitHub CLI PR creation. - Context window/reasoning mode not surfaced by the harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-20 12:13:23 -05:00
createdByUserId: "user-board",
createdAt: new Date("2026-04-19T10:00:00.000Z"),
updatedAt: new Date("2026-04-19T10:00:00.000Z"),
},
];
const filledEnv: Record<string, EnvBinding> = {
NODE_ENV: { type: "plain", value: "development" },
OPENAI_API_KEY: { type: "secret_ref", secretId: "secret-openai", version: "latest" },
};
const routineVariables: RoutineVariable[] = [
{
name: "repo",
label: "Repository",
type: "text",
defaultValue: "paperclipai/paperclip",
required: true,
options: [],
},
{
name: "priority",
label: "Priority",
type: "select",
defaultValue: "medium",
required: true,
options: ["low", "medium", "high"],
},
{
name: "include_browser",
label: "Include browser QA",
type: "boolean",
defaultValue: true,
required: false,
options: [],
},
{
name: "notes",
label: "Run notes",
type: "textarea",
defaultValue: "Capture any visible layout regressions.",
required: false,
options: [],
},
];
const storybookProject: Project = {
id: "project-board-ui",
companyId: "company-storybook",
urlKey: "board-ui",
goalId: "goal-company",
goalIds: ["goal-company"],
goals: [{ id: "goal-company", title: "We're building Paperclip" }],
name: "Board UI",
description: "Control-plane interface, Storybook review surfaces, and operator workflows.",
status: "in_progress",
leadAgentId: "agent-codex",
targetDate: null,
color: "#0f766e",
env: null,
pauseReason: null,
pausedAt: null,
executionWorkspacePolicy: null,
codebase: {
workspaceId: "workspace-board-ui",
repoUrl: "https://github.com/paperclipai/paperclip",
repoRef: "master",
defaultRef: "master",
repoName: "paperclip",
localFolder: "/Users/dotta/paperclip",
managedFolder: "paperclip",
effectiveLocalFolder: "/Users/dotta/paperclip",
origin: "local_folder",
},
workspaces: [],
primaryWorkspace: null,
archivedAt: null,
createdAt: new Date("2026-04-01T10:00:00.000Z"),
updatedAt: new Date("2026-04-20T10:00:00.000Z"),
};
const entityOptions: InlineEntityOption[] = [
{ id: "issue-1672", label: "Storybook forms and editors", searchText: "PAP-1672 ui story coverage" },
{ id: "project-board-ui", label: "Board UI", searchText: "project frontend Storybook" },
{ id: "agent-codex", label: "CodexCoder", searchText: "engineer implementation" },
];
function MarkdownEditorGallery() {
const [emptyMarkdown, setEmptyMarkdown] = useState("");
const [filledMarkdown, setFilledMarkdown] = useState(reviewMarkdown);
const [actionMarkdown, setActionMarkdown] = useState("Draft an update for @CodexCoder and /check-pr.");
return (
<Section
eyebrow="MarkdownEditor"
title="Composer states with content, read-only mode, and action buttons"
description="The editor is controlled in all examples so reviewers can type, trigger mentions, and see command insertion behavior."
>
<div className="grid gap-4 lg:grid-cols-2">
<StatePanel label="Empty" detail="Placeholder, border, and mention-ready empty state.">
<MarkdownEditor
value={emptyMarkdown}
onChange={setEmptyMarkdown}
placeholder="Write a task update..."
mentions={editorMentions}
/>
</StatePanel>
<StatePanel label="Filled" detail="Long-form markdown with a table and fenced code block.">
<MarkdownEditor value={filledMarkdown} onChange={setFilledMarkdown} mentions={editorMentions} />
</StatePanel>
<StatePanel label="Read-only" detail="Uses the editor rendering path without accepting edits." disabled>
<MarkdownEditor value={reviewMarkdown} onChange={() => undefined} readOnly mentions={editorMentions} />
</StatePanel>
<StatePanel label="Toolbar actions" detail="External controls exercise insertion actions around the editor.">
<div className="mb-3 flex flex-wrap gap-2">
<Button size="sm" variant="outline" onClick={() => setActionMarkdown((value) => `${value}\n\n## Next action\n`)}>
<FileText className="mr-2 h-4 w-4" />
Heading
</Button>
<Button size="sm" variant="outline" onClick={() => setActionMarkdown((value) => `${value}\n\n- Verify typecheck\n- Build Storybook\n`)}>
<ListPlus className="mr-2 h-4 w-4" />
List
</Button>
<Button size="sm" variant="outline" onClick={() => setActionMarkdown((value) => `${value}\n\n| Field | State |\n| --- | --- |\n| Forms | Ready |\n`)}>
<Table2 className="mr-2 h-4 w-4" />
Table
</Button>
<Button size="sm" variant="outline" onClick={() => setActionMarkdown((value) => `${value}\n\n\`\`\`sh\npnpm build-storybook\n\`\`\`\n`)}>
<Code2 className="mr-2 h-4 w-4" />
Code
</Button>
<Button size="sm" variant="ghost" onClick={() => setActionMarkdown("Draft an update for @CodexCoder and /check-pr.")}>
<RotateCcw className="mr-2 h-4 w-4" />
Reset
</Button>
</div>
<MarkdownEditor value={actionMarkdown} onChange={setActionMarkdown} mentions={editorMentions} />
</StatePanel>
</div>
</Section>
);
}
function MarkdownBodyGallery() {
return (
<Section
eyebrow="MarkdownBody"
title="Rendered markdown for task documents and comments"
description="GFM coverage includes headings, task lists, links, tables, and code blocks in the app's prose wrapper."
>
<div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_320px]">
<StatePanel label="Filled markdown" detail="Mixed document syntax with code and table overflow handling.">
<MarkdownBody linkIssueReferences={false}>{reviewMarkdown}</MarkdownBody>
</StatePanel>
<div className="space-y-4">
<StatePanel label="Empty">
<MarkdownBody>{""}</MarkdownBody>
<p className="text-sm text-muted-foreground">No markdown body content.</p>
</StatePanel>
<StatePanel label="Disabled container" disabled>
<MarkdownBody linkIssueReferences={false}>A read-only preview can be dimmed by the parent surface.</MarkdownBody>
</StatePanel>
</div>
</div>
</Section>
);
}
function JsonSchemaFormGallery() {
const [filledValues, setFilledValues] = useState<Record<string, unknown>>(validAdapterValues);
const [errorValues, setErrorValues] = useState<Record<string, unknown>>(invalidAdapterValues);
return (
<Section
eyebrow="JsonSchemaForm"
title="Generated adapter configuration forms"
description="The schema exercises strings, enums, secrets, numbers, booleans, arrays, objects, validation errors, and disabled controls."
>
<div className="grid gap-4 xl:grid-cols-2">
<StatePanel label="Filled">
<JsonSchemaForm schema={adapterSchema} values={filledValues} onChange={setFilledValues} />
</StatePanel>
<StatePanel label="Validation errors">
<JsonSchemaForm schema={adapterSchema} values={errorValues} onChange={setErrorValues} errors={adapterErrors} />
</StatePanel>
<StatePanel label="Empty schema">
<JsonSchemaForm schema={{ type: "object", properties: {} }} values={{}} onChange={() => undefined} />
</StatePanel>
<StatePanel label="Disabled" disabled>
<JsonSchemaForm schema={adapterSchema} values={filledValues} onChange={() => undefined} disabled />
</StatePanel>
</div>
</Section>
);
}
function InlineEditorGallery() {
const [title, setTitle] = useState("Storybook: Forms & Editors stories");
const [description, setDescription] = useState(
"Create fixture-backed editor stories for the board UI, then verify Storybook builds.",
);
const [emptyTitle, setEmptyTitle] = useState("");
return (
<Section eyebrow="InlineEditor" title="Inline title and description editing">
<div className="grid gap-4 lg:grid-cols-3">
<StatePanel label="Title editing" detail="Click the title to edit and press Enter to save.">
<InlineEditor value={title} onSave={setTitle} as="h2" className="text-2xl font-semibold" />
</StatePanel>
<StatePanel label="Description editing" detail="Multiline markdown editor with autosave affordance.">
<InlineEditor value={description} onSave={setDescription} as="p" multiline nullable />
</StatePanel>
<StatePanel label="Empty nullable title" detail="Placeholder state for optional inline fields.">
<InlineEditor value={emptyTitle} onSave={setEmptyTitle} as="h2" nullable placeholder="Untitled issue" />
</StatePanel>
</div>
</Section>
);
}
function EnvVarEditorGallery() {
const [emptyEnv, setEmptyEnv] = useState<Record<string, EnvBinding>>({});
const [env, setEnv] = useState<Record<string, EnvBinding>>(filledEnv);
const createSecret = async (name: string): Promise<CompanySecret> => ({
...storybookSecrets[0]!,
id: `secret-${name.toLowerCase()}`,
name,
latestVersion: 1,
});
return (
<Section eyebrow="EnvVarEditor" title="Runtime environment bindings">
<div className="grid gap-4 lg:grid-cols-3">
<StatePanel label="Empty add row" detail="Trailing blank row is the add state.">
<EnvVarEditor value={emptyEnv} secrets={storybookSecrets} onCreateSecret={createSecret} onChange={(next) => setEmptyEnv(next ?? {})} />
</StatePanel>
<StatePanel label="Plain and secret values" detail="Filled rows show edit, seal, secret select, and remove controls.">
<EnvVarEditor value={env} secrets={storybookSecrets} onCreateSecret={createSecret} onChange={(next) => setEnv(next ?? {})} />
</StatePanel>
<StatePanel label="Disabled shell" disabled>
<EnvVarEditor value={filledEnv} secrets={storybookSecrets} onCreateSecret={createSecret} onChange={() => undefined} />
</StatePanel>
</div>
</Section>
);
}
function ScheduleEditorGallery() {
const [emptyCron, setEmptyCron] = useState("");
const [weeklyCron, setWeeklyCron] = useState("30 9 * * 1");
const [customCron, setCustomCron] = useState("15 16 1 * *");
return (
<Section eyebrow="ScheduleEditor" title="Cron picker with human-readable previews">
<div className="grid gap-4 lg:grid-cols-3">
<StatePanel label="Empty default" detail={describeSchedule(emptyCron)}>
<ScheduleEditor value={emptyCron} onChange={setEmptyCron} />
</StatePanel>
<StatePanel label="Weekly filled" detail={describeSchedule(weeklyCron)}>
<ScheduleEditor value={weeklyCron} onChange={setWeeklyCron} />
</StatePanel>
<StatePanel label="Custom disabled preview" detail={describeSchedule(customCron)} disabled>
<ScheduleEditor value={customCron} onChange={setCustomCron} />
</StatePanel>
</div>
</Section>
);
}
function RoutineVariablesGallery() {
const [variables, setVariables] = useState<RoutineVariable[]>(routineVariables);
return (
<Section
eyebrow="RoutineVariablesEditor"
title="Detected runtime variable definitions"
description="Variable rows are synced from title and instructions placeholders, then configured with types, defaults, required flags, and select options."
>
<div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_320px]">
<StatePanel label="Detected variables">
<RoutineVariablesEditor
title="Review {{repo}} at {{priority}} priority"
description="Include browser QA: {{include_browser}}\n\nOperator notes: {{notes}}"
value={variables}
onChange={setVariables}
/>
</StatePanel>
<div className="space-y-4">
<StatePanel label="Empty hint">
<RoutineVariablesHint />
</StatePanel>
<StatePanel label="Disabled shell" disabled>
<RoutineVariablesEditor
title="Review {{repo}}"
description="Use {{priority}} priority"
value={variables.slice(0, 2)}
onChange={() => undefined}
/>
</StatePanel>
</div>
</div>
</Section>
);
}
function PickerGallery() {
const [issue, setIssue] = useState(() =>
createIssue({
executionPolicy: buildExecutionPolicy({
reviewerValues: ["agent:agent-qa"],
approverValues: ["user:user-board"],
}),
}),
);
const [manager, setManager] = useState<string | null>("agent-cto");
const [selectorValue, setSelectorValue] = useState("project-board-ui");
const agentsWithTerminated: Agent[] = useMemo(
() => [
...storybookAgents,
{
...storybookAgents[1]!,
id: "agent-legacy",
name: "LegacyReviewer",
status: "terminated",
reportsTo: null,
},
],
[],
);
return (
<Section
eyebrow="Pickers"
title="Execution participants, reporting hierarchy, and inline entity selection"
description="Closed trigger states stay compact, while the dropdowns are interactive for search and selection review."
>
<div className="grid gap-4 xl:grid-cols-3">
<StatePanel label="ExecutionParticipantPicker" detail="Review and approval participants share the same policy object.">
<div className="flex flex-wrap gap-3">
<ExecutionParticipantPicker
issue={issue}
stageType="review"
agents={storybookAgents}
currentUserId="user-board"
onUpdate={(patch) => setIssue((current) => ({ ...current, ...patch }))}
/>
<ExecutionParticipantPicker
issue={issue}
stageType="approval"
agents={storybookAgents}
currentUserId="user-board"
onUpdate={(patch) => setIssue((current) => ({ ...current, ...patch }))}
/>
</div>
</StatePanel>
<StatePanel label="ReportsToPicker" detail="Selected manager, CEO disabled state, and filtered hierarchy choices.">
<div className="flex flex-wrap gap-3">
<ReportsToPicker agents={agentsWithTerminated} value={manager} onChange={setManager} excludeAgentIds={["agent-codex"]} />
<ReportsToPicker agents={agentsWithTerminated} value={null} onChange={() => undefined} disabled />
</div>
</StatePanel>
<StatePanel label="InlineEntitySelector" detail="Search/select dropdown for issue, project, and agent entities.">
<div className="flex flex-wrap gap-3">
<InlineEntitySelector
value={selectorValue}
options={entityOptions}
recentOptionIds={["issue-1672"]}
placeholder="Entity"
noneLabel="No entity"
searchPlaceholder="Search entities..."
emptyMessage="No matching entity."
onChange={setSelectorValue}
/>
<div className="pointer-events-none opacity-55">
<InlineEntitySelector
value=""
options={entityOptions}
placeholder="Entity"
noneLabel="No entity"
searchPlaceholder="Search entities..."
emptyMessage="No matching entity."
onChange={() => undefined}
/>
</div>
</div>
</StatePanel>
</div>
</Section>
);
}
function FormsEditorsShowcase() {
return (
<StoryShell>
<section className="paperclip-story__frame p-6">
<div className="flex flex-wrap items-start justify-between gap-5">
<div>
<div className="paperclip-story__label">Forms and editors</div>
<h1 className="mt-2 text-3xl font-semibold tracking-tight">Paperclip form controls under realistic state</h1>
<p className="mt-3 max-w-3xl text-sm leading-6 text-muted-foreground">
Dense control-plane forms need to hold empty, filled, validation, and disabled states without losing scan
speed. These fixtures keep the components reviewable outside production routes.
</p>
</div>
<div className="flex flex-wrap gap-2">
<Badge variant="outline">empty</Badge>
<Badge variant="outline">filled</Badge>
<Badge variant="outline">validation</Badge>
<Badge variant="outline">disabled</Badge>
</div>
</div>
</section>
<MarkdownEditorGallery />
<MarkdownBodyGallery />
<JsonSchemaFormGallery />
<InlineEditorGallery />
<EnvVarEditorGallery />
<ScheduleEditorGallery />
<RoutineVariablesGallery />
<PickerGallery />
</StoryShell>
);
}
function RoutineRunDialogStory() {
const [open, setOpen] = useState(true);
const [submitted, setSubmitted] = useState<RoutineRunDialogSubmitData | null>(null);
return (
<StoryShell>
<Section
eyebrow="RoutineRunVariablesDialog"
title="Manual routine run configuration"
description="The dialog collects runtime variables, the target assignee, and optional project context before creating the run issue."
>
<div className="flex flex-wrap items-center gap-3">
<Button onClick={() => setOpen(true)}>Open run dialog</Button>
{submitted ? (
<pre className="max-w-full overflow-x-auto rounded-md border border-border bg-muted/40 px-3 py-2 text-xs">
{JSON.stringify(submitted, null, 2)}
</pre>
) : (
<span className="text-sm text-muted-foreground">Submit the dialog to inspect the payload.</span>
)}
</div>
</Section>
<RoutineRunVariablesDialog
open={open}
onOpenChange={setOpen}
companyId="company-storybook"
routineName="Weekly release review"
projects={[storybookProject]}
agents={storybookAgents}
defaultProjectId="project-board-ui"
defaultAssigneeAgentId="agent-codex"
variables={routineVariables}
isPending={false}
onSubmit={(data) => {
setSubmitted({ ...data });
setOpen(false);
}}
/>
</StoryShell>
);
}
const meta = {
title: "Components/Forms & Editors",
parameters: {
docs: {
description: {
component:
"Fixture-backed stories for Paperclip form controls, markdown editors, inline editors, schedule controls, runtime-variable dialogs, and selection pickers.",
},
},
},
} satisfies Meta;
export default meta;
type Story = StoryObj<typeof meta>;
export const AllFormsAndEditors: Story = {
name: "All Forms And Editors",
render: () => <FormsEditorsShowcase />,
};
export const RoutineRunVariablesDialogOpen: Story = {
name: "Routine Run Variables Dialog",
render: () => <RoutineRunDialogStory />,
};
[codex] Polish issue composer and long document display (#4420) ## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Issue comments and documents are the main working surface where operators and agents collaborate > - File drops, markdown editing, and long issue descriptions need to feel predictable because they sit directly in the task execution loop > - The composer had edge cases around drag targets, attachment feedback, image drops, and long markdown content crowding the page > - This pull request polishes the issue composer, hardens markdown editor regressions, and adds a fold curtain for long issue descriptions/documents > - The benefit is a calmer issue detail surface that handles uploads and long work products without hiding state or breaking layout ## What Changed - Scoped issue-composer drag/drop behavior so the composer owns file drops without turning the whole thread into a competing drop target. - Added clearer attachment upload feedback for non-image files and image-drop stability coverage. - Hardened markdown editor and markdown body handling around HTML-like tag regressions. - Added `FoldCurtain` and wired it into issue descriptions and issue documents so long markdown previews can expand/collapse. - Added Storybook coverage for the fold curtain state. ## Verification - `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx ui/src/components/MarkdownEditor.test.tsx ui/src/components/MarkdownBody.test.tsx --config ui/vitest.config.ts` passed: 3 files, 75 tests. - `git diff --check public-gh/master..pap-2228-editor-composer-polish -- . ':(exclude)ui/storybook-static'` passed. - Confirmed this PR does not include `pnpm-lock.yaml`. ## Risks - Low-to-medium risk: this changes user-facing composer/drop behavior and long markdown display. - The fold curtain uses DOM measurement and `ResizeObserver`; reviewers should check browser behavior for very long descriptions and documents. - No database migrations. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex coding agent based on GPT-5, with shell, git, Paperclip API, and GitHub CLI tool use in the local Paperclip workspace. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge Note: screenshots were not newly captured during branch splitting; the UI states are covered by component tests and a Storybook story. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-04-24 14:12:41 -05:00
const foldCurtainLongMarkdown = [
"# paperclip-bench",
"",
"Ship criteria for the benchmark harness — these notes are intentionally lengthy so the fold-curtain clips them.",
"",
"## Overview",
"",
"We need a benchmark that compares agent performance across task types and model backends. This includes:",
"",
"- a **runner** that executes tasks in isolated workspaces",
"- a **scorer** that grades outputs against ground truth",
"- a **dashboard** that trends metrics over time",
"",
"## Task format",
"",
"Each task is a directory containing a `task.md`, an optional `setup.sh`, and an `expected/` fixture. The runner mounts the task, executes the agent, and diffs the resulting workspace against `expected/`.",
"",
"```ts",
"type TaskResult = {",
" taskId: string;",
" agent: string;",
" exitCode: number;",
" scoreBreakdown: Record<string, number>;",
"};",
"```",
"",
"## Metrics",
"",
"| Metric | Description |",
"| --- | --- |",
"| Pass@1 | First-try correctness |",
"| Tokens | Cost per task |",
"| Wall time | End-to-end minutes |",
"",
"## Next steps",
"",
"1. Land the runner with support for 3 task types.",
"2. Backfill 50 tasks from open-source benchmarks.",
"3. Wire the scorer to GitHub Actions.",
"4. Publish baseline numbers on the main branch.",
"",
"All of this is described in more detail in the design doc linked from the home page.",
].join("\n");
const foldCurtainShortMarkdown = "This description is short. No curtain should appear.";
function FoldCurtainStory() {
return (
<StoryShell>
<Section
eyebrow="Presentation"
title="FoldCurtain"
description="Long content collapses to a preview with a bottom fade and a Show more button. Short content renders untouched."
>
<div className="space-y-6">
<StatePanel
label="Long description (collapsed)"
detail="Default state on every fresh page load. Natural height far exceeds the collapsed height, so the curtain activates."
>
<FoldCurtain>
<MarkdownBody className="text-[15px] leading-7">{foldCurtainLongMarkdown}</MarkdownBody>
</FoldCurtain>
</StatePanel>
<StatePanel
label="Short description (no curtain)"
detail="Content below the activation threshold renders with no curtain and no button."
>
<FoldCurtain>
<MarkdownBody className="text-[15px] leading-7">{foldCurtainShortMarkdown}</MarkdownBody>
</FoldCurtain>
</StatePanel>
</div>
</Section>
</StoryShell>
);
}
export const FoldCurtainShowcase: Story = {
name: "Fold Curtain",
render: () => <FoldCurtainStory />,
};