import { AnimatedDialogContent } from "@/components/AnimatedDialogContent";
import { ExternalAgentPresetPicker, DotConnectionChecks } from "@/components/new-agent/ExternalAgentInviteContent";
import { AgentMailApiKeyField } from "@/features/connections/AgentMailApiKeyField";
import { TaskBrowserFooter } from "@/components/task-side-panel/TaskBrowserFooter";
import { TaskBrowserActivity } from "@/components/task-side-panel/TaskBrowserActivity";
import type { TaskBrowser } from "@paperclipai/shared";
import { DispositionRecoveryNotice } from "../components/DispositionRecoveryNotice";
import { CloudSignIn } from "../components/CloudSignIn";
import { CloudAccessError } from "../components/CloudAccessGate";
import { SetupPrompt } from "./apps/chat/SetupPrompt";
import { MediaArtifactCard } from "@/components/artifacts/MediaArtifactCard";
import { SkillSourceTree } from "./skills/SkillSourceTree";
import { SkillBinaryFile } from "../components/SkillBinaryFile";
import { WebhookUrlWarning } from "@/components/routine-triggers/WebhookUrlWarning";
import { SetupWizardNavigation, SetupWizardFooter } from "../components/SetupWizard";
import { RemoteMcpDesignExample } from "@/features/connections/remote-mcp/RemoteMcpDesignExample";
import { AgentConversationSidebar } from "@/components/AgentConversationSidebar";
import { AgentChatPicker } from "@/components/AgentChatPicker";
import { TaskChatProjectCreatedCard } from "@/components/task-chat/TaskChatProjectCreatedCard";
import { TextAttachmentPreview } from "@/components/task-side-panel/TaskAttachmentPanel";
import { AnnouncementCard } from "@/components/AnnouncementCard";
import { announcementPreview, announcementAnimationPreview, announcementAnimationPreviewSrc } from "@/lib/announcement-preview";
import { TaskDetailTasksPanel } from "@/components/task-detail/TaskDetailTasksPanel";
import { AiConnectionDesignExamples } from "@/components/ai-connections/AiConnectionDesignExamples";
import { SavedProviderKeySelect } from "../components/onboarding/SavedProviderKeySelect";
import { AgentAvatar } from "@/components/AgentAvatar";
import { AgentCharacter } from "@/components/AgentCharacter";
import { AGENT_PALETTE_IDS, appearanceForPalette } from "@paperclipai/shared";
import { RepositoryEditor } from "@/components/RepositoryEditor";
import { TaskChatRunnerActivityGroup } from "@/components/task-chat/TaskChatRunnerActivityGroup";
import { TaskChatMarker } from "@/components/task-chat/TaskChatMarker";
import { TaskChatComposer } from "@/components/task-chat/TaskChatComposer";
import { ComposerAddMenu, ComposerModeChip } from "@/components/task-chat/ComposerAddMenu";
import type { IssueWorkMode } from "@paperclipai/shared";
import { TaskTreeControlDialog, TaskTreeControlMenuItems } from "@/components/TaskTreeControls";
import { useState } from "react";
import {
BookOpen,
Bot,
Check,
ChevronDown,
CircleDot,
Command as CommandIcon,
DollarSign,
Hexagon,
History,
Inbox,
LayoutDashboard,
ListTodo,
Mail,
Plus,
Search,
Settings,
Target,
Trash2,
Upload,
User,
Zap,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "@/components/ThemeToggle";
import { Badge } from "@/components/ui/badge";
import { InlineBanner } from "@/components/InlineBanner";
import { BuiltInLifecycleChip } from "@/components/BuiltInAgentBadges";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable-panels";
import { Skeleton } from "@/components/ui/skeleton";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from "@/components/ui/dialog";
import {
Tooltip,
TooltipTrigger,
TooltipContent,
} from "@/components/ui/tooltip";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/components/ui/select";
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuCheckboxItem,
DropdownMenuShortcut,
} from "@/components/ui/dropdown-menu";
import {
Popover,
PopoverTrigger,
PopoverContent,
} from "@/components/ui/popover";
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter,
} from "@/components/ui/sheet";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "@/components/ui/collapsible";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Command,
CommandInput,
CommandList,
CommandGroup,
CommandItem,
CommandEmpty,
CommandSeparator,
} from "@/components/ui/command";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
} from "@/components/ui/avatar";
import { AgentCapsule, AGENT_GRADIENT_COUNT } from "@/components/AgentCapsule";
import { AgentRunCard } from "@/components/ActiveAgentsPanel";
import { StatusBadge, IssueStatusBadge } from "@/components/StatusBadge";
import { StatusIcon } from "@/components/StatusIcon";
import { EnforcementBanner } from "@/components/EnforcementBanner";
import { ActionCard, ActionCardMobile, BindingsTable } from "@/components/actions/ActionCard";
import { PriorityIcon } from "@/components/PriorityIcon";
import { SHOW_TASK_PRIORITY_UI } from "@/lib/ui-flags";
import { agentStatusDot, agentStatusDotDefault } from "@/lib/status-colors";
import { EntityRow } from "@/components/EntityRow";
import { EmptyState } from "@/components/EmptyState";
import { MetricCard } from "@/components/MetricCard";
import { FilterBar, type FilterValue } from "@/components/FilterBar";
import { InlineEditor } from "@/components/InlineEditor";
import { PageSkeleton } from "@/components/PageSkeleton";
import { Identity } from "@/components/Identity";
import { AppLogo } from "@/pages/apps/AppLogo";
import { IssueReferencePill } from "@/components/IssueReferencePill";
import { LockedIssueChip } from "@/components/LockedIssueChip";
import { MembershipAction } from "@/components/MembershipAction";
import { IssueOutputSection } from "@/components/issue-output/IssueOutputSection";
import { EnvironmentVariablesEditor } from "@/components/environment-variables-editor";
import { IssueThreadInteractionCard } from "@/components/IssueThreadInteractionCard";
import {
connectedConnectionIntentInteraction,
issueThreadInteractionFixtureMeta,
pendingConnectionIntentInteraction,
retryConnectionIntentInteraction,
} from "@/fixtures/issueThreadInteractionFixtures";
import type { CompanySecret, EnvBinding, Issue } from "@paperclipai/shared";
import { CollectionToolbar } from "@/components/CollectionToolbar";
import { IssueRow } from "@/components/IssueRow";
import {
EnvInputsList,
ExternalSourcesList,
RequiredSkillsList,
StepSkillPlan,
StepSourcePolicy,
TeamCard,
TeamHierarchyPreview,
TeamRow,
} from "@/pages/TeamCatalog";
import {
currentInstalledState,
onboardingTeams,
optionalTeam,
outOfDateInstalledState,
sampleSkillPreparations,
sampleTeam,
warnTeam,
} from "@/pages/TeamCatalog.fixtures";
import type { IssueWorkProduct } from "@paperclipai/shared";
/* ------------------------------------------------------------------ */
/* Sample data for the Issue Output surface showcase */
/* ------------------------------------------------------------------ */
function sampleOutput(
id: string,
attachmentId: string,
contentType: string,
filename: string,
opts: { byteSize: number; isPrimary?: boolean; createdAt: string },
): IssueWorkProduct {
const contentPath = `/api/attachments/${attachmentId}/content`;
return {
id,
companyId: "demo-company",
projectId: null,
issueId: "demo-issue",
executionWorkspaceId: null,
runtimeServiceId: null,
type: "artifact",
provider: "paperclip",
externalId: null,
title: filename,
url: null,
status: "active",
reviewState: "none",
isPrimary: Boolean(opts.isPrimary),
healthStatus: "unknown",
summary: null,
createdByRunId: null,
createdAt: new Date(opts.createdAt),
updatedAt: new Date(opts.createdAt),
metadata: {
attachmentId,
contentType,
byteSize: opts.byteSize,
contentPath,
openPath: contentPath,
downloadPath: `${contentPath}?download=1`,
originalFilename: filename,
},
} as IssueWorkProduct;
}
const DESIGN_GUIDE_OUTPUTS: IssueWorkProduct[] = [
sampleOutput("wp-vid", "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "video/mp4", "q3-summary.mp4", {
byteSize: 19_293_798,
isPrimary: true,
createdAt: "2026-05-30T12:00:00Z",
}),
sampleOutput("wp-pdf", "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb", "application/pdf", "talking-points.pdf", {
byteSize: 421_888,
createdAt: "2026-05-30T11:52:00Z",
}),
];
const DESIGN_GUIDE_DEGRADED_OUTPUTS: IssueWorkProduct[] = [
{
...sampleOutput("wp-broken", "cccccccc-cccc-4ccc-8ccc-cccccccccccc", "video/mp4", "corrupt-output.mp4", {
byteSize: 0,
isPrimary: true,
createdAt: "2026-05-30T12:01:00Z",
}),
// Strip the path metadata so it fails the shared artifact schema.
metadata: { attachmentId: "cccccccc-cccc-4ccc-8ccc-cccccccccccc", contentType: "video/mp4" },
} as IssueWorkProduct,
];
const DESIGN_GUIDE_TASK = {
id: "design-guide-task",
identifier: "PAP-427",
title: "Reconcile the navigation model across operator surfaces",
status: "in_progress",
priority: "medium",
blockerAttention: false,
} as unknown as Issue;
/* ------------------------------------------------------------------ */
/* Section wrapper */
/* ------------------------------------------------------------------ */
function Section({ title, children }: { title: string; children: React.ReactNode }) {
return (
{title}
{cssVar}
{name}
{running ? "Running: type to switch Stop to Send." : "Paused: resume from the menu."}
Should the agent use the existing draft?
Every component, style, and pattern used across Paperclip.
This page should be updated when new UI primitives or app-level patterns ship.
CollectionToolbar owns shared geometry while each page owns its state and behavior. The canonical task row is opt-in during migration: status leads, unread work uses title emphasis, metadata remains stable, and the task identifier trails.
Card Title — text-sm font-medium
Card Title Alt — text-sm font-semibold
Body text — text-sm
Muted description — text-sm text-muted-foreground
Tiny label — text-xs text-muted-foreground
Mono identifier — text-sm font-mono text-muted-foreground
Large stat — text-2xl font-bold
Log/code text — font-mono text-xs
Used wherever a task is referenced — in markdown, the Related Work tab, and activity summaries.
Pass status to show the target issue's state at a glance.
Use variant="property" for compact badges with direct navigation.
Pass onRemove for a separate blocker removal control with reserved space.
Use strikethrough for "removed" contexts.
Existence-only reference to a private task shown from a surface the viewer can see (a blocker edge, a mention). Mono id + lock, dashed muted border,{" "} no title, never a link. Falls back to "Private" when even the identifier is withheld.
The brand "capsule is the agent" motif. A single agent reads as a tall
pill that moves through three states as it comes to life. The online fill uses
the live brand agent-gradient tokens (--agent-Na →{" "}
--agent-Nb); prefers-reduced-motion{" "}
skips the liquid rise and pulses and renders the final state.
Title (single-line)
Body text (single-line)
Description (multiline, auto-sizing)
Native single-value dropdowns share an inset, theme-aware caret and reserve room for it in the base stylesheet. Multiple-selection lists and controls with a custom icon keep their own appearance.
Current value: {selectValue}
Agent heartbeat
Last run succeeded 24s ago. Next timer run in 9m.
The dashboard and Live runs page use the same compact cards. In-progress task icons animate across the app, including between runs, to represent task workflow status. Live indicators report active execution. Open a run to view its status and transcript.
Card content goes here. This is the main body area.
Overview tab content.
Runs tab content.
Config tab content.
Costs tab content.
Summary content with underline tabs.
Details content.
Comments content.
Place one live character beside the agent name. Onboarding uses a larger padded frame. Onboarding and agent headers follow the pointer across the page; other placements track within their region. Full-page examples are in Storybook under Agents / Personas / Full pages.
Zapier, Arcade, Composio and Executor each own a connection. Their controlled setup views share Access → Connect. Tool discovery completes setup. Saved connections reuse the standard Permissions action list and per-action Test dialog. Storybook’s Apps / Connections groups use in-memory provider fixtures.
Shared by connection setup and trigger previews. Setup navigation takes over the section sidebar; each step owns a single footer.
Layout accepts sidebarSections to compose additional SidebarSection groups inside the shared sidebar. Use SidebarNavItem for each row, with sibling action buttons for starring or menus. The Chats section shows starred agents, the earliest-created agent when unstarred, then four recent agents without duplicates. Compose and star controls share a vertical column. Compose appears on hover or keyboard focus and remains visible on touch; starred icons remain visible. The picker searches all company agents by name or role without a subtitle, count, continuation labels, or footer. Task breadcrumbs support leading identity and trailing actions beside the label, including single-item task headers; see the Agent chat Storybook.
Started working on the authentication module. Will need API keys configured.
API keys have been added to the vault. Please proceed.
| Model | Tokens | Cost |
|---|---|---|
| claude-sonnet-4-20250514 | 1.2M | $18.00 |
| claude-haiku-4-20250506 | 500k | $1.25 |
| Total | 1.7M | $19.25 |
Horizontal
Components from the Team Catalog browse/install surface (/teams-catalog).
Fixtures are shared with the Storybook stories.
Installed teams collapse under INSTALLED · N; an out-of-date
install (server originHash ≠ catalog contentHash)
shows the amber ↑ badge (PAP-10256).
Square tile for the onboarding “Pick a starter team” grid. Selected tile gets{" "}
ring-2 ring-ring. Drives the{" "}
useInstallTeamCatalogEntry simplified flow.
When an issue has produced no artifact work products, the Output section renders nothing at all (no placeholder card).
Persistent at the top of the Tools & Access surface. Tints to denied-detected when
governed tool calls were denied or failed in the last hour. Observability only — enforcement lives
in the tool gateway.
Static governance copy with a tone. Used for the PAP-10400 trust-tier banner on Runtime and the
effective-access banner on Agent → Tools. Pass title/body and an optional{" "}
icon.
Signed payload sha256 + expiry surface on every variant (PAP-10400). The{" "}
stale variant tints the border amber, banners the catalog-hash mismatch, strikes through
the previous hash next to the current one, and renders Approve disabled until the request
is re-issued.
Identical content; the three buttons stack full-width in the order Approve / Deny / Edit & re-sign, and the bindings table uses a 70px label column.
Two-column key/value block with mono values. Lives inside ActionCard and is reused
standalone in the audit row drilldown.
Policy decisions, connection/runtime health, and catalog quarantine all route through the canonical{" "}
StatusBadge keys defined in lib/status-colors.
The shared FileTree explorer layout puts disclosure controls beside selection, with compact folder chains, equal-height rows, inline skill descriptions, and trailing status badges. Folders select descendant packages; package checkboxes select only that package, independently of nested skills. Included files use aligned rows without individual checkboxes (`getCheckboxState` returns null); package rows use `renderNodeExtra` for file counts and inspection. Use arrow keys to navigate and Space to select.
Loading, errors, empty search, mobile, and short viewports are covered in the Project repos Storybook stories.
Reusable env-var editor (agents, projects, environments, routines). One shared grid, an in-field Text/Secret source switch, a fuzzy secret picker with a pinned “Create secret” item, automatic sensitive-value detection, and inline secret-health warnings. See the Storybook Product/Environment Variables Editor stories for all 10 states.
Storybook’s Recovery notice stories show the actionable, pending, acknowledged, unavailable, failed, and mobile states using this production component.
A decision card sits above the ordinary message composer. Dismiss the card to keep a reopen control, or resolve it to clear the pending state.
Recovery runs in the background. Task lists keep their ordinary status without execution badges. Active transcript headers keep saying Working during automatic recovery. Recovery decisions and attempts belong in the run log; there is no execution status card or reconciliation form.
Match the harness picker with provider cards. Connection checks reflect confirmed server evidence. AnimatedDialogContent resizes to its content using motion tokens and respects reduced motion.
Use AgentSetupPrompt for prompts handed to an external agent: connections, webhook setup, onboarding, and task handoffs. One click copies the complete prompt, opens its preview, and confirms success inline; clipboard failures offer selectable text.
For a named recipient, pass the optional agent name and logo. The same copy feedback, preview, and manual clipboard recovery apply.
The task card is the dialog host for the shared connection setup flow. Provider forms, validation, OAuth, access selection, and completion come from the same feature module as the full-page Apps setup; this card owns only audience, dialog, and task refresh behavior. Pending connections stay in the timeline beside a usable composer. The independently addressable Connections/In-task connections stories cover access, OAuth recovery, narrow layouts, completion, and historical outcomes. AgentMail uses an inline API-key field with fixed access defaults; its field and direct key-page link are shared with Apps setup.
AgentMail setup has two steps: pick an agent, then pick an email address. Ask for the API key alongside the agent only when needed. Keep address errors beside the field and additional settings under Advanced options.
Preview only. This field does not save or submit a credential.
Design-system wrapper over react-resizable-panels{" "} (Skill Studio D2). Drag a handle to resize; panels accept percentage or pixel (minSize="240px") constraints and the middle panel is collapsible. Use anywhere a split view is needed.
Token-backed full-width notice (brandBanner tones). Use{" "} info for provenance/context and{" "} warning for paused/attention. Supports an optional bold title and a trailing actions slot. Replaces hand-rolled{" "} bg-yellow-*/bg-blue-*{" "} banners.
Uploaded text opens in a named task tab. Markdown offers Rendered and Raw icon controls; every text file has a download action.
Fit to pane follows the visible panel. Fixed viewport presets and session actions live in the footer menu. Costs stay in task reporting. The idle countdown appears only in the final five minutes. Full panel, activity, and settings states are in Storybook under Browser Use.
{(["running", "idle", "closing-soon", "closed"] as const).map((state) => (Each browser appears once at its opening time among the task messages. Its status updates in place; the action opens its side-panel tab.
{(["starting", "running", "idle", "closed", "failed"] as const).map((status) => (Images and videos use gallery tiles. The whole tile opens the task gallery; files and links keep compact, fully clickable rows. Task/Artifact Gallery in Storybook covers playable videos, mixed files, narrow panels, and unavailable previews.
A derived lifecycle chip (amber) for attention states. The lifecycle chip is separate from the agent status vocabulary and only shows for{" "} needs_setup / pending_approval.
<BuiltInAgentGate agentKey> composes{" "} PageSkeleton + EmptyState{" "} + InlineBanner to render the loading / setup / pending-approval / paused / ready states of a feature that depends on a built-in agent.