import type { CatalogEntry } from './types'; /** * The curated Foundry app-UI catalog. Order is roughly "reach for these first" → * heavier/nicher last. Keep it small and honest: every entry must be genuinely * useful in a data-driven tenant app and cheap to explain to a non-technical * owner. `builtIn` blocks ship in the template today; the rest are scaffolded in * on demand so the base template stays thin. */ export const UI_CATALOG: CatalogEntry[] = [ { id: 'metrics', category: 'widget', title: 'Metrics row', description: 'A row of big-number tiles, one per entity type, each linking to its section. The default at-a-glance overview — good on almost every app.', dataNeeds: 'Any types (uses record counts).', builtIn: true, source: { export: 'MetricCard', from: '@startsimpli/ui' }, configExample: { kind: 'metrics', title: 'Overview' }, }, { id: 'quick-create', category: 'widget', title: 'Quick add', description: 'One-click "New " buttons that open the create form in a dialog. The fast path from an empty app to its first records.', dataNeeds: 'Any types.', builtIn: true, source: { export: 'BaseDialog', from: '@startsimpli/ui' }, configExample: { kind: 'quick-create', title: 'Quick add' }, }, { id: 'pipeline', category: 'widget', title: 'Pipeline funnel', description: 'A funnel of one type\'s records across the stages of its status field, with per-stage counts and conversion. Best for a clear forward workflow (e.g. lead → won). Reads oddly for branch statuses like "rejected".', dataNeeds: 'A type with a status/enum field whose stages flow forward.', builtIn: true, source: { export: 'PipelineFunnel', from: '@startsimpli/ui' }, configExample: { kind: 'pipeline', type: '', title: 'Pipeline' }, }, { id: 'recent', category: 'widget', title: 'Recent activity', description: 'A live feed of the most recently created records — across all types or one — with type badges and relative timestamps.', dataNeeds: 'Any types (uses created_at).', builtIn: true, source: { export: 'Card', from: '@startsimpli/ui' }, configExample: { kind: 'recent', limit: 8, title: 'Recent activity' }, }, { id: 'type-grid', category: 'widget', title: 'Section cards', description: 'The classic per-type card grid: count + status breakdown, each card links into its section. A compact index of the whole app.', dataNeeds: 'Any types.', builtIn: true, source: { export: 'Card', from: '@startsimpli/ui' }, configExample: { kind: 'type-grid', title: 'All sections' }, }, { id: 'kanban-board', category: 'widget', title: 'Kanban board preview', description: 'A drag-to-move board that lays a status type\'s records into lanes. Use as a home widget for the primary workflow type, or as the full section for it.', dataNeeds: 'A type with a status/enum field.', heavy: true, source: { export: 'KanbanBoard', from: '@startsimpli/ui' }, configExample: { kind: 'kanban-board', type: '', title: 'Board' }, }, { id: 'pipeline-health', category: 'widget', title: 'Pipeline health', description: 'A compact health card for one status type: how many records sit in each stage, plus a stuck/aging flag that pulls the card to a warning tone. Use on a system-health home to bubble up a content type\'s throughput at a glance (the pipeline funnel shows conversion; this shows health).', dataNeeds: 'A type with a status/enum field.', source: { export: 'PipelineHealth', from: '@startsimpli/ui' }, configExample: { kind: 'pipeline-health', type: '', title: 'Pipeline health' }, }, { id: 'source-freshness', category: 'widget', title: 'Source freshness', description: 'A health card listing upstream sources as fresh vs stale by their last-updated time — any stale feed pulls the card to a warning. Use to prove ongoing ingestion is actually flowing (a stale source is a bug, not coverage).', dataNeeds: 'A type whose records carry a last-updated / last-fetched timestamp.', source: { export: 'SourceFreshness', from: '@startsimpli/ui' }, configExample: { kind: 'source-freshness', type: '', title: 'Source freshness' }, }, { id: 'delivery-health', category: 'widget', title: 'Delivery health', description: 'A health card for scheduled deliverables: on-time / late / missed / upcoming counts derived from a type\'s scheduled and delivered date fields. Use for recurring outputs like weekly briefs.', dataNeeds: 'A type with a scheduled-date and a delivered-date field.', source: { export: 'DeliveryHealth', from: '@startsimpli/ui' }, configExample: { kind: 'delivery-health', type: '', scheduledField: '', deliveredField: '', title: 'Delivery', }, }, { id: 'attention', category: 'widget', title: 'Needs attention', description: 'A cross-type queue of records that need a human — stuck records, drafts awaiting review. Empty is the healthy state. Use as the "what should I look at" panel on a system-health home.', dataNeeds: 'Any types (flags records by status / age).', source: { export: 'AttentionFeed', from: '@startsimpli/ui' }, configExample: { kind: 'attention', limit: 8, title: 'Needs attention' }, }, { id: 'data-table', category: 'view', title: 'Data table', description: 'An enterprise table for one type — sortable columns, column picker, server pagination, Excel export. Use for dense list types the owner scans and exports.', dataNeeds: 'Any type (renders its fields as columns).', heavy: true, source: { export: 'UnifiedTable', from: '@startsimpli/ui/table' }, configExample: { kind: 'data-table', type: '', title: 'Records' }, }, { id: 'calendar', category: 'view', title: 'Calendar', description: 'A month/week calendar of a type\'s records placed by one of its date fields. Use for anything time-anchored — events, posts, deadlines.', dataNeeds: 'A type with a date field.', heavy: true, source: { export: 'CalendarView', from: '@startsimpli/ui' }, configExample: { kind: 'calendar', type: '', dateField: '', title: 'Calendar' }, }, { id: 'gantt', category: 'view', title: 'Gantt timeline', description: 'A timeline of records with start/end dates as bars, with board and timeline modes. Use for scheduling/project types spanning ranges.', dataNeeds: 'A type with a start-date and an end-date field.', heavy: true, source: { export: 'GanttChart', from: '@startsimpli/ui/gantt' }, configExample: { kind: 'gantt', type: '', startField: '', endField: '', title: 'Timeline' }, }, { id: 'metric-trend', category: 'widget', title: 'Trend metric', description: 'A single metric tile with a sparkline and up/down trend. Use to headline one number that matters (this week\'s new records, a running total).', dataNeeds: 'Any type, or a numeric field tracked over time.', source: { export: 'MetricCard', from: '@startsimpli/ui' }, configExample: { kind: 'metric-trend', type: '', title: 'This week' }, }, { id: 'command-palette', category: 'component', title: 'Command palette', description: 'A ⌘K global search/jump over the app\'s sections and records. An app-shell add-on, not a home widget — enable it once for the whole app.', dataNeeds: 'Any types.', source: { export: 'CommandPalette', from: '@startsimpli/ui' }, }, { id: 'document-editor', category: 'component', title: 'Document editor', description: "A Google-Docs-like editor over a record's sub-sections — long-text as markdown (edit/preview split), plain text with word count, structured key/value fields (with an SEO meta-description meter), and editable source lists. Controlled + debounced-autosave (the app owns persistence). Use to review + edit a multi-part content record (e.g. a marketing draft: blog + LinkedIn + SEO + sources); the read-only DraftReviewWorkspace is its compare/approve complement. Map schema→sections with sectionsFromRecord.", dataNeeds: 'A type with long-text / structured (json) fields to edit (optionally a source-list field).', source: { export: 'DocumentEditor', from: '@startsimpli/ui/document-editor' }, }, { id: 'validation-checklist', category: 'component', title: 'Validation checklist', description: "A pass/warn/fail review panel for an AI-generated content record: renders the deterministic auto-checks (word-count bands, hype-word scan, approved-source allow-list) as a green/amber/red checklist, surfaces the buried AI judge verdict (per-dimension scores + an expandable issues list), and supports a reasoned reviewer override. Its runContentChecks util RE-RUNS the deterministic checks over the reviewer's *edited* fields, so validation tracks the current draft, not the stale original — pair it with the document-editor to review-and-accept a content draft.", dataNeeds: 'A content type carrying a judge verdict + auto-checks (and the editable content fields to recheck).', source: { export: 'ValidationChecklist', from: '@startsimpli/ui' }, }, { id: 'review-scorecard', category: 'component', title: 'Review scorecard', description: "A controlled scorecard for a human reviewer's structured judgement of an AI-generated draft: an overall verdict segmented control (Approve / Revise / Reject, toned green/amber/red), one 1–5 score + note row per guardrail dimension (defaults to political-sensitivity, source-reliability, recency, tone-and-voice, accuracy — overridable), and an overall note. Bring-your-own-data + onChange (the app owns persistence); the captured verdict + scores drive a downstream AI revise loop. Pair it with the validation-checklist (machine review) and review-notes (section critique).", dataNeeds: 'A content type carrying a reviewer verdict + per-dimension scores/notes.', source: { export: 'ReviewScorecard', from: '@startsimpli/ui' }, }, { id: 'review-notes', category: 'component', title: 'Review notes', description: "A lightweight critique thread for an AI-generated draft, used per content section or overall: a list of reviewer notes (author, relative time, resolve action, resolved styling) plus a composer. Purely presentational + bring-your-own-data (onAdd / onResolve callbacks; no fetching). Pair it with the review-scorecard to capture section-level feedback that feeds the AI revise loop.", dataNeeds: 'A review-note / comment type (body + optional author, timestamp, section, resolved flag).', source: { export: 'ReviewNotes', from: '@startsimpli/ui' }, }, { id: 'chat', category: 'component', title: 'Chat thread', description: 'A threaded message view with a composer and attachments. Use only when the app genuinely models conversations (a messages type with a thread). Niche — do not add by default.', dataNeeds: 'A messages/thread type.', source: { export: 'ChatThread', from: '@startsimpli/ui' }, }, { id: 'session-list', category: 'view', title: 'Agent sessions list', description: "A presentational grid/table of agent-run sessions (name, status, branch, project) — cards or a project-grouped table. Use for a coding/agent workspace's session index. Status is injected per row (no per-row queries).", dataNeeds: 'A session/run type mapped to the SessionSummary view-model.', source: { export: 'SessionList', from: '@startsimpli/ui' }, }, { id: 'agent-terminal', category: 'component', title: 'Agent terminal', description: 'A live xterm.js terminal you drive imperatively (the parent owns the transport and pumps output in). Use for a session/agent surface that streams a PTY. Import styles from @startsimpli/ui/terminal/styles.', dataNeeds: 'A streaming agent/PTY transport (not schema data).', heavy: true, source: { export: 'Terminal', from: '@startsimpli/ui' }, }, { id: 'agent-session-console', category: 'component', title: 'Agent session console', description: 'The full live session surface: a terminal + a steer-the-agent conversation timeline + a diff tab, driven by @startsimpli/realtime over a websocket. Use for the session-detail page of an agent/coding workspace.', dataNeeds: 'A realtime agent-session websocket URL (not schema data).', heavy: true, source: { export: 'AgentSessionConsole', from: '@startsimpli/ui/session-console' }, }, ];