@powerhousedao/workflow 6.2.3-dev.11 → 6.2.3-dev.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/assets/{entry-4n9sWkpV.js → entry-4ObkElbc.js} +2 -2
- package/dist/browser/assets/{projection-entry-Bzn-Fath.js → projection-entry-DRGRQCSu.js} +8 -8
- package/dist/browser/{editor-DJX9NpD5.js → editor-D2hD_zy5.js} +2 -2
- package/dist/browser/{editor-DJX9NpD5.js.map → editor-D2hD_zy5.js.map} +1 -1
- package/dist/browser/{editor-Hh1cyIIW.js → editor-DPQptW3F.js} +2 -2
- package/dist/browser/{editor-Hh1cyIIW.js.map → editor-DPQptW3F.js.map} +1 -1
- package/dist/browser/{editor-BCxZ5i20.js → editor-tgTc0MrV.js} +2 -2
- package/dist/browser/{editor-BCxZ5i20.js.map → editor-tgTc0MrV.js.map} +1 -1
- package/dist/browser/editors/connection-editor/module.js +1 -1
- package/dist/browser/editors/workflow-editor/module.js +1 -1
- package/dist/browser/editors/workflow-studio/module.js +1 -1
- package/dist/browser/{use-runtime-url-DzYskFkw.js → use-runtime-url-CSz0PsWV.js} +2 -2
- package/dist/browser/{use-runtime-url-DzYskFkw.js.map → use-runtime-url-CSz0PsWV.js.map} +1 -1
- package/dist/node/{editor-CS8ttjKp.mjs → editor-D7WL8J_4.mjs} +2 -2
- package/dist/node/{editor-CS8ttjKp.mjs.map → editor-D7WL8J_4.mjs.map} +1 -1
- package/dist/node/{editor-DQUie3HQ.mjs → editor-gpF-ytd5.mjs} +2 -2
- package/dist/node/{editor-DQUie3HQ.mjs.map → editor-gpF-ytd5.mjs.map} +1 -1
- package/dist/node/{editor-DhgG3VOa.mjs → editor-sBw5dTYS.mjs} +2 -2
- package/dist/node/{editor-DhgG3VOa.mjs.map → editor-sBw5dTYS.mjs.map} +1 -1
- package/dist/node/editors/connection-editor/module.mjs +1 -1
- package/dist/node/editors/workflow-editor/module.mjs +1 -1
- package/dist/node/editors/workflow-studio/module.mjs +1 -1
- package/dist/node/{use-runtime-url-C_adivge.mjs → use-runtime-url-BOooH4kU.mjs} +2 -2
- package/dist/node/{use-runtime-url-C_adivge.mjs.map → use-runtime-url-BOooH4kU.mjs.map} +1 -1
- package/dist/types/document-models/workflow/v1/gen/schema/zod.d.ts +3 -3
- package/package.json +8 -8
|
@@ -2,7 +2,7 @@ import { E as packageFromConnectorId, f as fireWorkflow, g as rerunRun, l as fet
|
|
|
2
2
|
import { y as actions } from "./module-IA-Ay7ig.mjs";
|
|
3
3
|
import { y as actions$1 } from "./module-IRMgzJC1.mjs";
|
|
4
4
|
import { r as useWorkflowDocumentsInSelectedDrive } from "./workflow-fFvyypuu.mjs";
|
|
5
|
-
import { i as errorMessage, n as DocumentErrorBoundary, r as DocumentLoadError, t as useSyncWorkflowRuntimeUrl } from "./use-runtime-url-
|
|
5
|
+
import { i as errorMessage, n as DocumentErrorBoundary, r as DocumentLoadError, t as useSyncWorkflowRuntimeUrl } from "./use-runtime-url-BOooH4kU.mjs";
|
|
6
6
|
import { t as CONNECTION_STATUS_STYLES } from "./status-CDRcDUMS.mjs";
|
|
7
7
|
import { i as portRank, l as usePieceLogos, o as blockMeta } from "./ap-layout-DDOX4Vxv.mjs";
|
|
8
8
|
import { addDocument, setSelectedNode, showDeleteNodeModal, useDispatch, useDocumentSafe, useFileNodesInSelectedDrive, usePHToast, useSelectedDrive, useSelectedNode, useSetPHAppConfig } from "@powerhousedao/reactor-browser";
|
|
@@ -1547,4 +1547,4 @@ function Editor(props) {
|
|
|
1547
1547
|
//#endregion
|
|
1548
1548
|
export { Editor as default };
|
|
1549
1549
|
|
|
1550
|
-
//# sourceMappingURL=editor-
|
|
1550
|
+
//# sourceMappingURL=editor-gpF-ytd5.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-DQUie3HQ.mjs","names":["WORKFLOW_TYPE","CONNECTION_TYPE","ACTION","Stat","connectionActions","WORKFLOW_TYPE","WORKFLOW_TYPE","workflowActions"],"sources":["../../editors/workflow-studio/components/run-format.ts","../../editors/workflow-studio/components/EditorToolbar.tsx","../../editors/workflow-studio/components/connection-usage.ts","../../editors/workflow-studio/components/ConnectionView.tsx","../../editors/workflow-studio/components/RunsTable.tsx","../../editors/workflow-studio/components/RunsView.tsx","../../editors/workflow-studio/components/Sidebar.tsx","../../editors/workflow-studio/components/use-hash-selection.ts","../../editors/workflow-studio/components/useRuns.ts","../../editors/workflow-studio/components/step-outline.ts","../../editors/workflow-studio/components/WorkflowSteps.tsx","../../editors/workflow-studio/components/WorkflowHeader.tsx","../../editors/workflow-studio/components/WorkflowStudio.tsx","../../editors/workflow-studio/config.ts","../../editors/workflow-studio/editor.tsx"],"sourcesContent":["// Shared run vocabulary: one set of formatters and status colours so the\n// header, the table and the editor toolbar never disagree about a run.\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\n\nexport const RUN_STATUSES = [\"RUNNING\", \"SUCCEEDED\", \"FAILED\"] as const;\n\n// Status is the only place colour carries meaning in this view.\nexport const RUN_DOT: Record<string, string> = {\n SUCCEEDED: \"bg-green-500\",\n FAILED: \"bg-red-500\",\n RUNNING: \"bg-amber-400\",\n PARKED: \"bg-slate-400\",\n CANCELLED: \"bg-slate-400\",\n};\n\nexport const RUN_TEXT: Record<string, string> = {\n SUCCEEDED: \"text-green-700\",\n FAILED: \"text-red-700\",\n RUNNING: \"text-amber-700\",\n};\n\nexport const STEP_TEXT: Record<string, string> = {\n SUCCEEDED: \"text-green-600\",\n FAILED: \"text-red-600\",\n SKIPPED: \"text-slate-400\",\n REPLAYED: \"text-sky-600\",\n};\n\n// Sidebar dots: the same status vocabulary at glyph size.\nexport const WORKFLOW_STATUS_DOT: Record<string, string> = {\n ENABLED: \"bg-green-500\",\n DRAFT: \"bg-slate-300\",\n DISABLED: \"bg-amber-400\",\n ARCHIVED: \"bg-slate-200\",\n};\n\nexport const CONNECTION_STATUS_DOT: Record<string, string> = {\n OK: \"bg-green-500\",\n ERROR: \"bg-red-500\",\n REVOKED: \"bg-red-400\",\n UNCONFIGURED: \"bg-slate-300\",\n};\n\nexport const WORKFLOW_STATUS_STYLES: Record<string, string> = {\n ENABLED: \"bg-green-100 text-green-700\",\n DRAFT: \"bg-slate-100 text-slate-500\",\n DISABLED: \"bg-amber-100 text-amber-700\",\n ARCHIVED: \"bg-slate-200 text-slate-400\",\n};\n\nexport function formatDuration(\n startedAt: string,\n endedAt: string | null,\n): string {\n if (!endedAt) return \"…\";\n const ms = new Date(endedAt).getTime() - new Date(startedAt).getTime();\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;\n}\n\nexport function durationMs(\n startedAt: string,\n endedAt: string | null,\n): number | null {\n if (!endedAt) return null;\n return new Date(endedAt).getTime() - new Date(startedAt).getTime();\n}\n\nexport function formatWhen(startedAt: string): string {\n const diff = Date.now() - new Date(startedAt).getTime();\n if (diff < 60_000) return \"just now\";\n if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`;\n if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`;\n return new Date(startedAt).toLocaleDateString();\n}\n\nexport function formatAbsolute(iso: string): string {\n return new Date(iso).toLocaleString();\n}\n\n// A trigger kind reads better as a verb phrase than as its stored token.\nexport function formatTrigger(kind: string): string {\n return kind.replace(/[-_]/g, \" \").toLowerCase();\n}\n\nexport interface RunStats {\n total: number;\n succeeded: number;\n failed: number;\n running: number;\n lastRun?: RunRecord;\n // Null until at least one run has finished.\n successRate: number | null;\n}\n\nexport function runStats(runs: RunRecord[]): RunStats {\n const succeeded = runs.filter((run) => run.status === \"SUCCEEDED\").length;\n const failed = runs.filter((run) => run.status === \"FAILED\").length;\n const finished = succeeded + failed;\n return {\n total: runs.length,\n succeeded,\n failed,\n running: runs.filter((run) => run.status === \"RUNNING\").length,\n // Runs arrive newest first.\n lastRun: runs[0],\n successRate:\n finished === 0 ? null : Math.round((succeeded / finished) * 100),\n };\n}\n","// The bar above an open document editor: the way back to the journal, plus\n// the run facts an author wants while editing.\nimport { useDocumentSafe } from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport type { WorkflowDocument } from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport {\n formatAbsolute,\n formatDuration,\n formatWhen,\n RUN_DOT,\n RUN_TEXT,\n runStats,\n WORKFLOW_STATUS_STYLES,\n} from \"./run-format.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\nfunction Fact(props: { label: string; value: string; title?: string }) {\n return (\n <span className=\"flex items-baseline gap-1.5\" title={props.title}>\n <span className=\"text-[11px] text-slate-400\">{props.label}</span>\n <span className=\"text-xs tabular-nums text-slate-700\">{props.value}</span>\n </span>\n );\n}\n\nexport function EditorToolbar(props: {\n node?: FileNode;\n runs: RunRecord[] | null;\n onBack: () => void;\n}) {\n const { data: document } = useDocumentSafe(props.node?.id ?? null);\n const isWorkflow = document?.header.documentType === WORKFLOW_TYPE;\n const state = isWorkflow\n ? (document as WorkflowDocument).state.global\n : undefined;\n const stats = runStats(props.runs ?? []);\n const lastRun = isWorkflow ? stats.lastRun : undefined;\n\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-2 border-b border-solid border-slate-200 bg-slate-50 px-3 py-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 rounded border border-solid border-slate-300 bg-white px-2 py-1 text-xs font-medium text-slate-600 hover:border-slate-400 hover:text-slate-900\"\n onClick={props.onBack}\n >\n <span aria-hidden>←</span>\n {isWorkflow ? \"Back to runs\" : \"Back to overview\"}\n </button>\n <span className=\"min-w-0 truncate text-sm font-medium text-slate-800\">\n {state?.name || props.node?.name || \"Untitled\"}\n </span>\n {state ? (\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${WORKFLOW_STATUS_STYLES[state.status] ?? \"bg-slate-100 text-slate-500\"}`}\n >\n {state.status}\n </span>\n ) : null}\n {isWorkflow ? (\n <span className=\"ml-auto flex flex-wrap items-center gap-x-4 gap-y-1\">\n {lastRun ? (\n <span\n className=\"flex items-baseline gap-1.5\"\n title={formatAbsolute(lastRun.startedAt)}\n >\n <span className=\"text-[11px] text-slate-400\">Last run</span>\n <span className=\"flex items-center gap-1.5 text-xs\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[lastRun.status] ?? \"bg-slate-300\"}`}\n />\n <span className={RUN_TEXT[lastRun.status] ?? \"text-slate-700\"}>\n {formatWhen(lastRun.startedAt)}\n </span>\n <span className=\"tabular-nums text-slate-400\">\n {formatDuration(lastRun.startedAt, lastRun.endedAt)}\n </span>\n </span>\n </span>\n ) : (\n <Fact label=\"Last run\" value=\"Never run\" />\n )}\n {stats.successRate !== null ? (\n <Fact\n label=\"Success\"\n value={`${stats.successRate}%`}\n title={`${stats.succeeded} of ${stats.succeeded + stats.failed} finished runs succeeded`}\n />\n ) : null}\n <Fact label=\"Runs\" value={String(stats.total)} />\n </span>\n ) : null}\n </div>\n );\n}\n","// Which workflows depend on a connection, and where. Answers the question a\n// connection page has to answer before anyone dares revoke or delete it.\n\nexport interface UsageStep {\n id: string;\n key: string;\n name: string;\n blockType: string;\n}\n\nexport interface UsageWorkflow {\n id: string;\n name: string;\n status: string;\n trigger?: { blockType: string; connectionId?: string | null } | null;\n steps: readonly UsageStep[];\n}\n\nexport interface ConnectionUsage {\n workflow: UsageWorkflow;\n // The trigger binds this connection.\n trigger: boolean;\n steps: UsageStep[];\n}\n\nexport function connectionUsage(\n connectionId: string,\n workflows: readonly UsageWorkflow[],\n): ConnectionUsage[] {\n const usage: ConnectionUsage[] = [];\n for (const workflow of workflows) {\n const trigger = workflow.trigger?.connectionId === connectionId;\n const steps = workflow.steps.filter(\n (step) =>\n (step as { connectionId?: string | null }).connectionId ===\n connectionId,\n );\n if (trigger || steps.length > 0) usage.push({ workflow, trigger, steps });\n }\n return usage.sort((a, b) => a.workflow.name.localeCompare(b.workflow.name));\n}\n\n// An enabled workflow that depends on this connection breaks the moment it is\n// revoked, so the UI warns before that happens.\nexport function enabledDependents(usage: ConnectionUsage[]): number {\n return usage.filter((entry) => entry.workflow.status === \"ENABLED\").length;\n}\n","// A connection's view mode: what it connects to, how it is configured, and\n// which workflows would break if it went away.\nimport {\n showDeleteNodeModal,\n useDispatch,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport {\n actions as connectionActions,\n type ConnectionDocument,\n} from \"document-models/connection\";\nimport { useWorkflowDocumentsInSelectedDrive } from \"document-models/workflow\";\nimport type { ReactNode } from \"react\";\nimport { CONNECTION_STATUS_STYLES } from \"../../connection-editor/status.js\";\nimport { packageFromConnectorId } from \"../../connection-editor/piece-auth.js\";\nimport { DocumentLoadError } from \"../../shared/DocumentErrorBoundary.js\";\nimport {\n connectionUsage,\n enabledDependents,\n type UsageWorkflow,\n} from \"./connection-usage.js\";\nimport { formatAbsolute, WORKFLOW_STATUS_DOT } from \"./run-format.js\";\n\nconst CONNECTION_TYPE = \"powerhouse/connection\";\n\nconst ACTION =\n \"rounded border border-solid border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 hover:border-slate-400 hover:bg-slate-50\";\n\nfunction Stat(props: { label: string; children: ReactNode }) {\n return (\n <div className=\"min-w-0 grow border-l border-solid border-slate-200 px-3 py-2 first:border-l-0 first:pl-0\">\n <div className=\"text-[11px] text-slate-400\">{props.label}</div>\n <div className=\"truncate text-xs text-slate-800\">{props.children}</div>\n </div>\n );\n}\n\nfunction configEntries(config: unknown): [string, string][] {\n if (!config || typeof config !== \"object\" || Array.isArray(config)) return [];\n return Object.entries(config as Record<string, unknown>).map(\n ([key, value]) => [\n key,\n typeof value === \"string\" ? value : JSON.stringify(value),\n ],\n );\n}\n\nexport function ConnectionView(props: {\n node: FileNode;\n onEdit: () => void;\n onOpenWorkflow: (workflowId: string) => void;\n}) {\n const connectionId = props.node.id;\n const { data: document, error, reload } = useDocumentSafe(connectionId);\n const [, dispatch] = useDispatch(document);\n const workflows = useWorkflowDocumentsInSelectedDrive();\n\n if (error !== undefined) {\n return (\n <DocumentLoadError\n title=\"This connection could not be loaded\"\n documentId={connectionId}\n error={error}\n onRetry={() => {\n void reload();\n }}\n />\n );\n }\n if (document?.header.documentType !== CONNECTION_TYPE) return null;\n\n const state = (document as ConnectionDocument).state.global;\n const revoked = state.status === \"REVOKED\";\n const packageName = packageFromConnectorId(state.connectorId);\n const usage = connectionUsage(\n connectionId,\n (workflows ?? []).map(\n (workflow): UsageWorkflow => ({\n id: workflow.header.id,\n name: workflow.state.global.name || workflow.header.name || \"Untitled\",\n status: workflow.state.global.status,\n trigger: workflow.state.global.trigger,\n steps: workflow.state.global.steps,\n }),\n ),\n );\n const atRisk = enabledDependents(usage);\n const config = configEntries(state.config);\n\n const setStatus = (status: \"OK\" | \"REVOKED\") =>\n dispatch(\n connectionActions.recordCheckResult({\n status,\n checkedAt: new Date().toISOString(),\n }),\n );\n\n return (\n <div className=\"mx-auto w-full max-w-5xl p-6\">\n <header className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"min-w-0 truncate text-base font-semibold text-slate-800\">\n {state.name || props.node.name || \"Untitled connection\"}\n </h2>\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${CONNECTION_STATUS_STYLES[state.status]}`}\n >\n {state.status}\n </span>\n <span className=\"grow\" />\n <button type=\"button\" className={ACTION} onClick={props.onEdit}>\n Edit connection\n </button>\n <button\n type=\"button\"\n className={ACTION}\n onClick={() => setStatus(revoked ? \"OK\" : \"REVOKED\")}\n >\n {revoked ? \"Reactivate\" : \"Revoke\"}\n </button>\n <button\n type=\"button\"\n className=\"rounded border border-solid border-red-200 bg-white px-2.5 py-1 text-xs font-medium text-red-600 hover:border-red-300 hover:bg-red-50\"\n onClick={() => showDeleteNodeModal(props.node)}\n >\n Delete\n </button>\n </div>\n <div className=\"mt-3 flex flex-wrap items-stretch rounded-md border border-solid border-slate-200 bg-white px-3\">\n <Stat label=\"Connector\">\n {packageName || <span className=\"text-slate-400\">None picked</span>}\n </Stat>\n <Stat label=\"Auth\">{state.authType}</Stat>\n <Stat label=\"Account\">\n {state.accountLabel ?? <span className=\"text-slate-400\">—</span>}\n </Stat>\n <Stat label=\"Last checked\">\n {state.lastCheckedAt ? (\n formatAbsolute(state.lastCheckedAt)\n ) : (\n <span className=\"text-slate-400\">Never</span>\n )}\n </Stat>\n <Stat label=\"Secrets\">\n <span className=\"tabular-nums\">{state.secretRefs.length}</span>\n </Stat>\n <Stat label=\"Used by\">\n <span className=\"tabular-nums\">\n {usage.length}\n {atRisk > 0 ? (\n <span className=\"text-slate-400\"> · {atRisk} enabled</span>\n ) : null}\n </span>\n </Stat>\n </div>\n </header>\n\n {state.lastError ? (\n <p className=\"mb-4 rounded bg-red-50 px-3 py-2 text-xs text-red-600\">\n {state.lastError}\n </p>\n ) : null}\n\n <section className=\"mb-4 rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <h3 className=\"mb-2 text-[11px] text-slate-400\">Used by</h3>\n {usage.length === 0 ? (\n <p className=\"text-xs text-slate-500\">\n No workflow uses this connection yet. Bind it to a step in a\n workflow's editor.\n </p>\n ) : (\n <ul className=\"flex flex-col gap-1\">\n {usage.map((entry) => (\n <li key={entry.workflow.id}>\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-2 rounded px-1 py-1 text-left hover:bg-slate-50\"\n onClick={() => props.onOpenWorkflow(entry.workflow.id)}\n >\n <span\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${WORKFLOW_STATUS_DOT[entry.workflow.status] ?? \"bg-slate-300\"}`}\n title={entry.workflow.status}\n />\n <span className=\"shrink-0 text-xs font-medium text-slate-700\">\n {entry.workflow.name}\n </span>\n <span className=\"truncate text-[11px] text-slate-400\">\n {entry.trigger ? \"trigger\" : null}\n {entry.trigger && entry.steps.length > 0 ? \" · \" : null}\n {entry.steps.map((step) => step.key).join(\", \")}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </section>\n\n <section className=\"rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <h3 className=\"mb-2 text-[11px] text-slate-400\">Configuration</h3>\n {config.length === 0 && state.secretRefs.length === 0 ? (\n <p className=\"text-xs text-slate-500\">\n Nothing configured yet.{\" \"}\n <button\n type=\"button\"\n className=\"underline hover:text-slate-800\"\n onClick={props.onEdit}\n >\n Open the editor\n </button>{\" \"}\n to fill it in.\n </p>\n ) : (\n <dl className=\"flex flex-col gap-1\">\n {config.map(([key, value]) => (\n <div key={key} className=\"flex gap-2 text-xs\">\n <dt className=\"w-40 shrink-0 truncate text-slate-500\">{key}</dt>\n <dd className=\"min-w-0 truncate text-slate-800\">{value}</dd>\n </div>\n ))}\n {state.secretRefs.map((ref) => (\n <div key={ref.id} className=\"flex gap-2 text-xs\">\n <dt className=\"w-40 shrink-0 truncate text-slate-500\">\n {ref.name}\n </dt>\n <dd className=\"text-slate-400\">\n stored secret · never displayed\n </dd>\n </div>\n ))}\n </dl>\n )}\n </section>\n </div>\n );\n}\n","// The run journal as a filterable table. Rows expand in place to their step\n// executions, so drilling into a failure never leaves the list.\nimport { Fragment, useMemo, useState } from \"react\";\nimport {\n rerunRun,\n type RunRecord,\n type RunStepRecord,\n} from \"../../workflow-editor/runtime-api.js\";\nimport { blockMeta } from \"../../workflow-editor/ui/block-meta.js\";\nimport {\n formatAbsolute,\n formatDuration,\n formatTrigger,\n formatWhen,\n durationMs,\n RUN_DOT,\n RUN_STATUSES,\n RUN_TEXT,\n STEP_TEXT,\n} from \"./run-format.js\";\n\ntype StatusFilter = \"ALL\" | (typeof RUN_STATUSES)[number];\ntype SortKey = \"startedAt\" | \"duration\";\n\nconst CONTROL =\n \"rounded border border-solid border-slate-300 bg-white px-2 py-1 text-xs text-slate-700 focus:border-slate-400 focus:outline-none\";\n\nfunction stringify(value: unknown): string {\n if (value === undefined) return \"\";\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value as string);\n }\n}\n\nfunction StepRow(props: { step: RunStepRecord }) {\n const { step } = props;\n const meta = blockMeta(step.blockType);\n const [open, setOpen] = useState(false);\n return (\n <div className=\"border-t border-solid border-slate-100 first:border-t-0\">\n <button\n type=\"button\"\n aria-expanded={open}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left hover:bg-white focus-visible:bg-white focus-visible:outline-none\"\n onClick={() => setOpen((value) => !value)}\n >\n <span\n className={`w-16 shrink-0 text-[11px] font-semibold ${STEP_TEXT[step.status] ?? \"text-slate-500\"}`}\n >\n {step.status}\n </span>\n <span className=\"shrink-0 text-xs font-medium text-slate-700\">\n {step.stepKey}\n </span>\n <span className=\"truncate text-xs text-slate-400\">\n {meta.displayName} · {meta.subtitle}\n </span>\n {step.port ? (\n <span className=\"ml-auto shrink-0 rounded bg-slate-100 px-1 text-[10px] text-slate-500\">\n → {step.port}\n </span>\n ) : null}\n </button>\n {open ? (\n <div className=\"space-y-1 px-3 pb-2\">\n {step.error ? (\n <pre className=\"overflow-x-auto rounded bg-red-50 p-2 text-[11px] text-red-600\">\n {step.error}\n </pre>\n ) : null}\n <details>\n <summary className=\"cursor-pointer text-[11px] text-slate-400\">\n input\n </summary>\n <pre className=\"max-h-48 overflow-auto rounded bg-white p-2 text-[11px] text-slate-600\">\n {stringify(step.input)}\n </pre>\n </details>\n <details>\n <summary className=\"cursor-pointer text-[11px] text-slate-400\">\n output\n </summary>\n <pre className=\"max-h-48 overflow-auto rounded bg-white p-2 text-[11px] text-slate-600\">\n {stringify(step.output)}\n </pre>\n </details>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction RunDetail(props: { run: RunRecord; onChanged: () => void }) {\n const { run } = props;\n const [rerunning, setRerunning] = useState(false);\n const [rerunError, setRerunError] = useState<string | null>(null);\n return (\n <div className=\"space-y-2 bg-slate-50 px-4 py-3\">\n {run.error ? (\n <p className=\"rounded bg-red-50 px-2 py-1 text-xs text-red-600\">\n {run.error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-[11px] text-slate-500\">\n <span>\n run <span className=\"font-mono\">{run.id.slice(0, 8)}</span>\n </span>\n <span>started {formatAbsolute(run.startedAt)}</span>\n {run.rerunOf ? (\n <span>\n resumes <span className=\"font-mono\">{run.rerunOf.slice(0, 8)}</span>\n </span>\n ) : null}\n {run.status === \"FAILED\" ? (\n <button\n type=\"button\"\n disabled={rerunning}\n className=\"rounded border border-solid border-slate-300 bg-white px-2 py-1 font-medium text-slate-600 hover:border-slate-400 disabled:opacity-50\"\n onClick={() => {\n setRerunning(true);\n setRerunError(null);\n rerunRun(run.id)\n .then((result) => setRerunError(result.error))\n .catch((error: unknown) =>\n setRerunError(\n error instanceof Error ? error.message : String(error),\n ),\n )\n .finally(() => {\n setRerunning(false);\n props.onChanged();\n });\n }}\n >\n {rerunning ? \"Rerunning…\" : \"↻ Rerun from failure\"}\n </button>\n ) : null}\n {rerunError ? <span className=\"text-red-600\">{rerunError}</span> : null}\n </div>\n {run.steps.length === 0 ? (\n <p className=\"text-xs text-slate-400\">This run recorded no steps.</p>\n ) : (\n <div className=\"rounded border border-solid border-slate-200 bg-slate-50\">\n {run.steps.map((step) => (\n <StepRow key={step.stepId + step.stepKey} step={step} />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction SortHeader(props: {\n label: string;\n active: boolean;\n descending: boolean;\n onClick: () => void;\n className?: string;\n}) {\n return (\n <th scope=\"col\" className={props.className}>\n <button\n type=\"button\"\n className={`flex items-center gap-1 hover:text-slate-700 ${props.active ? \"text-slate-700\" : \"\"}`}\n onClick={props.onClick}\n >\n {props.label}\n <span aria-hidden className={props.active ? \"\" : \"opacity-0\"}>\n {props.descending ? \"↓\" : \"↑\"}\n </span>\n </button>\n </th>\n );\n}\n\nexport function RunsTable(props: {\n runs: RunRecord[];\n showWorkflow: boolean;\n onChanged: () => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const [status, setStatus] = useState<StatusFilter>(\"ALL\");\n const [workflow, setWorkflow] = useState(\"ALL\");\n const [trigger, setTrigger] = useState(\"ALL\");\n const [sort, setSort] = useState<SortKey>(\"startedAt\");\n const [descending, setDescending] = useState(true);\n const [expanded, setExpanded] = useState<string | null>(null);\n\n const workflowOptions = useMemo(\n () =>\n [...new Map(props.runs.map((run) => [run.workflowId, run.workflowName]))]\n .map(([id, name]) => ({ id, name }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n [props.runs],\n );\n const triggerOptions = useMemo(\n () => [...new Set(props.runs.map((run) => run.triggerKind))].sort(),\n [props.runs],\n );\n\n // Everything except the status filter, so the status counts describe what\n // picking each one would actually show.\n const scoped = useMemo(() => {\n const needle = query.trim().toLowerCase();\n return props.runs.filter((run) => {\n if (workflow !== \"ALL\" && run.workflowId !== workflow) return false;\n if (trigger !== \"ALL\" && run.triggerKind !== trigger) return false;\n if (!needle) return true;\n return (\n run.workflowName.toLowerCase().includes(needle) ||\n run.id.toLowerCase().includes(needle) ||\n (run.error?.toLowerCase().includes(needle) ?? false) ||\n run.steps.some((step) => step.stepKey.toLowerCase().includes(needle))\n );\n });\n }, [props.runs, query, workflow, trigger]);\n\n const counts = useMemo(\n () => ({\n ALL: scoped.length,\n RUNNING: scoped.filter((run) => run.status === \"RUNNING\").length,\n SUCCEEDED: scoped.filter((run) => run.status === \"SUCCEEDED\").length,\n FAILED: scoped.filter((run) => run.status === \"FAILED\").length,\n }),\n [scoped],\n );\n\n const visible = useMemo(() => {\n const rows = scoped.filter(\n (run) => status === \"ALL\" || run.status === status,\n );\n const direction = descending ? -1 : 1;\n return [...rows].sort((a, b) => {\n if (sort === \"duration\") {\n // An unfinished run has no duration yet; keep those together.\n const left = durationMs(a.startedAt, a.endedAt) ?? Infinity;\n const right = durationMs(b.startedAt, b.endedAt) ?? Infinity;\n return (left - right) * direction;\n }\n return (\n (new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime()) *\n direction\n );\n });\n }, [scoped, status, sort, descending]);\n\n const filtered = query.trim() || workflow !== \"ALL\" || trigger !== \"ALL\";\n const sortBy = (key: SortKey) => {\n if (key === sort) {\n setDescending((value) => !value);\n return;\n }\n setSort(key);\n setDescending(true);\n };\n\n return (\n <div>\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <div className=\"flex overflow-hidden rounded border border-solid border-slate-300\">\n {([\"ALL\", ...RUN_STATUSES] as StatusFilter[]).map((option) => (\n <button\n key={option}\n type=\"button\"\n aria-pressed={status === option}\n className={`border-r border-solid border-slate-200 px-2.5 py-1 text-xs last:border-r-0 ${\n status === option\n ? \"bg-slate-800 text-white\"\n : \"bg-white text-slate-600 hover:bg-slate-50\"\n }`}\n onClick={() => setStatus(option)}\n >\n {option === \"ALL\"\n ? \"All\"\n : option.charAt(0) + option.slice(1).toLowerCase()}\n <span className=\"ml-1.5 tabular-nums opacity-60\">\n {counts[option]}\n </span>\n </button>\n ))}\n </div>\n <input\n type=\"search\"\n className={`${CONTROL} w-44`}\n placeholder=\"Search runs\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n />\n {props.showWorkflow && workflowOptions.length > 1 ? (\n <select\n className={CONTROL}\n value={workflow}\n onChange={(event) => setWorkflow(event.target.value)}\n >\n <option value=\"ALL\">Every workflow</option>\n {workflowOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n ) : null}\n {triggerOptions.length > 1 ? (\n <select\n className={CONTROL}\n value={trigger}\n onChange={(event) => setTrigger(event.target.value)}\n >\n <option value=\"ALL\">Every trigger</option>\n {triggerOptions.map((option) => (\n <option key={option} value={option}>\n {formatTrigger(option)}\n </option>\n ))}\n </select>\n ) : null}\n {filtered ? (\n <button\n type=\"button\"\n className=\"text-xs text-slate-500 underline hover:text-slate-800\"\n onClick={() => {\n setQuery(\"\");\n setWorkflow(\"ALL\");\n setTrigger(\"ALL\");\n }}\n >\n Clear filters\n </button>\n ) : null}\n <span className=\"ml-auto text-[11px] tabular-nums text-slate-400\">\n {visible.length} of {props.runs.length} runs\n </span>\n </div>\n\n <div className=\"overflow-x-auto rounded-md border border-solid border-slate-200 bg-white\">\n <table className=\"w-full border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-solid border-slate-200 text-[11px] font-medium text-slate-400\">\n <th scope=\"col\" className=\"px-3 py-2\">\n Status\n </th>\n {props.showWorkflow ? (\n <th scope=\"col\" className=\"px-3 py-2\">\n Workflow\n </th>\n ) : null}\n <th scope=\"col\" className=\"px-3 py-2\">\n Trigger\n </th>\n <SortHeader\n label=\"Started\"\n className=\"px-3 py-2\"\n active={sort === \"startedAt\"}\n descending={descending}\n onClick={() => sortBy(\"startedAt\")}\n />\n <SortHeader\n label=\"Duration\"\n className=\"px-3 py-2\"\n active={sort === \"duration\"}\n descending={descending}\n onClick={() => sortBy(\"duration\")}\n />\n <th scope=\"col\" className=\"px-3 py-2\">\n Steps\n </th>\n <th scope=\"col\" className=\"w-8 px-3 py-2\">\n <span className=\"sr-only\">Details</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {visible.length === 0 ? (\n <tr>\n <td\n colSpan={props.showWorkflow ? 7 : 6}\n className=\"px-3 py-6 text-center text-sm text-slate-400\"\n >\n No runs match these filters.\n </td>\n </tr>\n ) : (\n visible.map((run) => {\n const open = expanded === run.id;\n return (\n <Fragment key={run.id}>\n <tr\n className={`cursor-pointer border-b border-solid border-slate-100 text-sm ${\n open ? \"bg-slate-50\" : \"hover:bg-slate-50\"\n }`}\n onClick={() => setExpanded(open ? null : run.id)}\n >\n <td className=\"px-3 py-2\">\n <span className=\"flex items-center gap-2\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[run.status] ?? \"bg-slate-300\"}`}\n />\n <span\n className={`text-xs font-medium ${RUN_TEXT[run.status] ?? \"text-slate-500\"}`}\n >\n {run.status.charAt(0) +\n run.status.slice(1).toLowerCase()}\n </span>\n </span>\n </td>\n {props.showWorkflow ? (\n <td className=\"max-w-48 truncate px-3 py-2 text-slate-800\">\n {run.workflowName}\n </td>\n ) : null}\n <td className=\"px-3 py-2 text-xs text-slate-500\">\n {formatTrigger(run.triggerKind)}\n <span className=\"ml-1 text-slate-300\">\n v{run.workflowVersion}\n </span>\n </td>\n <td\n className=\"whitespace-nowrap px-3 py-2 text-xs tabular-nums text-slate-500\"\n title={formatAbsolute(run.startedAt)}\n >\n {formatWhen(run.startedAt)}\n </td>\n <td className=\"whitespace-nowrap px-3 py-2 text-xs tabular-nums text-slate-500\">\n {formatDuration(run.startedAt, run.endedAt)}\n </td>\n <td className=\"px-3 py-2 text-xs tabular-nums text-slate-500\">\n {run.steps.length}\n </td>\n <td className=\"px-3 py-2\">\n <button\n type=\"button\"\n aria-expanded={open}\n aria-label={`${open ? \"Hide\" : \"Show\"} steps of the run started ${formatAbsolute(run.startedAt)}`}\n className=\"rounded px-1 text-xs text-slate-400 hover:text-slate-700\"\n onClick={(event) => {\n event.stopPropagation();\n setExpanded(open ? null : run.id);\n }}\n >\n <span aria-hidden>{open ? \"▾\" : \"▸\"}</span>\n </button>\n </td>\n </tr>\n {open ? (\n <tr>\n <td\n colSpan={props.showWorkflow ? 7 : 6}\n className=\"border-b border-solid border-slate-200 p-0\"\n >\n <RunDetail run={run} onChanged={props.onChanged} />\n </td>\n </tr>\n ) : null}\n </Fragment>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n","// The runs pane: what scope is being shown, how to fire it, and the journal.\n// The run feed is owned by the studio so the header shares these rows.\nimport { useState } from \"react\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { RunsTable } from \"./RunsTable.js\";\n\nexport function RunsView(props: {\n title: string;\n runs: RunRecord[] | null;\n error: string | null;\n reload: () => void;\n showWorkflow: boolean;\n // Present only for manual-trigger workflows.\n onFire?: () => Promise<string | null>;\n}) {\n const [firing, setFiring] = useState(false);\n const [fireError, setFireError] = useState<string | null>(null);\n const { runs } = props;\n\n return (\n <div className=\"w-full\">\n <div className=\"mb-3 flex items-center gap-3\">\n <h2 className=\"text-base font-semibold text-slate-800\">\n {props.title}\n </h2>\n <span className=\"grow\" />\n {props.onFire ? (\n <button\n type=\"button\"\n disabled={firing}\n className=\"rounded bg-blue-600 px-3 py-1.5 text-xs font-semibold text-white hover:bg-blue-700 disabled:opacity-50\"\n onClick={() => {\n setFiring(true);\n setFireError(null);\n props.onFire!()\n .then((fireResultError) => setFireError(fireResultError))\n .catch((fireCallError: unknown) =>\n setFireError(\n fireCallError instanceof Error\n ? fireCallError.message\n : String(fireCallError),\n ),\n )\n .finally(() => {\n setFiring(false);\n props.reload();\n });\n }}\n >\n {firing ? \"Running…\" : \"▶ Run workflow\"}\n </button>\n ) : null}\n </div>\n {fireError ? (\n <p className=\"mb-2 rounded bg-red-50 px-3 py-2 text-xs text-red-600\">\n {fireError}\n </p>\n ) : null}\n {props.error ? (\n <p className=\"rounded bg-amber-50 px-3 py-2 text-xs text-amber-700\">\n The workflow runtime is unreachable, so runs cannot be listed:{\" \"}\n {props.error}\n </p>\n ) : runs === null ? (\n <p className=\"text-sm text-slate-400\">Loading runs…</p>\n ) : runs.length === 0 ? (\n <p className=\"rounded-md border border-solid border-slate-200 bg-white px-3 py-6 text-center text-sm text-slate-400\">\n No runs yet\n {props.onFire ? \" — run the workflow to record the first one\" : \"\"}.\n </p>\n ) : (\n <RunsTable\n runs={runs}\n showWorkflow={props.showWorkflow}\n onChanged={props.reload}\n />\n )}\n </div>\n );\n}\n","// Studio navigation: the drive-wide journal, then the drive's workflows and\n// connections. Each row carries its document's status as a dot.\nimport {\n showDeleteNodeModal,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport { useEffect, type ReactNode } from \"react\";\nimport { errorMessage } from \"../../shared/DocumentErrorBoundary.js\";\nimport { CONNECTION_STATUS_DOT, WORKFLOW_STATUS_DOT } from \"./run-format.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\n// The drive node name goes stale after renames; the document state is the\n// source of truth for both workflow and connection names.\nfunction documentName(document: unknown, fallback: string): string {\n const state = (document as { state?: { global?: { name?: string } } } | null)\n ?.state?.global;\n return state?.name || fallback || \"(unnamed)\";\n}\n\nfunction documentStatus(document: unknown): string | undefined {\n const state = (\n document as { state?: { global?: { status?: string } } } | null\n )?.state?.global;\n return state?.status;\n}\n\nfunction Row(props: {\n active: boolean;\n onClick: () => void;\n children: ReactNode;\n trailing?: ReactNode;\n}) {\n return (\n <div\n className={`group mx-2 flex items-center rounded ${\n props.active ? \"bg-white ring-1 ring-slate-200\" : \"hover:bg-slate-100\"\n }`}\n >\n <button\n type=\"button\"\n aria-current={props.active ? \"true\" : undefined}\n className={`flex min-w-0 grow items-center gap-2 px-2 py-1.5 text-left text-sm ${\n props.active ? \"text-slate-900\" : \"text-slate-600\"\n }`}\n onClick={props.onClick}\n >\n {props.children}\n </button>\n {props.trailing}\n </div>\n );\n}\n\nconst ROW_ACTION =\n \"shrink-0 rounded px-1 py-0.5 text-xs text-slate-400 opacity-0 hover:bg-slate-200 hover:text-slate-700 focus-visible:opacity-100 group-hover:opacity-100\";\n\nconst DELETE_ACTION = `${ROW_ACTION} hover:bg-red-100 hover:text-red-600`;\n\nfunction DeleteButton(props: { node: FileNode; label: string }) {\n return (\n <button\n type=\"button\"\n title=\"Delete\"\n aria-label={`Delete ${props.label}`}\n className={DELETE_ACTION}\n onClick={() => showDeleteNodeModal(props.node)}\n >\n <span aria-hidden>🗑</span>\n </button>\n );\n}\n\n// A node can outlive its document (deleted, or unreadable history), so one\n// broken node degrades to its drive name plus a warning marker.\nfunction NodeRow(props: {\n node: FileNode;\n active: boolean;\n onOpen: () => void;\n onEdit?: () => void;\n}) {\n const { node } = props;\n const { data: document, error } = useDocumentSafe(node.id);\n useEffect(() => {\n if (error !== undefined) {\n console.error(`Failed to load document ${node.id}:`, error);\n }\n }, [error, node.id]);\n\n if (error !== undefined) {\n return (\n <Row\n active={props.active}\n onClick={props.onOpen}\n trailing={\n <span className=\"mr-1.5 flex shrink-0 items-center\">\n <DeleteButton node={node} label={node.name || node.id} />\n </span>\n }\n >\n <span\n className=\"shrink-0 text-xs text-red-600\"\n title={`Could not load ${node.id}: ${errorMessage(error)}`}\n aria-hidden\n >\n ⚠\n </span>\n <span className=\"min-w-0 truncate text-red-600\">\n {node.name || \"(unnamed)\"}\n </span>\n </Row>\n );\n }\n\n const status = documentStatus(document);\n const dots =\n node.documentType === WORKFLOW_TYPE\n ? WORKFLOW_STATUS_DOT\n : CONNECTION_STATUS_DOT;\n return (\n <Row\n active={props.active}\n onClick={props.onOpen}\n trailing={\n <span className=\"mr-1.5 flex shrink-0 items-center\">\n {props.onEdit ? (\n <button\n type=\"button\"\n title=\"Open in editor\"\n aria-label={`Open ${documentName(document, node.name)} in the editor`}\n className={ROW_ACTION}\n onClick={props.onEdit}\n >\n <span aria-hidden>✎</span>\n </button>\n ) : null}\n <DeleteButton node={node} label={documentName(document, node.name)} />\n </span>\n }\n >\n <span\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${\n status ? (dots[status] ?? \"bg-slate-300\") : \"bg-slate-200\"\n }`}\n title={status}\n />\n <span className=\"min-w-0 truncate\">\n {documentName(document, node.name)}\n </span>\n </Row>\n );\n}\n\nfunction Section(props: {\n title: string;\n addLabel: string;\n empty: string;\n nodes: FileNode[];\n activeId?: string | null;\n onOpen: (node: FileNode) => void;\n onEdit?: (node: FileNode) => void;\n onCreate: () => void;\n creating: boolean;\n}) {\n return (\n <div className=\"mt-2\">\n {/* A banded header, so the two groups read as separate lists. */}\n <div className=\"mb-1.5 flex items-center justify-between border-y border-solid border-slate-200 bg-slate-100 px-4 py-1.5\">\n <span className=\"text-[11px] font-bold uppercase tracking-wider text-slate-600\">\n {props.title}\n </span>\n <button\n type=\"button\"\n disabled={props.creating}\n className=\"flex h-5 w-5 items-center justify-center rounded border border-solid border-transparent text-sm leading-none text-slate-500 hover:border-slate-300 hover:bg-white hover:text-slate-800 disabled:opacity-50\"\n title={props.addLabel}\n aria-label={props.addLabel}\n onClick={props.onCreate}\n >\n <span aria-hidden>+</span>\n </button>\n </div>\n {props.nodes.length === 0 ? (\n <p className=\"px-4 py-1 text-xs text-slate-400\">{props.empty}</p>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n {props.nodes.map((node) => (\n <NodeRow\n key={node.id}\n node={node}\n active={props.activeId === node.id}\n onOpen={() => props.onOpen(node)}\n onEdit={props.onEdit ? () => props.onEdit!(node) : undefined}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function Sidebar(props: {\n workflows: FileNode[];\n connections: FileNode[];\n activeId?: string | null;\n allRunsActive: boolean;\n creating: boolean;\n onShowAllRuns: () => void;\n onOpenWorkflow: (node: FileNode) => void;\n onEditWorkflow: (node: FileNode) => void;\n onOpenConnection: (node: FileNode) => void;\n onEditConnection: (node: FileNode) => void;\n onCreateWorkflow: () => void;\n onCreateConnection: () => void;\n}) {\n return (\n <aside className=\"w-60 shrink-0 overflow-y-auto border-r border-solid border-slate-200 bg-slate-50 py-2\">\n <Row active={props.allRunsActive} onClick={props.onShowAllRuns}>\n <span aria-hidden className=\"shrink-0 text-xs text-slate-400\">\n ☰\n </span>\n <span className=\"font-medium\">All runs</span>\n </Row>\n <Section\n title=\"Workflows\"\n addLabel=\"New workflow\"\n empty=\"No workflows yet. Use + to add one.\"\n nodes={props.workflows}\n activeId={props.activeId}\n onOpen={props.onOpenWorkflow}\n onEdit={props.onEditWorkflow}\n onCreate={props.onCreateWorkflow}\n creating={props.creating}\n />\n <Section\n title=\"Connections\"\n addLabel=\"New connection\"\n empty=\"No connections yet. Use + to add one.\"\n nodes={props.connections}\n activeId={props.activeId}\n onOpen={props.onOpenConnection}\n onEdit={props.onEditConnection}\n onCreate={props.onCreateConnection}\n creating={props.creating}\n />\n </aside>\n );\n}\n","// Connect owns the path (`/d/<drive>/<node>`) for an open editor; the studio's\n// sidebar selection lives in the hash, so it survives a refresh.\nimport { useCallback, useEffect, useState } from \"react\";\n\nfunction readHash(): string | undefined {\n return window.location.hash.replace(/^#/, \"\") || undefined;\n}\n\nexport function useHashSelection(): [\n string | undefined,\n (id?: string) => void,\n] {\n const [selected, setSelected] = useState<string | undefined>(readHash);\n\n useEffect(() => {\n // Covers back/forward and a hand-edited URL.\n const sync = () => setSelected(readHash());\n window.addEventListener(\"hashchange\", sync);\n window.addEventListener(\"popstate\", sync);\n return () => {\n window.removeEventListener(\"hashchange\", sync);\n window.removeEventListener(\"popstate\", sync);\n };\n }, []);\n\n const select = useCallback((id?: string) => {\n setSelected(id);\n // Replaced, not pushed: Connect pushes a path entry on the same click, and\n // two history entries per click breaks the back button.\n const url = new URL(window.location.href);\n url.hash = id ?? \"\";\n window.history.replaceState(null, \"\", url);\n }, []);\n\n return [selected, select];\n}\n","// One polling subscription to the run journal per studio pane. The header,\n// the table and the editor toolbar all read from it, so they stay in step.\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n fetchRuns,\n type RunRecord,\n type RunsScope,\n} from \"../../workflow-editor/runtime-api.js\";\n\nconst POLL_MS = 5000;\n\nexport interface RunsFeed {\n runs: RunRecord[] | null;\n error: string | null;\n reload: () => void;\n}\n\nexport function useRuns(scope: RunsScope): RunsFeed {\n const { workflowId, driveId, limit } = scope;\n const [runs, setRuns] = useState<RunRecord[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n // Lets reload() run against the current scope without re-subscribing.\n const load = useRef<() => void>(() => undefined);\n\n useEffect(() => {\n let cancelled = false;\n const run = () => {\n fetchRuns({ workflowId, driveId, limit }).then(\n (result) => {\n if (cancelled) return;\n setRuns(result);\n setError(null);\n },\n (loadError: unknown) => {\n if (cancelled) return;\n setError(\n loadError instanceof Error ? loadError.message : String(loadError),\n );\n },\n );\n };\n load.current = run;\n // A scope change makes the previous rows the wrong rows.\n setRuns(null);\n run();\n const timer = setInterval(run, POLL_MS);\n return () => {\n cancelled = true;\n clearInterval(timer);\n };\n }, [workflowId, driveId, limit]);\n\n const reload = useCallback(() => load.current(), []);\n return { runs, error, reload };\n}\n","// Flattens a workflow's graph into the order a run walks it, so the studio\n// can show the shape of a workflow without drawing the canvas.\nimport { portRank } from \"../../workflow-editor/ui/ap-layout.js\";\n\nexport interface OutlineStep {\n id: string;\n key: string;\n name: string;\n blockType: string;\n}\n\nexport interface OutlineEdge {\n from: string;\n to: string;\n port: string;\n}\n\nexport interface OutlineRow {\n step: OutlineStep;\n // The port that led here; null on the entry step and on \"next\".\n port: string | null;\n}\n\nexport interface StepOutline {\n rows: OutlineRow[];\n // Authored but unreachable from the trigger, so no run ever executes them.\n orphans: OutlineStep[];\n}\n\nexport function stepOutline(args: {\n triggerId?: string | null;\n steps: readonly OutlineStep[];\n edges: readonly OutlineEdge[];\n}): StepOutline {\n const stepById = new Map(args.steps.map((step) => [step.id, step]));\n const outgoing = new Map<string, OutlineEdge[]>();\n for (const edge of args.edges) {\n if (!stepById.has(edge.to)) continue;\n const list = outgoing.get(edge.from) ?? [];\n list.push(edge);\n outgoing.set(edge.from, list);\n }\n for (const list of outgoing.values()) {\n list.sort((a, b) => portRank(a.port) - portRank(b.port));\n }\n\n const rows: OutlineRow[] = [];\n const seen = new Set<string>();\n // Depth-first so a branch reads as a continuous path, as it runs.\n const walk = (fromId: string, port: string | null) => {\n const step = stepById.get(fromId);\n if (step) {\n if (seen.has(fromId)) return;\n seen.add(fromId);\n rows.push({ step, port: port === \"next\" ? null : port });\n }\n for (const edge of outgoing.get(fromId) ?? []) {\n walk(edge.to, edge.port);\n }\n };\n if (args.triggerId) walk(args.triggerId, null);\n\n return {\n rows,\n orphans: args.steps.filter((step) => !seen.has(step.id)),\n };\n}\n","// The workflow's shape as a pipeline: trigger, then each step in the order a\n// run walks it, annotated with how that step fared in the latest run.\nimport type { WorkflowState } from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { useState } from \"react\";\nimport {\n blockMeta,\n usePieceLogos,\n} from \"../../workflow-editor/ui/block-meta.js\";\nimport { RUN_DOT } from \"./run-format.js\";\nimport { stepOutline, type OutlineStep } from \"./step-outline.js\";\n\nconst STEP_DOT: Record<string, string> = {\n ...RUN_DOT,\n SKIPPED: \"bg-slate-300\",\n REPLAYED: \"bg-sky-400\",\n};\n\n// The piece logo, degrading to the block glyph when absent or unloadable.\nfunction ChipLogo(props: { logoUrl?: string; glyph?: string }) {\n const [broken, setBroken] = useState(false);\n if (props.logoUrl && !broken) {\n return (\n <img\n src={props.logoUrl}\n alt=\"\"\n className=\"h-4 w-4 shrink-0\"\n onError={() => setBroken(true)}\n />\n );\n }\n return (\n <span className=\"w-4 shrink-0 text-center text-xs text-slate-400\">\n {props.glyph ?? \"▪\"}\n </span>\n );\n}\n\nfunction Chip(props: {\n title: string;\n subtitle: string;\n glyph?: string;\n logoUrl?: string;\n status?: string;\n muted?: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n title={\n props.status ? `${props.subtitle} · ${props.status}` : props.subtitle\n }\n className={`flex max-w-56 items-center gap-2 rounded border border-solid px-2 py-1 text-left hover:border-slate-400 ${\n props.muted\n ? \"border-dashed border-slate-300 bg-slate-50\"\n : \"border-slate-200 bg-white\"\n }`}\n onClick={props.onClick}\n >\n <ChipLogo logoUrl={props.logoUrl} glyph={props.glyph} />\n <span className=\"min-w-0\">\n <span className=\"block truncate text-xs font-medium text-slate-700\">\n {props.title}\n </span>\n <span className=\"block truncate text-[11px] text-slate-400\">\n {props.subtitle}\n </span>\n </span>\n {props.status ? (\n <span\n className={`ml-1 h-2 w-2 shrink-0 rounded-full ${STEP_DOT[props.status] ?? \"bg-slate-300\"}`}\n />\n ) : null}\n </button>\n );\n}\n\nfunction Arrow(props: { port: string | null }) {\n return (\n <span className=\"flex shrink-0 items-center gap-1 text-slate-300\">\n <span aria-hidden>→</span>\n {props.port ? (\n <span className=\"rounded bg-slate-100 px-1 text-[10px] text-slate-500\">\n {props.port}\n </span>\n ) : null}\n </span>\n );\n}\n\nexport function WorkflowSteps(props: {\n state: WorkflowState;\n latestRun?: RunRecord;\n onOpenEditor: () => void;\n}) {\n const { state } = props;\n // Piece logos arrive with the catalog; re-renders this pipeline once known.\n usePieceLogos();\n const outline = stepOutline({\n triggerId: state.trigger?.id,\n steps: state.steps,\n edges: state.edges,\n });\n // Latest-run outcome per step, so the pipeline shows where a run stopped.\n const statusByKey = new Map(\n (props.latestRun?.steps ?? []).map((step) => [step.stepKey, step.status]),\n );\n\n const chipFor = (step: OutlineStep, muted: boolean) => {\n const meta = blockMeta(step.blockType);\n return (\n <Chip\n key={step.id}\n title={step.name || step.key}\n subtitle={meta.displayName}\n glyph={meta.glyph}\n logoUrl={meta.logoUrl}\n status={statusByKey.get(step.key)}\n muted={muted}\n onClick={props.onOpenEditor}\n />\n );\n };\n\n if (!state.trigger && state.steps.length === 0) {\n return (\n <section className=\"mt-3 rounded-md border border-solid border-slate-200 bg-white px-3 py-4\">\n <p className=\"text-xs text-slate-500\">\n This workflow has no trigger or steps yet.{\" \"}\n <button\n type=\"button\"\n className=\"underline hover:text-slate-800\"\n onClick={props.onOpenEditor}\n >\n Open the editor\n </button>{\" \"}\n to build it.\n </p>\n </section>\n );\n }\n\n const triggerMeta = state.trigger ? blockMeta(state.trigger.blockType) : null;\n\n return (\n <section className=\"mt-3 rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <div className=\"mb-2 flex items-baseline gap-2\">\n <h3 className=\"text-[11px] text-slate-400\">Steps</h3>\n <span className=\"text-[11px] tabular-nums text-slate-400\">\n {state.steps.length}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {triggerMeta && state.trigger ? (\n <Chip\n title={triggerMeta.displayName}\n subtitle=\"Trigger\"\n glyph={triggerMeta.glyph}\n logoUrl={triggerMeta.logoUrl}\n muted={false}\n onClick={props.onOpenEditor}\n />\n ) : (\n <span className=\"rounded border border-dashed border-slate-300 px-2 py-1 text-[11px] text-slate-400\">\n No trigger\n </span>\n )}\n {outline.rows.map((row) => (\n <span key={row.step.id} className=\"flex items-center gap-2\">\n <Arrow port={row.port} />\n {chipFor(row.step, false)}\n </span>\n ))}\n </div>\n {outline.orphans.length > 0 ? (\n <div className=\"mt-3 border-t border-solid border-slate-100 pt-2\">\n <p className=\"mb-2 text-[11px] text-slate-400\">\n Not connected to the trigger, so runs never reach these:\n </p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {outline.orphans.map((step) => chipFor(step, true))}\n </div>\n </div>\n ) : null}\n </section>\n );\n}\n","// Identity, state and the actions for the workflow whose runs are shown:\n// enable/disable, open the editor, delete. Stats come from the shared feed.\nimport {\n showDeleteNodeModal,\n useDispatch,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport type { ReactNode } from \"react\";\nimport {\n actions as workflowActions,\n type WorkflowDocument,\n} from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { blockMeta } from \"../../workflow-editor/ui/block-meta.js\";\nimport { DocumentLoadError } from \"../../shared/DocumentErrorBoundary.js\";\nimport {\n formatAbsolute,\n formatWhen,\n RUN_DOT,\n RUN_TEXT,\n runStats,\n WORKFLOW_STATUS_STYLES,\n} from \"./run-format.js\";\nimport { WorkflowSteps } from \"./WorkflowSteps.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\nconst ACTION =\n \"rounded border border-solid border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 hover:border-slate-400 hover:bg-slate-50\";\n\nfunction Stat(props: { label: string; children: ReactNode }) {\n return (\n <div className=\"min-w-0 grow border-l border-solid border-slate-200 px-3 py-2 first:border-l-0 first:pl-0\">\n <div className=\"text-[11px] text-slate-400\">{props.label}</div>\n <div className=\"truncate text-xs text-slate-800\">{props.children}</div>\n </div>\n );\n}\n\nexport function WorkflowHeader(props: {\n node: FileNode;\n runs: RunRecord[] | null;\n onEdit: () => void;\n}) {\n const workflowId = props.node.id;\n const { data: document, error, reload } = useDocumentSafe(workflowId);\n const [, dispatch] = useDispatch(document);\n\n if (error !== undefined) {\n return (\n <DocumentLoadError\n title=\"This workflow could not be loaded\"\n documentId={workflowId}\n error={error}\n onRetry={() => {\n void reload();\n }}\n />\n );\n }\n if (document?.header.documentType !== WORKFLOW_TYPE) return null;\n\n const workflow = document as WorkflowDocument;\n const state = workflow.state.global;\n const enabled = state.status === \"ENABLED\";\n const stats = runStats(props.runs ?? []);\n const trigger = state.trigger\n ? blockMeta(state.trigger.blockType).displayName\n : null;\n\n return (\n <header className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"min-w-0 truncate text-base font-semibold text-slate-800\">\n {state.name || props.node.name || \"Untitled workflow\"}\n </h2>\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${WORKFLOW_STATUS_STYLES[state.status] ?? \"bg-slate-100 text-slate-500\"}`}\n >\n {state.status}\n </span>\n <span className=\"grow\" />\n <button\n type=\"button\"\n className={ACTION}\n onClick={() =>\n dispatch(\n workflowActions.setWorkflowStatus({\n status: enabled ? \"DISABLED\" : \"ENABLED\",\n }),\n )\n }\n >\n {enabled ? \"Disable\" : \"Enable\"}\n </button>\n <button type=\"button\" className={ACTION} onClick={props.onEdit}>\n Edit workflow\n </button>\n <button\n type=\"button\"\n className=\"rounded border border-solid border-red-200 bg-white px-2.5 py-1 text-xs font-medium text-red-600 hover:border-red-300 hover:bg-red-50\"\n // The host modal confirms; the studio drops the target once the\n // node leaves the drive.\n onClick={() => showDeleteNodeModal(props.node)}\n >\n Delete\n </button>\n </div>\n {state.description ? (\n <p className=\"mt-1 max-w-2xl text-xs text-slate-500\">\n {state.description}\n </p>\n ) : null}\n <div className=\"mt-3 flex flex-wrap items-stretch rounded-md border border-solid border-slate-200 bg-white px-3\">\n <Stat label=\"Trigger\">\n {trigger ?? <span className=\"text-slate-400\">None set</span>}\n </Stat>\n <Stat label=\"Last run\">\n {stats.lastRun ? (\n <span\n className=\"flex items-center gap-1.5\"\n title={formatAbsolute(stats.lastRun.startedAt)}\n >\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[stats.lastRun.status] ?? \"bg-slate-300\"}`}\n />\n <span className={RUN_TEXT[stats.lastRun.status] ?? \"\"}>\n {formatWhen(stats.lastRun.startedAt)}\n </span>\n </span>\n ) : (\n <span className=\"text-slate-400\">Never run</span>\n )}\n </Stat>\n <Stat label=\"Recent runs\">\n <span className=\"tabular-nums\">\n {stats.total}\n {stats.failed > 0 ? (\n <span className=\"text-red-600\"> · {stats.failed} failed</span>\n ) : null}\n {stats.running > 0 ? (\n <span className=\"text-amber-700\"> · {stats.running} running</span>\n ) : null}\n </span>\n </Stat>\n <Stat label=\"Success rate\">\n {stats.successRate === null ? (\n <span className=\"text-slate-400\">—</span>\n ) : (\n <span className=\"tabular-nums\">{stats.successRate}%</span>\n )}\n </Stat>\n <Stat label=\"Version\">\n <span className=\"tabular-nums\">v{state.version}</span>\n </Stat>\n </div>\n <WorkflowSteps\n state={state}\n latestRun={stats.lastRun}\n onOpenEditor={props.onEdit}\n />\n </header>\n );\n}\n","// Workflow Studio: drive app listing workflows and connections with a\n// GitHub-Actions-style run journal; opens the per-document editors inline.\nimport {\n addDocument,\n setSelectedNode,\n useDocumentSafe,\n useFileNodesInSelectedDrive,\n usePHToast,\n useSelectedDrive,\n useSelectedNode,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { type WorkflowDocument } from \"document-models/workflow\";\nimport { fireWorkflow } from \"../../workflow-editor/runtime-api.js\";\nimport \"../../workflow-editor/runtime-piece-source.js\";\nimport { DocumentErrorBoundary } from \"../../shared/DocumentErrorBoundary.js\";\nimport { EditorToolbar } from \"./EditorToolbar.js\";\nimport { ConnectionView } from \"./ConnectionView.js\";\nimport { RunsView } from \"./RunsView.js\";\nimport { Sidebar } from \"./Sidebar.js\";\nimport { useHashSelection } from \"./use-hash-selection.js\";\nimport { useRuns } from \"./useRuns.js\";\nimport { WorkflowHeader } from \"./WorkflowHeader.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\nconst CONNECTION_TYPE = \"powerhouse/connection\";\n\nexport function WorkflowStudio(props: { children?: ReactNode }) {\n const [drive] = useSelectedDrive();\n const fileNodes = useFileNodesInSelectedDrive() ?? [];\n const selectedNode = useSelectedNode();\n const selectedNodeId = selectedNode?.id;\n const toast = usePHToast();\n // The sidebar selection, kept in the URL hash; undefined = all runs.\n const [selectedId, select] = useHashSelection();\n const [creating, setCreating] = useState(false);\n\n const driveId = drive.header.id;\n const workflows = fileNodes.filter(\n (node) => node.documentType === WORKFLOW_TYPE,\n );\n const connections = fileNodes.filter(\n (node) => node.documentType === CONNECTION_TYPE,\n );\n const editorOpen = Boolean(props.children && selectedNodeId);\n\n const create = (documentType: string, baseName: string, count: number) => {\n if (creating) return;\n setCreating(true);\n addDocument(driveId, `${baseName} ${count + 1}`, documentType)\n .then((node) => {\n select(node.id);\n setSelectedNode(node.id);\n })\n .catch((error: unknown) => {\n toast?.(\n error instanceof Error\n ? error.message\n : `Failed to create ${baseName}`,\n { type: \"error\" },\n );\n })\n .finally(() => setCreating(false));\n };\n\n const showRuns = (node: FileNode | null) => {\n setSelectedNode(undefined);\n select(node?.id);\n };\n\n // Resolved from the drive each render, so a deleted node drops out on its own.\n const liveTarget = workflows.find((node) => node.id === selectedId) ?? null;\n const liveConnection =\n connections.find((node) => node.id === selectedId) ?? null;\n const openNode = fileNodes.find((node) => node.id === selectedNodeId);\n // A deleted node must not keep the hash pointing at nothing.\n const selectionExists = fileNodes.some((node) => node.id === selectedId);\n useEffect(() => {\n if (selectedId && fileNodes.length > 0 && !selectionExists)\n select(undefined);\n }, [fileNodes.length, select, selectedId, selectionExists]);\n const editedWorkflow = editorOpen\n ? (workflows.find((node) => node.id === selectedNodeId) ?? null)\n : null;\n // One feed per pane, shared by the header, the table and the toolbar: the\n // focused workflow's runs, or every run in this drive.\n const focusedWorkflow = editedWorkflow ?? liveTarget;\n const {\n runs,\n error: runsError,\n reload: reloadRuns,\n } = useRuns({\n workflowId: focusedWorkflow?.id,\n driveId: focusedWorkflow ? undefined : driveId,\n });\n\n // Manual fire only makes sense for core#manual triggers.\n const { data: targetDocument } = useDocumentSafe(liveTarget?.id ?? null);\n const manualTrigger =\n targetDocument?.header.documentType === WORKFLOW_TYPE &&\n (targetDocument as WorkflowDocument).state.global.trigger?.blockType ===\n \"core#manual\";\n\n return (\n <div className=\"flex h-full min-h-0\">\n <Sidebar\n workflows={workflows}\n connections={connections}\n activeId={selectedId}\n allRunsActive={!selectedId}\n creating={creating}\n onShowAllRuns={() => showRuns(null)}\n onOpenWorkflow={(node) => showRuns(node)}\n onEditWorkflow={(node) => {\n select(node.id);\n setSelectedNode(node.id);\n }}\n onOpenConnection={(node) => showRuns(node)}\n onEditConnection={(node) => {\n select(node.id);\n setSelectedNode(node.id);\n }}\n onCreateWorkflow={() =>\n create(WORKFLOW_TYPE, \"Workflow\", workflows.length)\n }\n onCreateConnection={() =>\n create(CONNECTION_TYPE, \"Connection\", connections.length)\n }\n />\n <main className=\"min-w-0 flex-1 overflow-y-auto\">\n {editorOpen ? (\n <div className=\"flex h-full min-h-0 flex-col\">\n <EditorToolbar\n node={openNode}\n runs={editedWorkflow ? runs : null}\n onBack={() => setSelectedNode(undefined)}\n />\n <div className=\"flex min-h-0 flex-1 flex-col [&>#document-editor-container]:min-h-0\">\n <DocumentErrorBoundary\n key={selectedNodeId}\n documentId={selectedNodeId}\n label={selectedNode?.name}\n onDismiss={() => setSelectedNode(undefined)}\n >\n {props.children}\n </DocumentErrorBoundary>\n </div>\n </div>\n ) : liveConnection ? (\n <ConnectionView\n key={liveConnection.id}\n node={liveConnection}\n onEdit={() => {\n select(liveConnection.id);\n setSelectedNode(liveConnection.id);\n }}\n onOpenWorkflow={(workflowId) => select(workflowId)}\n />\n ) : (\n <div className=\"mx-auto w-full max-w-5xl p-6\">\n {liveTarget ? (\n <WorkflowHeader\n key={liveTarget.id}\n node={liveTarget}\n runs={runs}\n onEdit={() => setSelectedNode(liveTarget.id)}\n />\n ) : null}\n <RunsView\n // The header already names the workflow; don't say it twice.\n title={liveTarget ? \"Runs\" : \"All runs in this drive\"}\n runs={runs}\n error={runsError}\n reload={reloadRuns}\n showWorkflow={liveTarget === null}\n onFire={\n liveTarget && manualTrigger\n ? () =>\n fireWorkflow(liveTarget.id).then((result) => result.error)\n : undefined\n }\n />\n </div>\n )}\n </main>\n </div>\n );\n}\n","import type { PHAppConfig } from \"@powerhousedao/reactor-browser\";\n\nexport const editorConfig: PHAppConfig = {\n isDragAndDropEnabled: true,\n allowedDocumentTypes: [\"powerhouse/workflow\", \"powerhouse/connection\"],\n};\n","/**\n * WARNING: DO NOT EDIT\n * This file is auto-generated and updated by codegen\n */\nimport { useSetPHAppConfig } from \"@powerhousedao/reactor-browser\";\nimport type { EditorProps } from \"document-model\";\nimport { useSyncWorkflowRuntimeUrl } from \"../workflow-editor/use-runtime-url.js\";\nimport { WorkflowStudio } from \"./components/WorkflowStudio.js\";\nimport { editorConfig } from \"./config.js\";\n\n/** Editor component for the app */\nexport default function Editor(props: EditorProps) {\n useSetPHAppConfig(editorConfig);\n useSyncWorkflowRuntimeUrl();\n return (\n <div className=\"h-full min-h-0 bg-background\">\n <WorkflowStudio>{props.children}</WorkflowStudio>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editor-gpF-ytd5.mjs","names":["WORKFLOW_TYPE","CONNECTION_TYPE","ACTION","Stat","connectionActions","WORKFLOW_TYPE","WORKFLOW_TYPE","workflowActions"],"sources":["../../editors/workflow-studio/components/run-format.ts","../../editors/workflow-studio/components/EditorToolbar.tsx","../../editors/workflow-studio/components/connection-usage.ts","../../editors/workflow-studio/components/ConnectionView.tsx","../../editors/workflow-studio/components/RunsTable.tsx","../../editors/workflow-studio/components/RunsView.tsx","../../editors/workflow-studio/components/Sidebar.tsx","../../editors/workflow-studio/components/use-hash-selection.ts","../../editors/workflow-studio/components/useRuns.ts","../../editors/workflow-studio/components/step-outline.ts","../../editors/workflow-studio/components/WorkflowSteps.tsx","../../editors/workflow-studio/components/WorkflowHeader.tsx","../../editors/workflow-studio/components/WorkflowStudio.tsx","../../editors/workflow-studio/config.ts","../../editors/workflow-studio/editor.tsx"],"sourcesContent":["// Shared run vocabulary: one set of formatters and status colours so the\n// header, the table and the editor toolbar never disagree about a run.\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\n\nexport const RUN_STATUSES = [\"RUNNING\", \"SUCCEEDED\", \"FAILED\"] as const;\n\n// Status is the only place colour carries meaning in this view.\nexport const RUN_DOT: Record<string, string> = {\n SUCCEEDED: \"bg-green-500\",\n FAILED: \"bg-red-500\",\n RUNNING: \"bg-amber-400\",\n PARKED: \"bg-slate-400\",\n CANCELLED: \"bg-slate-400\",\n};\n\nexport const RUN_TEXT: Record<string, string> = {\n SUCCEEDED: \"text-green-700\",\n FAILED: \"text-red-700\",\n RUNNING: \"text-amber-700\",\n};\n\nexport const STEP_TEXT: Record<string, string> = {\n SUCCEEDED: \"text-green-600\",\n FAILED: \"text-red-600\",\n SKIPPED: \"text-slate-400\",\n REPLAYED: \"text-sky-600\",\n};\n\n// Sidebar dots: the same status vocabulary at glyph size.\nexport const WORKFLOW_STATUS_DOT: Record<string, string> = {\n ENABLED: \"bg-green-500\",\n DRAFT: \"bg-slate-300\",\n DISABLED: \"bg-amber-400\",\n ARCHIVED: \"bg-slate-200\",\n};\n\nexport const CONNECTION_STATUS_DOT: Record<string, string> = {\n OK: \"bg-green-500\",\n ERROR: \"bg-red-500\",\n REVOKED: \"bg-red-400\",\n UNCONFIGURED: \"bg-slate-300\",\n};\n\nexport const WORKFLOW_STATUS_STYLES: Record<string, string> = {\n ENABLED: \"bg-green-100 text-green-700\",\n DRAFT: \"bg-slate-100 text-slate-500\",\n DISABLED: \"bg-amber-100 text-amber-700\",\n ARCHIVED: \"bg-slate-200 text-slate-400\",\n};\n\nexport function formatDuration(\n startedAt: string,\n endedAt: string | null,\n): string {\n if (!endedAt) return \"…\";\n const ms = new Date(endedAt).getTime() - new Date(startedAt).getTime();\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;\n}\n\nexport function durationMs(\n startedAt: string,\n endedAt: string | null,\n): number | null {\n if (!endedAt) return null;\n return new Date(endedAt).getTime() - new Date(startedAt).getTime();\n}\n\nexport function formatWhen(startedAt: string): string {\n const diff = Date.now() - new Date(startedAt).getTime();\n if (diff < 60_000) return \"just now\";\n if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`;\n if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`;\n return new Date(startedAt).toLocaleDateString();\n}\n\nexport function formatAbsolute(iso: string): string {\n return new Date(iso).toLocaleString();\n}\n\n// A trigger kind reads better as a verb phrase than as its stored token.\nexport function formatTrigger(kind: string): string {\n return kind.replace(/[-_]/g, \" \").toLowerCase();\n}\n\nexport interface RunStats {\n total: number;\n succeeded: number;\n failed: number;\n running: number;\n lastRun?: RunRecord;\n // Null until at least one run has finished.\n successRate: number | null;\n}\n\nexport function runStats(runs: RunRecord[]): RunStats {\n const succeeded = runs.filter((run) => run.status === \"SUCCEEDED\").length;\n const failed = runs.filter((run) => run.status === \"FAILED\").length;\n const finished = succeeded + failed;\n return {\n total: runs.length,\n succeeded,\n failed,\n running: runs.filter((run) => run.status === \"RUNNING\").length,\n // Runs arrive newest first.\n lastRun: runs[0],\n successRate:\n finished === 0 ? null : Math.round((succeeded / finished) * 100),\n };\n}\n","// The bar above an open document editor: the way back to the journal, plus\n// the run facts an author wants while editing.\nimport { useDocumentSafe } from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport type { WorkflowDocument } from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport {\n formatAbsolute,\n formatDuration,\n formatWhen,\n RUN_DOT,\n RUN_TEXT,\n runStats,\n WORKFLOW_STATUS_STYLES,\n} from \"./run-format.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\nfunction Fact(props: { label: string; value: string; title?: string }) {\n return (\n <span className=\"flex items-baseline gap-1.5\" title={props.title}>\n <span className=\"text-[11px] text-slate-400\">{props.label}</span>\n <span className=\"text-xs tabular-nums text-slate-700\">{props.value}</span>\n </span>\n );\n}\n\nexport function EditorToolbar(props: {\n node?: FileNode;\n runs: RunRecord[] | null;\n onBack: () => void;\n}) {\n const { data: document } = useDocumentSafe(props.node?.id ?? null);\n const isWorkflow = document?.header.documentType === WORKFLOW_TYPE;\n const state = isWorkflow\n ? (document as WorkflowDocument).state.global\n : undefined;\n const stats = runStats(props.runs ?? []);\n const lastRun = isWorkflow ? stats.lastRun : undefined;\n\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-2 border-b border-solid border-slate-200 bg-slate-50 px-3 py-2\">\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 rounded border border-solid border-slate-300 bg-white px-2 py-1 text-xs font-medium text-slate-600 hover:border-slate-400 hover:text-slate-900\"\n onClick={props.onBack}\n >\n <span aria-hidden>←</span>\n {isWorkflow ? \"Back to runs\" : \"Back to overview\"}\n </button>\n <span className=\"min-w-0 truncate text-sm font-medium text-slate-800\">\n {state?.name || props.node?.name || \"Untitled\"}\n </span>\n {state ? (\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${WORKFLOW_STATUS_STYLES[state.status] ?? \"bg-slate-100 text-slate-500\"}`}\n >\n {state.status}\n </span>\n ) : null}\n {isWorkflow ? (\n <span className=\"ml-auto flex flex-wrap items-center gap-x-4 gap-y-1\">\n {lastRun ? (\n <span\n className=\"flex items-baseline gap-1.5\"\n title={formatAbsolute(lastRun.startedAt)}\n >\n <span className=\"text-[11px] text-slate-400\">Last run</span>\n <span className=\"flex items-center gap-1.5 text-xs\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[lastRun.status] ?? \"bg-slate-300\"}`}\n />\n <span className={RUN_TEXT[lastRun.status] ?? \"text-slate-700\"}>\n {formatWhen(lastRun.startedAt)}\n </span>\n <span className=\"tabular-nums text-slate-400\">\n {formatDuration(lastRun.startedAt, lastRun.endedAt)}\n </span>\n </span>\n </span>\n ) : (\n <Fact label=\"Last run\" value=\"Never run\" />\n )}\n {stats.successRate !== null ? (\n <Fact\n label=\"Success\"\n value={`${stats.successRate}%`}\n title={`${stats.succeeded} of ${stats.succeeded + stats.failed} finished runs succeeded`}\n />\n ) : null}\n <Fact label=\"Runs\" value={String(stats.total)} />\n </span>\n ) : null}\n </div>\n );\n}\n","// Which workflows depend on a connection, and where. Answers the question a\n// connection page has to answer before anyone dares revoke or delete it.\n\nexport interface UsageStep {\n id: string;\n key: string;\n name: string;\n blockType: string;\n}\n\nexport interface UsageWorkflow {\n id: string;\n name: string;\n status: string;\n trigger?: { blockType: string; connectionId?: string | null } | null;\n steps: readonly UsageStep[];\n}\n\nexport interface ConnectionUsage {\n workflow: UsageWorkflow;\n // The trigger binds this connection.\n trigger: boolean;\n steps: UsageStep[];\n}\n\nexport function connectionUsage(\n connectionId: string,\n workflows: readonly UsageWorkflow[],\n): ConnectionUsage[] {\n const usage: ConnectionUsage[] = [];\n for (const workflow of workflows) {\n const trigger = workflow.trigger?.connectionId === connectionId;\n const steps = workflow.steps.filter(\n (step) =>\n (step as { connectionId?: string | null }).connectionId ===\n connectionId,\n );\n if (trigger || steps.length > 0) usage.push({ workflow, trigger, steps });\n }\n return usage.sort((a, b) => a.workflow.name.localeCompare(b.workflow.name));\n}\n\n// An enabled workflow that depends on this connection breaks the moment it is\n// revoked, so the UI warns before that happens.\nexport function enabledDependents(usage: ConnectionUsage[]): number {\n return usage.filter((entry) => entry.workflow.status === \"ENABLED\").length;\n}\n","// A connection's view mode: what it connects to, how it is configured, and\n// which workflows would break if it went away.\nimport {\n showDeleteNodeModal,\n useDispatch,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport {\n actions as connectionActions,\n type ConnectionDocument,\n} from \"document-models/connection\";\nimport { useWorkflowDocumentsInSelectedDrive } from \"document-models/workflow\";\nimport type { ReactNode } from \"react\";\nimport { CONNECTION_STATUS_STYLES } from \"../../connection-editor/status.js\";\nimport { packageFromConnectorId } from \"../../connection-editor/piece-auth.js\";\nimport { DocumentLoadError } from \"../../shared/DocumentErrorBoundary.js\";\nimport {\n connectionUsage,\n enabledDependents,\n type UsageWorkflow,\n} from \"./connection-usage.js\";\nimport { formatAbsolute, WORKFLOW_STATUS_DOT } from \"./run-format.js\";\n\nconst CONNECTION_TYPE = \"powerhouse/connection\";\n\nconst ACTION =\n \"rounded border border-solid border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 hover:border-slate-400 hover:bg-slate-50\";\n\nfunction Stat(props: { label: string; children: ReactNode }) {\n return (\n <div className=\"min-w-0 grow border-l border-solid border-slate-200 px-3 py-2 first:border-l-0 first:pl-0\">\n <div className=\"text-[11px] text-slate-400\">{props.label}</div>\n <div className=\"truncate text-xs text-slate-800\">{props.children}</div>\n </div>\n );\n}\n\nfunction configEntries(config: unknown): [string, string][] {\n if (!config || typeof config !== \"object\" || Array.isArray(config)) return [];\n return Object.entries(config as Record<string, unknown>).map(\n ([key, value]) => [\n key,\n typeof value === \"string\" ? value : JSON.stringify(value),\n ],\n );\n}\n\nexport function ConnectionView(props: {\n node: FileNode;\n onEdit: () => void;\n onOpenWorkflow: (workflowId: string) => void;\n}) {\n const connectionId = props.node.id;\n const { data: document, error, reload } = useDocumentSafe(connectionId);\n const [, dispatch] = useDispatch(document);\n const workflows = useWorkflowDocumentsInSelectedDrive();\n\n if (error !== undefined) {\n return (\n <DocumentLoadError\n title=\"This connection could not be loaded\"\n documentId={connectionId}\n error={error}\n onRetry={() => {\n void reload();\n }}\n />\n );\n }\n if (document?.header.documentType !== CONNECTION_TYPE) return null;\n\n const state = (document as ConnectionDocument).state.global;\n const revoked = state.status === \"REVOKED\";\n const packageName = packageFromConnectorId(state.connectorId);\n const usage = connectionUsage(\n connectionId,\n (workflows ?? []).map(\n (workflow): UsageWorkflow => ({\n id: workflow.header.id,\n name: workflow.state.global.name || workflow.header.name || \"Untitled\",\n status: workflow.state.global.status,\n trigger: workflow.state.global.trigger,\n steps: workflow.state.global.steps,\n }),\n ),\n );\n const atRisk = enabledDependents(usage);\n const config = configEntries(state.config);\n\n const setStatus = (status: \"OK\" | \"REVOKED\") =>\n dispatch(\n connectionActions.recordCheckResult({\n status,\n checkedAt: new Date().toISOString(),\n }),\n );\n\n return (\n <div className=\"mx-auto w-full max-w-5xl p-6\">\n <header className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"min-w-0 truncate text-base font-semibold text-slate-800\">\n {state.name || props.node.name || \"Untitled connection\"}\n </h2>\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${CONNECTION_STATUS_STYLES[state.status]}`}\n >\n {state.status}\n </span>\n <span className=\"grow\" />\n <button type=\"button\" className={ACTION} onClick={props.onEdit}>\n Edit connection\n </button>\n <button\n type=\"button\"\n className={ACTION}\n onClick={() => setStatus(revoked ? \"OK\" : \"REVOKED\")}\n >\n {revoked ? \"Reactivate\" : \"Revoke\"}\n </button>\n <button\n type=\"button\"\n className=\"rounded border border-solid border-red-200 bg-white px-2.5 py-1 text-xs font-medium text-red-600 hover:border-red-300 hover:bg-red-50\"\n onClick={() => showDeleteNodeModal(props.node)}\n >\n Delete\n </button>\n </div>\n <div className=\"mt-3 flex flex-wrap items-stretch rounded-md border border-solid border-slate-200 bg-white px-3\">\n <Stat label=\"Connector\">\n {packageName || <span className=\"text-slate-400\">None picked</span>}\n </Stat>\n <Stat label=\"Auth\">{state.authType}</Stat>\n <Stat label=\"Account\">\n {state.accountLabel ?? <span className=\"text-slate-400\">—</span>}\n </Stat>\n <Stat label=\"Last checked\">\n {state.lastCheckedAt ? (\n formatAbsolute(state.lastCheckedAt)\n ) : (\n <span className=\"text-slate-400\">Never</span>\n )}\n </Stat>\n <Stat label=\"Secrets\">\n <span className=\"tabular-nums\">{state.secretRefs.length}</span>\n </Stat>\n <Stat label=\"Used by\">\n <span className=\"tabular-nums\">\n {usage.length}\n {atRisk > 0 ? (\n <span className=\"text-slate-400\"> · {atRisk} enabled</span>\n ) : null}\n </span>\n </Stat>\n </div>\n </header>\n\n {state.lastError ? (\n <p className=\"mb-4 rounded bg-red-50 px-3 py-2 text-xs text-red-600\">\n {state.lastError}\n </p>\n ) : null}\n\n <section className=\"mb-4 rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <h3 className=\"mb-2 text-[11px] text-slate-400\">Used by</h3>\n {usage.length === 0 ? (\n <p className=\"text-xs text-slate-500\">\n No workflow uses this connection yet. Bind it to a step in a\n workflow's editor.\n </p>\n ) : (\n <ul className=\"flex flex-col gap-1\">\n {usage.map((entry) => (\n <li key={entry.workflow.id}>\n <button\n type=\"button\"\n className=\"flex w-full items-center gap-2 rounded px-1 py-1 text-left hover:bg-slate-50\"\n onClick={() => props.onOpenWorkflow(entry.workflow.id)}\n >\n <span\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${WORKFLOW_STATUS_DOT[entry.workflow.status] ?? \"bg-slate-300\"}`}\n title={entry.workflow.status}\n />\n <span className=\"shrink-0 text-xs font-medium text-slate-700\">\n {entry.workflow.name}\n </span>\n <span className=\"truncate text-[11px] text-slate-400\">\n {entry.trigger ? \"trigger\" : null}\n {entry.trigger && entry.steps.length > 0 ? \" · \" : null}\n {entry.steps.map((step) => step.key).join(\", \")}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </section>\n\n <section className=\"rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <h3 className=\"mb-2 text-[11px] text-slate-400\">Configuration</h3>\n {config.length === 0 && state.secretRefs.length === 0 ? (\n <p className=\"text-xs text-slate-500\">\n Nothing configured yet.{\" \"}\n <button\n type=\"button\"\n className=\"underline hover:text-slate-800\"\n onClick={props.onEdit}\n >\n Open the editor\n </button>{\" \"}\n to fill it in.\n </p>\n ) : (\n <dl className=\"flex flex-col gap-1\">\n {config.map(([key, value]) => (\n <div key={key} className=\"flex gap-2 text-xs\">\n <dt className=\"w-40 shrink-0 truncate text-slate-500\">{key}</dt>\n <dd className=\"min-w-0 truncate text-slate-800\">{value}</dd>\n </div>\n ))}\n {state.secretRefs.map((ref) => (\n <div key={ref.id} className=\"flex gap-2 text-xs\">\n <dt className=\"w-40 shrink-0 truncate text-slate-500\">\n {ref.name}\n </dt>\n <dd className=\"text-slate-400\">\n stored secret · never displayed\n </dd>\n </div>\n ))}\n </dl>\n )}\n </section>\n </div>\n );\n}\n","// The run journal as a filterable table. Rows expand in place to their step\n// executions, so drilling into a failure never leaves the list.\nimport { Fragment, useMemo, useState } from \"react\";\nimport {\n rerunRun,\n type RunRecord,\n type RunStepRecord,\n} from \"../../workflow-editor/runtime-api.js\";\nimport { blockMeta } from \"../../workflow-editor/ui/block-meta.js\";\nimport {\n formatAbsolute,\n formatDuration,\n formatTrigger,\n formatWhen,\n durationMs,\n RUN_DOT,\n RUN_STATUSES,\n RUN_TEXT,\n STEP_TEXT,\n} from \"./run-format.js\";\n\ntype StatusFilter = \"ALL\" | (typeof RUN_STATUSES)[number];\ntype SortKey = \"startedAt\" | \"duration\";\n\nconst CONTROL =\n \"rounded border border-solid border-slate-300 bg-white px-2 py-1 text-xs text-slate-700 focus:border-slate-400 focus:outline-none\";\n\nfunction stringify(value: unknown): string {\n if (value === undefined) return \"\";\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value as string);\n }\n}\n\nfunction StepRow(props: { step: RunStepRecord }) {\n const { step } = props;\n const meta = blockMeta(step.blockType);\n const [open, setOpen] = useState(false);\n return (\n <div className=\"border-t border-solid border-slate-100 first:border-t-0\">\n <button\n type=\"button\"\n aria-expanded={open}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left hover:bg-white focus-visible:bg-white focus-visible:outline-none\"\n onClick={() => setOpen((value) => !value)}\n >\n <span\n className={`w-16 shrink-0 text-[11px] font-semibold ${STEP_TEXT[step.status] ?? \"text-slate-500\"}`}\n >\n {step.status}\n </span>\n <span className=\"shrink-0 text-xs font-medium text-slate-700\">\n {step.stepKey}\n </span>\n <span className=\"truncate text-xs text-slate-400\">\n {meta.displayName} · {meta.subtitle}\n </span>\n {step.port ? (\n <span className=\"ml-auto shrink-0 rounded bg-slate-100 px-1 text-[10px] text-slate-500\">\n → {step.port}\n </span>\n ) : null}\n </button>\n {open ? (\n <div className=\"space-y-1 px-3 pb-2\">\n {step.error ? (\n <pre className=\"overflow-x-auto rounded bg-red-50 p-2 text-[11px] text-red-600\">\n {step.error}\n </pre>\n ) : null}\n <details>\n <summary className=\"cursor-pointer text-[11px] text-slate-400\">\n input\n </summary>\n <pre className=\"max-h-48 overflow-auto rounded bg-white p-2 text-[11px] text-slate-600\">\n {stringify(step.input)}\n </pre>\n </details>\n <details>\n <summary className=\"cursor-pointer text-[11px] text-slate-400\">\n output\n </summary>\n <pre className=\"max-h-48 overflow-auto rounded bg-white p-2 text-[11px] text-slate-600\">\n {stringify(step.output)}\n </pre>\n </details>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction RunDetail(props: { run: RunRecord; onChanged: () => void }) {\n const { run } = props;\n const [rerunning, setRerunning] = useState(false);\n const [rerunError, setRerunError] = useState<string | null>(null);\n return (\n <div className=\"space-y-2 bg-slate-50 px-4 py-3\">\n {run.error ? (\n <p className=\"rounded bg-red-50 px-2 py-1 text-xs text-red-600\">\n {run.error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-[11px] text-slate-500\">\n <span>\n run <span className=\"font-mono\">{run.id.slice(0, 8)}</span>\n </span>\n <span>started {formatAbsolute(run.startedAt)}</span>\n {run.rerunOf ? (\n <span>\n resumes <span className=\"font-mono\">{run.rerunOf.slice(0, 8)}</span>\n </span>\n ) : null}\n {run.status === \"FAILED\" ? (\n <button\n type=\"button\"\n disabled={rerunning}\n className=\"rounded border border-solid border-slate-300 bg-white px-2 py-1 font-medium text-slate-600 hover:border-slate-400 disabled:opacity-50\"\n onClick={() => {\n setRerunning(true);\n setRerunError(null);\n rerunRun(run.id)\n .then((result) => setRerunError(result.error))\n .catch((error: unknown) =>\n setRerunError(\n error instanceof Error ? error.message : String(error),\n ),\n )\n .finally(() => {\n setRerunning(false);\n props.onChanged();\n });\n }}\n >\n {rerunning ? \"Rerunning…\" : \"↻ Rerun from failure\"}\n </button>\n ) : null}\n {rerunError ? <span className=\"text-red-600\">{rerunError}</span> : null}\n </div>\n {run.steps.length === 0 ? (\n <p className=\"text-xs text-slate-400\">This run recorded no steps.</p>\n ) : (\n <div className=\"rounded border border-solid border-slate-200 bg-slate-50\">\n {run.steps.map((step) => (\n <StepRow key={step.stepId + step.stepKey} step={step} />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction SortHeader(props: {\n label: string;\n active: boolean;\n descending: boolean;\n onClick: () => void;\n className?: string;\n}) {\n return (\n <th scope=\"col\" className={props.className}>\n <button\n type=\"button\"\n className={`flex items-center gap-1 hover:text-slate-700 ${props.active ? \"text-slate-700\" : \"\"}`}\n onClick={props.onClick}\n >\n {props.label}\n <span aria-hidden className={props.active ? \"\" : \"opacity-0\"}>\n {props.descending ? \"↓\" : \"↑\"}\n </span>\n </button>\n </th>\n );\n}\n\nexport function RunsTable(props: {\n runs: RunRecord[];\n showWorkflow: boolean;\n onChanged: () => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const [status, setStatus] = useState<StatusFilter>(\"ALL\");\n const [workflow, setWorkflow] = useState(\"ALL\");\n const [trigger, setTrigger] = useState(\"ALL\");\n const [sort, setSort] = useState<SortKey>(\"startedAt\");\n const [descending, setDescending] = useState(true);\n const [expanded, setExpanded] = useState<string | null>(null);\n\n const workflowOptions = useMemo(\n () =>\n [...new Map(props.runs.map((run) => [run.workflowId, run.workflowName]))]\n .map(([id, name]) => ({ id, name }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n [props.runs],\n );\n const triggerOptions = useMemo(\n () => [...new Set(props.runs.map((run) => run.triggerKind))].sort(),\n [props.runs],\n );\n\n // Everything except the status filter, so the status counts describe what\n // picking each one would actually show.\n const scoped = useMemo(() => {\n const needle = query.trim().toLowerCase();\n return props.runs.filter((run) => {\n if (workflow !== \"ALL\" && run.workflowId !== workflow) return false;\n if (trigger !== \"ALL\" && run.triggerKind !== trigger) return false;\n if (!needle) return true;\n return (\n run.workflowName.toLowerCase().includes(needle) ||\n run.id.toLowerCase().includes(needle) ||\n (run.error?.toLowerCase().includes(needle) ?? false) ||\n run.steps.some((step) => step.stepKey.toLowerCase().includes(needle))\n );\n });\n }, [props.runs, query, workflow, trigger]);\n\n const counts = useMemo(\n () => ({\n ALL: scoped.length,\n RUNNING: scoped.filter((run) => run.status === \"RUNNING\").length,\n SUCCEEDED: scoped.filter((run) => run.status === \"SUCCEEDED\").length,\n FAILED: scoped.filter((run) => run.status === \"FAILED\").length,\n }),\n [scoped],\n );\n\n const visible = useMemo(() => {\n const rows = scoped.filter(\n (run) => status === \"ALL\" || run.status === status,\n );\n const direction = descending ? -1 : 1;\n return [...rows].sort((a, b) => {\n if (sort === \"duration\") {\n // An unfinished run has no duration yet; keep those together.\n const left = durationMs(a.startedAt, a.endedAt) ?? Infinity;\n const right = durationMs(b.startedAt, b.endedAt) ?? Infinity;\n return (left - right) * direction;\n }\n return (\n (new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime()) *\n direction\n );\n });\n }, [scoped, status, sort, descending]);\n\n const filtered = query.trim() || workflow !== \"ALL\" || trigger !== \"ALL\";\n const sortBy = (key: SortKey) => {\n if (key === sort) {\n setDescending((value) => !value);\n return;\n }\n setSort(key);\n setDescending(true);\n };\n\n return (\n <div>\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <div className=\"flex overflow-hidden rounded border border-solid border-slate-300\">\n {([\"ALL\", ...RUN_STATUSES] as StatusFilter[]).map((option) => (\n <button\n key={option}\n type=\"button\"\n aria-pressed={status === option}\n className={`border-r border-solid border-slate-200 px-2.5 py-1 text-xs last:border-r-0 ${\n status === option\n ? \"bg-slate-800 text-white\"\n : \"bg-white text-slate-600 hover:bg-slate-50\"\n }`}\n onClick={() => setStatus(option)}\n >\n {option === \"ALL\"\n ? \"All\"\n : option.charAt(0) + option.slice(1).toLowerCase()}\n <span className=\"ml-1.5 tabular-nums opacity-60\">\n {counts[option]}\n </span>\n </button>\n ))}\n </div>\n <input\n type=\"search\"\n className={`${CONTROL} w-44`}\n placeholder=\"Search runs\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n />\n {props.showWorkflow && workflowOptions.length > 1 ? (\n <select\n className={CONTROL}\n value={workflow}\n onChange={(event) => setWorkflow(event.target.value)}\n >\n <option value=\"ALL\">Every workflow</option>\n {workflowOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n ) : null}\n {triggerOptions.length > 1 ? (\n <select\n className={CONTROL}\n value={trigger}\n onChange={(event) => setTrigger(event.target.value)}\n >\n <option value=\"ALL\">Every trigger</option>\n {triggerOptions.map((option) => (\n <option key={option} value={option}>\n {formatTrigger(option)}\n </option>\n ))}\n </select>\n ) : null}\n {filtered ? (\n <button\n type=\"button\"\n className=\"text-xs text-slate-500 underline hover:text-slate-800\"\n onClick={() => {\n setQuery(\"\");\n setWorkflow(\"ALL\");\n setTrigger(\"ALL\");\n }}\n >\n Clear filters\n </button>\n ) : null}\n <span className=\"ml-auto text-[11px] tabular-nums text-slate-400\">\n {visible.length} of {props.runs.length} runs\n </span>\n </div>\n\n <div className=\"overflow-x-auto rounded-md border border-solid border-slate-200 bg-white\">\n <table className=\"w-full border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-solid border-slate-200 text-[11px] font-medium text-slate-400\">\n <th scope=\"col\" className=\"px-3 py-2\">\n Status\n </th>\n {props.showWorkflow ? (\n <th scope=\"col\" className=\"px-3 py-2\">\n Workflow\n </th>\n ) : null}\n <th scope=\"col\" className=\"px-3 py-2\">\n Trigger\n </th>\n <SortHeader\n label=\"Started\"\n className=\"px-3 py-2\"\n active={sort === \"startedAt\"}\n descending={descending}\n onClick={() => sortBy(\"startedAt\")}\n />\n <SortHeader\n label=\"Duration\"\n className=\"px-3 py-2\"\n active={sort === \"duration\"}\n descending={descending}\n onClick={() => sortBy(\"duration\")}\n />\n <th scope=\"col\" className=\"px-3 py-2\">\n Steps\n </th>\n <th scope=\"col\" className=\"w-8 px-3 py-2\">\n <span className=\"sr-only\">Details</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {visible.length === 0 ? (\n <tr>\n <td\n colSpan={props.showWorkflow ? 7 : 6}\n className=\"px-3 py-6 text-center text-sm text-slate-400\"\n >\n No runs match these filters.\n </td>\n </tr>\n ) : (\n visible.map((run) => {\n const open = expanded === run.id;\n return (\n <Fragment key={run.id}>\n <tr\n className={`cursor-pointer border-b border-solid border-slate-100 text-sm ${\n open ? \"bg-slate-50\" : \"hover:bg-slate-50\"\n }`}\n onClick={() => setExpanded(open ? null : run.id)}\n >\n <td className=\"px-3 py-2\">\n <span className=\"flex items-center gap-2\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[run.status] ?? \"bg-slate-300\"}`}\n />\n <span\n className={`text-xs font-medium ${RUN_TEXT[run.status] ?? \"text-slate-500\"}`}\n >\n {run.status.charAt(0) +\n run.status.slice(1).toLowerCase()}\n </span>\n </span>\n </td>\n {props.showWorkflow ? (\n <td className=\"max-w-48 truncate px-3 py-2 text-slate-800\">\n {run.workflowName}\n </td>\n ) : null}\n <td className=\"px-3 py-2 text-xs text-slate-500\">\n {formatTrigger(run.triggerKind)}\n <span className=\"ml-1 text-slate-300\">\n v{run.workflowVersion}\n </span>\n </td>\n <td\n className=\"whitespace-nowrap px-3 py-2 text-xs tabular-nums text-slate-500\"\n title={formatAbsolute(run.startedAt)}\n >\n {formatWhen(run.startedAt)}\n </td>\n <td className=\"whitespace-nowrap px-3 py-2 text-xs tabular-nums text-slate-500\">\n {formatDuration(run.startedAt, run.endedAt)}\n </td>\n <td className=\"px-3 py-2 text-xs tabular-nums text-slate-500\">\n {run.steps.length}\n </td>\n <td className=\"px-3 py-2\">\n <button\n type=\"button\"\n aria-expanded={open}\n aria-label={`${open ? \"Hide\" : \"Show\"} steps of the run started ${formatAbsolute(run.startedAt)}`}\n className=\"rounded px-1 text-xs text-slate-400 hover:text-slate-700\"\n onClick={(event) => {\n event.stopPropagation();\n setExpanded(open ? null : run.id);\n }}\n >\n <span aria-hidden>{open ? \"▾\" : \"▸\"}</span>\n </button>\n </td>\n </tr>\n {open ? (\n <tr>\n <td\n colSpan={props.showWorkflow ? 7 : 6}\n className=\"border-b border-solid border-slate-200 p-0\"\n >\n <RunDetail run={run} onChanged={props.onChanged} />\n </td>\n </tr>\n ) : null}\n </Fragment>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n","// The runs pane: what scope is being shown, how to fire it, and the journal.\n// The run feed is owned by the studio so the header shares these rows.\nimport { useState } from \"react\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { RunsTable } from \"./RunsTable.js\";\n\nexport function RunsView(props: {\n title: string;\n runs: RunRecord[] | null;\n error: string | null;\n reload: () => void;\n showWorkflow: boolean;\n // Present only for manual-trigger workflows.\n onFire?: () => Promise<string | null>;\n}) {\n const [firing, setFiring] = useState(false);\n const [fireError, setFireError] = useState<string | null>(null);\n const { runs } = props;\n\n return (\n <div className=\"w-full\">\n <div className=\"mb-3 flex items-center gap-3\">\n <h2 className=\"text-base font-semibold text-slate-800\">\n {props.title}\n </h2>\n <span className=\"grow\" />\n {props.onFire ? (\n <button\n type=\"button\"\n disabled={firing}\n className=\"rounded bg-blue-600 px-3 py-1.5 text-xs font-semibold text-white hover:bg-blue-700 disabled:opacity-50\"\n onClick={() => {\n setFiring(true);\n setFireError(null);\n props.onFire!()\n .then((fireResultError) => setFireError(fireResultError))\n .catch((fireCallError: unknown) =>\n setFireError(\n fireCallError instanceof Error\n ? fireCallError.message\n : String(fireCallError),\n ),\n )\n .finally(() => {\n setFiring(false);\n props.reload();\n });\n }}\n >\n {firing ? \"Running…\" : \"▶ Run workflow\"}\n </button>\n ) : null}\n </div>\n {fireError ? (\n <p className=\"mb-2 rounded bg-red-50 px-3 py-2 text-xs text-red-600\">\n {fireError}\n </p>\n ) : null}\n {props.error ? (\n <p className=\"rounded bg-amber-50 px-3 py-2 text-xs text-amber-700\">\n The workflow runtime is unreachable, so runs cannot be listed:{\" \"}\n {props.error}\n </p>\n ) : runs === null ? (\n <p className=\"text-sm text-slate-400\">Loading runs…</p>\n ) : runs.length === 0 ? (\n <p className=\"rounded-md border border-solid border-slate-200 bg-white px-3 py-6 text-center text-sm text-slate-400\">\n No runs yet\n {props.onFire ? \" — run the workflow to record the first one\" : \"\"}.\n </p>\n ) : (\n <RunsTable\n runs={runs}\n showWorkflow={props.showWorkflow}\n onChanged={props.reload}\n />\n )}\n </div>\n );\n}\n","// Studio navigation: the drive-wide journal, then the drive's workflows and\n// connections. Each row carries its document's status as a dot.\nimport {\n showDeleteNodeModal,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport { useEffect, type ReactNode } from \"react\";\nimport { errorMessage } from \"../../shared/DocumentErrorBoundary.js\";\nimport { CONNECTION_STATUS_DOT, WORKFLOW_STATUS_DOT } from \"./run-format.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\n// The drive node name goes stale after renames; the document state is the\n// source of truth for both workflow and connection names.\nfunction documentName(document: unknown, fallback: string): string {\n const state = (document as { state?: { global?: { name?: string } } } | null)\n ?.state?.global;\n return state?.name || fallback || \"(unnamed)\";\n}\n\nfunction documentStatus(document: unknown): string | undefined {\n const state = (\n document as { state?: { global?: { status?: string } } } | null\n )?.state?.global;\n return state?.status;\n}\n\nfunction Row(props: {\n active: boolean;\n onClick: () => void;\n children: ReactNode;\n trailing?: ReactNode;\n}) {\n return (\n <div\n className={`group mx-2 flex items-center rounded ${\n props.active ? \"bg-white ring-1 ring-slate-200\" : \"hover:bg-slate-100\"\n }`}\n >\n <button\n type=\"button\"\n aria-current={props.active ? \"true\" : undefined}\n className={`flex min-w-0 grow items-center gap-2 px-2 py-1.5 text-left text-sm ${\n props.active ? \"text-slate-900\" : \"text-slate-600\"\n }`}\n onClick={props.onClick}\n >\n {props.children}\n </button>\n {props.trailing}\n </div>\n );\n}\n\nconst ROW_ACTION =\n \"shrink-0 rounded px-1 py-0.5 text-xs text-slate-400 opacity-0 hover:bg-slate-200 hover:text-slate-700 focus-visible:opacity-100 group-hover:opacity-100\";\n\nconst DELETE_ACTION = `${ROW_ACTION} hover:bg-red-100 hover:text-red-600`;\n\nfunction DeleteButton(props: { node: FileNode; label: string }) {\n return (\n <button\n type=\"button\"\n title=\"Delete\"\n aria-label={`Delete ${props.label}`}\n className={DELETE_ACTION}\n onClick={() => showDeleteNodeModal(props.node)}\n >\n <span aria-hidden>🗑</span>\n </button>\n );\n}\n\n// A node can outlive its document (deleted, or unreadable history), so one\n// broken node degrades to its drive name plus a warning marker.\nfunction NodeRow(props: {\n node: FileNode;\n active: boolean;\n onOpen: () => void;\n onEdit?: () => void;\n}) {\n const { node } = props;\n const { data: document, error } = useDocumentSafe(node.id);\n useEffect(() => {\n if (error !== undefined) {\n console.error(`Failed to load document ${node.id}:`, error);\n }\n }, [error, node.id]);\n\n if (error !== undefined) {\n return (\n <Row\n active={props.active}\n onClick={props.onOpen}\n trailing={\n <span className=\"mr-1.5 flex shrink-0 items-center\">\n <DeleteButton node={node} label={node.name || node.id} />\n </span>\n }\n >\n <span\n className=\"shrink-0 text-xs text-red-600\"\n title={`Could not load ${node.id}: ${errorMessage(error)}`}\n aria-hidden\n >\n ⚠\n </span>\n <span className=\"min-w-0 truncate text-red-600\">\n {node.name || \"(unnamed)\"}\n </span>\n </Row>\n );\n }\n\n const status = documentStatus(document);\n const dots =\n node.documentType === WORKFLOW_TYPE\n ? WORKFLOW_STATUS_DOT\n : CONNECTION_STATUS_DOT;\n return (\n <Row\n active={props.active}\n onClick={props.onOpen}\n trailing={\n <span className=\"mr-1.5 flex shrink-0 items-center\">\n {props.onEdit ? (\n <button\n type=\"button\"\n title=\"Open in editor\"\n aria-label={`Open ${documentName(document, node.name)} in the editor`}\n className={ROW_ACTION}\n onClick={props.onEdit}\n >\n <span aria-hidden>✎</span>\n </button>\n ) : null}\n <DeleteButton node={node} label={documentName(document, node.name)} />\n </span>\n }\n >\n <span\n className={`h-1.5 w-1.5 shrink-0 rounded-full ${\n status ? (dots[status] ?? \"bg-slate-300\") : \"bg-slate-200\"\n }`}\n title={status}\n />\n <span className=\"min-w-0 truncate\">\n {documentName(document, node.name)}\n </span>\n </Row>\n );\n}\n\nfunction Section(props: {\n title: string;\n addLabel: string;\n empty: string;\n nodes: FileNode[];\n activeId?: string | null;\n onOpen: (node: FileNode) => void;\n onEdit?: (node: FileNode) => void;\n onCreate: () => void;\n creating: boolean;\n}) {\n return (\n <div className=\"mt-2\">\n {/* A banded header, so the two groups read as separate lists. */}\n <div className=\"mb-1.5 flex items-center justify-between border-y border-solid border-slate-200 bg-slate-100 px-4 py-1.5\">\n <span className=\"text-[11px] font-bold uppercase tracking-wider text-slate-600\">\n {props.title}\n </span>\n <button\n type=\"button\"\n disabled={props.creating}\n className=\"flex h-5 w-5 items-center justify-center rounded border border-solid border-transparent text-sm leading-none text-slate-500 hover:border-slate-300 hover:bg-white hover:text-slate-800 disabled:opacity-50\"\n title={props.addLabel}\n aria-label={props.addLabel}\n onClick={props.onCreate}\n >\n <span aria-hidden>+</span>\n </button>\n </div>\n {props.nodes.length === 0 ? (\n <p className=\"px-4 py-1 text-xs text-slate-400\">{props.empty}</p>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n {props.nodes.map((node) => (\n <NodeRow\n key={node.id}\n node={node}\n active={props.activeId === node.id}\n onOpen={() => props.onOpen(node)}\n onEdit={props.onEdit ? () => props.onEdit!(node) : undefined}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function Sidebar(props: {\n workflows: FileNode[];\n connections: FileNode[];\n activeId?: string | null;\n allRunsActive: boolean;\n creating: boolean;\n onShowAllRuns: () => void;\n onOpenWorkflow: (node: FileNode) => void;\n onEditWorkflow: (node: FileNode) => void;\n onOpenConnection: (node: FileNode) => void;\n onEditConnection: (node: FileNode) => void;\n onCreateWorkflow: () => void;\n onCreateConnection: () => void;\n}) {\n return (\n <aside className=\"w-60 shrink-0 overflow-y-auto border-r border-solid border-slate-200 bg-slate-50 py-2\">\n <Row active={props.allRunsActive} onClick={props.onShowAllRuns}>\n <span aria-hidden className=\"shrink-0 text-xs text-slate-400\">\n ☰\n </span>\n <span className=\"font-medium\">All runs</span>\n </Row>\n <Section\n title=\"Workflows\"\n addLabel=\"New workflow\"\n empty=\"No workflows yet. Use + to add one.\"\n nodes={props.workflows}\n activeId={props.activeId}\n onOpen={props.onOpenWorkflow}\n onEdit={props.onEditWorkflow}\n onCreate={props.onCreateWorkflow}\n creating={props.creating}\n />\n <Section\n title=\"Connections\"\n addLabel=\"New connection\"\n empty=\"No connections yet. Use + to add one.\"\n nodes={props.connections}\n activeId={props.activeId}\n onOpen={props.onOpenConnection}\n onEdit={props.onEditConnection}\n onCreate={props.onCreateConnection}\n creating={props.creating}\n />\n </aside>\n );\n}\n","// Connect owns the path (`/d/<drive>/<node>`) for an open editor; the studio's\n// sidebar selection lives in the hash, so it survives a refresh.\nimport { useCallback, useEffect, useState } from \"react\";\n\nfunction readHash(): string | undefined {\n return window.location.hash.replace(/^#/, \"\") || undefined;\n}\n\nexport function useHashSelection(): [\n string | undefined,\n (id?: string) => void,\n] {\n const [selected, setSelected] = useState<string | undefined>(readHash);\n\n useEffect(() => {\n // Covers back/forward and a hand-edited URL.\n const sync = () => setSelected(readHash());\n window.addEventListener(\"hashchange\", sync);\n window.addEventListener(\"popstate\", sync);\n return () => {\n window.removeEventListener(\"hashchange\", sync);\n window.removeEventListener(\"popstate\", sync);\n };\n }, []);\n\n const select = useCallback((id?: string) => {\n setSelected(id);\n // Replaced, not pushed: Connect pushes a path entry on the same click, and\n // two history entries per click breaks the back button.\n const url = new URL(window.location.href);\n url.hash = id ?? \"\";\n window.history.replaceState(null, \"\", url);\n }, []);\n\n return [selected, select];\n}\n","// One polling subscription to the run journal per studio pane. The header,\n// the table and the editor toolbar all read from it, so they stay in step.\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n fetchRuns,\n type RunRecord,\n type RunsScope,\n} from \"../../workflow-editor/runtime-api.js\";\n\nconst POLL_MS = 5000;\n\nexport interface RunsFeed {\n runs: RunRecord[] | null;\n error: string | null;\n reload: () => void;\n}\n\nexport function useRuns(scope: RunsScope): RunsFeed {\n const { workflowId, driveId, limit } = scope;\n const [runs, setRuns] = useState<RunRecord[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n // Lets reload() run against the current scope without re-subscribing.\n const load = useRef<() => void>(() => undefined);\n\n useEffect(() => {\n let cancelled = false;\n const run = () => {\n fetchRuns({ workflowId, driveId, limit }).then(\n (result) => {\n if (cancelled) return;\n setRuns(result);\n setError(null);\n },\n (loadError: unknown) => {\n if (cancelled) return;\n setError(\n loadError instanceof Error ? loadError.message : String(loadError),\n );\n },\n );\n };\n load.current = run;\n // A scope change makes the previous rows the wrong rows.\n setRuns(null);\n run();\n const timer = setInterval(run, POLL_MS);\n return () => {\n cancelled = true;\n clearInterval(timer);\n };\n }, [workflowId, driveId, limit]);\n\n const reload = useCallback(() => load.current(), []);\n return { runs, error, reload };\n}\n","// Flattens a workflow's graph into the order a run walks it, so the studio\n// can show the shape of a workflow without drawing the canvas.\nimport { portRank } from \"../../workflow-editor/ui/ap-layout.js\";\n\nexport interface OutlineStep {\n id: string;\n key: string;\n name: string;\n blockType: string;\n}\n\nexport interface OutlineEdge {\n from: string;\n to: string;\n port: string;\n}\n\nexport interface OutlineRow {\n step: OutlineStep;\n // The port that led here; null on the entry step and on \"next\".\n port: string | null;\n}\n\nexport interface StepOutline {\n rows: OutlineRow[];\n // Authored but unreachable from the trigger, so no run ever executes them.\n orphans: OutlineStep[];\n}\n\nexport function stepOutline(args: {\n triggerId?: string | null;\n steps: readonly OutlineStep[];\n edges: readonly OutlineEdge[];\n}): StepOutline {\n const stepById = new Map(args.steps.map((step) => [step.id, step]));\n const outgoing = new Map<string, OutlineEdge[]>();\n for (const edge of args.edges) {\n if (!stepById.has(edge.to)) continue;\n const list = outgoing.get(edge.from) ?? [];\n list.push(edge);\n outgoing.set(edge.from, list);\n }\n for (const list of outgoing.values()) {\n list.sort((a, b) => portRank(a.port) - portRank(b.port));\n }\n\n const rows: OutlineRow[] = [];\n const seen = new Set<string>();\n // Depth-first so a branch reads as a continuous path, as it runs.\n const walk = (fromId: string, port: string | null) => {\n const step = stepById.get(fromId);\n if (step) {\n if (seen.has(fromId)) return;\n seen.add(fromId);\n rows.push({ step, port: port === \"next\" ? null : port });\n }\n for (const edge of outgoing.get(fromId) ?? []) {\n walk(edge.to, edge.port);\n }\n };\n if (args.triggerId) walk(args.triggerId, null);\n\n return {\n rows,\n orphans: args.steps.filter((step) => !seen.has(step.id)),\n };\n}\n","// The workflow's shape as a pipeline: trigger, then each step in the order a\n// run walks it, annotated with how that step fared in the latest run.\nimport type { WorkflowState } from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { useState } from \"react\";\nimport {\n blockMeta,\n usePieceLogos,\n} from \"../../workflow-editor/ui/block-meta.js\";\nimport { RUN_DOT } from \"./run-format.js\";\nimport { stepOutline, type OutlineStep } from \"./step-outline.js\";\n\nconst STEP_DOT: Record<string, string> = {\n ...RUN_DOT,\n SKIPPED: \"bg-slate-300\",\n REPLAYED: \"bg-sky-400\",\n};\n\n// The piece logo, degrading to the block glyph when absent or unloadable.\nfunction ChipLogo(props: { logoUrl?: string; glyph?: string }) {\n const [broken, setBroken] = useState(false);\n if (props.logoUrl && !broken) {\n return (\n <img\n src={props.logoUrl}\n alt=\"\"\n className=\"h-4 w-4 shrink-0\"\n onError={() => setBroken(true)}\n />\n );\n }\n return (\n <span className=\"w-4 shrink-0 text-center text-xs text-slate-400\">\n {props.glyph ?? \"▪\"}\n </span>\n );\n}\n\nfunction Chip(props: {\n title: string;\n subtitle: string;\n glyph?: string;\n logoUrl?: string;\n status?: string;\n muted?: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n title={\n props.status ? `${props.subtitle} · ${props.status}` : props.subtitle\n }\n className={`flex max-w-56 items-center gap-2 rounded border border-solid px-2 py-1 text-left hover:border-slate-400 ${\n props.muted\n ? \"border-dashed border-slate-300 bg-slate-50\"\n : \"border-slate-200 bg-white\"\n }`}\n onClick={props.onClick}\n >\n <ChipLogo logoUrl={props.logoUrl} glyph={props.glyph} />\n <span className=\"min-w-0\">\n <span className=\"block truncate text-xs font-medium text-slate-700\">\n {props.title}\n </span>\n <span className=\"block truncate text-[11px] text-slate-400\">\n {props.subtitle}\n </span>\n </span>\n {props.status ? (\n <span\n className={`ml-1 h-2 w-2 shrink-0 rounded-full ${STEP_DOT[props.status] ?? \"bg-slate-300\"}`}\n />\n ) : null}\n </button>\n );\n}\n\nfunction Arrow(props: { port: string | null }) {\n return (\n <span className=\"flex shrink-0 items-center gap-1 text-slate-300\">\n <span aria-hidden>→</span>\n {props.port ? (\n <span className=\"rounded bg-slate-100 px-1 text-[10px] text-slate-500\">\n {props.port}\n </span>\n ) : null}\n </span>\n );\n}\n\nexport function WorkflowSteps(props: {\n state: WorkflowState;\n latestRun?: RunRecord;\n onOpenEditor: () => void;\n}) {\n const { state } = props;\n // Piece logos arrive with the catalog; re-renders this pipeline once known.\n usePieceLogos();\n const outline = stepOutline({\n triggerId: state.trigger?.id,\n steps: state.steps,\n edges: state.edges,\n });\n // Latest-run outcome per step, so the pipeline shows where a run stopped.\n const statusByKey = new Map(\n (props.latestRun?.steps ?? []).map((step) => [step.stepKey, step.status]),\n );\n\n const chipFor = (step: OutlineStep, muted: boolean) => {\n const meta = blockMeta(step.blockType);\n return (\n <Chip\n key={step.id}\n title={step.name || step.key}\n subtitle={meta.displayName}\n glyph={meta.glyph}\n logoUrl={meta.logoUrl}\n status={statusByKey.get(step.key)}\n muted={muted}\n onClick={props.onOpenEditor}\n />\n );\n };\n\n if (!state.trigger && state.steps.length === 0) {\n return (\n <section className=\"mt-3 rounded-md border border-solid border-slate-200 bg-white px-3 py-4\">\n <p className=\"text-xs text-slate-500\">\n This workflow has no trigger or steps yet.{\" \"}\n <button\n type=\"button\"\n className=\"underline hover:text-slate-800\"\n onClick={props.onOpenEditor}\n >\n Open the editor\n </button>{\" \"}\n to build it.\n </p>\n </section>\n );\n }\n\n const triggerMeta = state.trigger ? blockMeta(state.trigger.blockType) : null;\n\n return (\n <section className=\"mt-3 rounded-md border border-solid border-slate-200 bg-white px-3 py-3\">\n <div className=\"mb-2 flex items-baseline gap-2\">\n <h3 className=\"text-[11px] text-slate-400\">Steps</h3>\n <span className=\"text-[11px] tabular-nums text-slate-400\">\n {state.steps.length}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {triggerMeta && state.trigger ? (\n <Chip\n title={triggerMeta.displayName}\n subtitle=\"Trigger\"\n glyph={triggerMeta.glyph}\n logoUrl={triggerMeta.logoUrl}\n muted={false}\n onClick={props.onOpenEditor}\n />\n ) : (\n <span className=\"rounded border border-dashed border-slate-300 px-2 py-1 text-[11px] text-slate-400\">\n No trigger\n </span>\n )}\n {outline.rows.map((row) => (\n <span key={row.step.id} className=\"flex items-center gap-2\">\n <Arrow port={row.port} />\n {chipFor(row.step, false)}\n </span>\n ))}\n </div>\n {outline.orphans.length > 0 ? (\n <div className=\"mt-3 border-t border-solid border-slate-100 pt-2\">\n <p className=\"mb-2 text-[11px] text-slate-400\">\n Not connected to the trigger, so runs never reach these:\n </p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {outline.orphans.map((step) => chipFor(step, true))}\n </div>\n </div>\n ) : null}\n </section>\n );\n}\n","// Identity, state and the actions for the workflow whose runs are shown:\n// enable/disable, open the editor, delete. Stats come from the shared feed.\nimport {\n showDeleteNodeModal,\n useDispatch,\n useDocumentSafe,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport type { ReactNode } from \"react\";\nimport {\n actions as workflowActions,\n type WorkflowDocument,\n} from \"document-models/workflow\";\nimport type { RunRecord } from \"../../workflow-editor/runtime-api.js\";\nimport { blockMeta } from \"../../workflow-editor/ui/block-meta.js\";\nimport { DocumentLoadError } from \"../../shared/DocumentErrorBoundary.js\";\nimport {\n formatAbsolute,\n formatWhen,\n RUN_DOT,\n RUN_TEXT,\n runStats,\n WORKFLOW_STATUS_STYLES,\n} from \"./run-format.js\";\nimport { WorkflowSteps } from \"./WorkflowSteps.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\n\nconst ACTION =\n \"rounded border border-solid border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 hover:border-slate-400 hover:bg-slate-50\";\n\nfunction Stat(props: { label: string; children: ReactNode }) {\n return (\n <div className=\"min-w-0 grow border-l border-solid border-slate-200 px-3 py-2 first:border-l-0 first:pl-0\">\n <div className=\"text-[11px] text-slate-400\">{props.label}</div>\n <div className=\"truncate text-xs text-slate-800\">{props.children}</div>\n </div>\n );\n}\n\nexport function WorkflowHeader(props: {\n node: FileNode;\n runs: RunRecord[] | null;\n onEdit: () => void;\n}) {\n const workflowId = props.node.id;\n const { data: document, error, reload } = useDocumentSafe(workflowId);\n const [, dispatch] = useDispatch(document);\n\n if (error !== undefined) {\n return (\n <DocumentLoadError\n title=\"This workflow could not be loaded\"\n documentId={workflowId}\n error={error}\n onRetry={() => {\n void reload();\n }}\n />\n );\n }\n if (document?.header.documentType !== WORKFLOW_TYPE) return null;\n\n const workflow = document as WorkflowDocument;\n const state = workflow.state.global;\n const enabled = state.status === \"ENABLED\";\n const stats = runStats(props.runs ?? []);\n const trigger = state.trigger\n ? blockMeta(state.trigger.blockType).displayName\n : null;\n\n return (\n <header className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"min-w-0 truncate text-base font-semibold text-slate-800\">\n {state.name || props.node.name || \"Untitled workflow\"}\n </h2>\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${WORKFLOW_STATUS_STYLES[state.status] ?? \"bg-slate-100 text-slate-500\"}`}\n >\n {state.status}\n </span>\n <span className=\"grow\" />\n <button\n type=\"button\"\n className={ACTION}\n onClick={() =>\n dispatch(\n workflowActions.setWorkflowStatus({\n status: enabled ? \"DISABLED\" : \"ENABLED\",\n }),\n )\n }\n >\n {enabled ? \"Disable\" : \"Enable\"}\n </button>\n <button type=\"button\" className={ACTION} onClick={props.onEdit}>\n Edit workflow\n </button>\n <button\n type=\"button\"\n className=\"rounded border border-solid border-red-200 bg-white px-2.5 py-1 text-xs font-medium text-red-600 hover:border-red-300 hover:bg-red-50\"\n // The host modal confirms; the studio drops the target once the\n // node leaves the drive.\n onClick={() => showDeleteNodeModal(props.node)}\n >\n Delete\n </button>\n </div>\n {state.description ? (\n <p className=\"mt-1 max-w-2xl text-xs text-slate-500\">\n {state.description}\n </p>\n ) : null}\n <div className=\"mt-3 flex flex-wrap items-stretch rounded-md border border-solid border-slate-200 bg-white px-3\">\n <Stat label=\"Trigger\">\n {trigger ?? <span className=\"text-slate-400\">None set</span>}\n </Stat>\n <Stat label=\"Last run\">\n {stats.lastRun ? (\n <span\n className=\"flex items-center gap-1.5\"\n title={formatAbsolute(stats.lastRun.startedAt)}\n >\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${RUN_DOT[stats.lastRun.status] ?? \"bg-slate-300\"}`}\n />\n <span className={RUN_TEXT[stats.lastRun.status] ?? \"\"}>\n {formatWhen(stats.lastRun.startedAt)}\n </span>\n </span>\n ) : (\n <span className=\"text-slate-400\">Never run</span>\n )}\n </Stat>\n <Stat label=\"Recent runs\">\n <span className=\"tabular-nums\">\n {stats.total}\n {stats.failed > 0 ? (\n <span className=\"text-red-600\"> · {stats.failed} failed</span>\n ) : null}\n {stats.running > 0 ? (\n <span className=\"text-amber-700\"> · {stats.running} running</span>\n ) : null}\n </span>\n </Stat>\n <Stat label=\"Success rate\">\n {stats.successRate === null ? (\n <span className=\"text-slate-400\">—</span>\n ) : (\n <span className=\"tabular-nums\">{stats.successRate}%</span>\n )}\n </Stat>\n <Stat label=\"Version\">\n <span className=\"tabular-nums\">v{state.version}</span>\n </Stat>\n </div>\n <WorkflowSteps\n state={state}\n latestRun={stats.lastRun}\n onOpenEditor={props.onEdit}\n />\n </header>\n );\n}\n","// Workflow Studio: drive app listing workflows and connections with a\n// GitHub-Actions-style run journal; opens the per-document editors inline.\nimport {\n addDocument,\n setSelectedNode,\n useDocumentSafe,\n useFileNodesInSelectedDrive,\n usePHToast,\n useSelectedDrive,\n useSelectedNode,\n} from \"@powerhousedao/reactor-browser\";\nimport type { FileNode } from \"@powerhousedao/shared/document-drive\";\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { type WorkflowDocument } from \"document-models/workflow\";\nimport { fireWorkflow } from \"../../workflow-editor/runtime-api.js\";\nimport \"../../workflow-editor/runtime-piece-source.js\";\nimport { DocumentErrorBoundary } from \"../../shared/DocumentErrorBoundary.js\";\nimport { EditorToolbar } from \"./EditorToolbar.js\";\nimport { ConnectionView } from \"./ConnectionView.js\";\nimport { RunsView } from \"./RunsView.js\";\nimport { Sidebar } from \"./Sidebar.js\";\nimport { useHashSelection } from \"./use-hash-selection.js\";\nimport { useRuns } from \"./useRuns.js\";\nimport { WorkflowHeader } from \"./WorkflowHeader.js\";\n\nconst WORKFLOW_TYPE = \"powerhouse/workflow\";\nconst CONNECTION_TYPE = \"powerhouse/connection\";\n\nexport function WorkflowStudio(props: { children?: ReactNode }) {\n const [drive] = useSelectedDrive();\n const fileNodes = useFileNodesInSelectedDrive() ?? [];\n const selectedNode = useSelectedNode();\n const selectedNodeId = selectedNode?.id;\n const toast = usePHToast();\n // The sidebar selection, kept in the URL hash; undefined = all runs.\n const [selectedId, select] = useHashSelection();\n const [creating, setCreating] = useState(false);\n\n const driveId = drive.header.id;\n const workflows = fileNodes.filter(\n (node) => node.documentType === WORKFLOW_TYPE,\n );\n const connections = fileNodes.filter(\n (node) => node.documentType === CONNECTION_TYPE,\n );\n const editorOpen = Boolean(props.children && selectedNodeId);\n\n const create = (documentType: string, baseName: string, count: number) => {\n if (creating) return;\n setCreating(true);\n addDocument(driveId, `${baseName} ${count + 1}`, documentType)\n .then((node) => {\n select(node.id);\n setSelectedNode(node.id);\n })\n .catch((error: unknown) => {\n toast?.(\n error instanceof Error\n ? error.message\n : `Failed to create ${baseName}`,\n { type: \"error\" },\n );\n })\n .finally(() => setCreating(false));\n };\n\n const showRuns = (node: FileNode | null) => {\n setSelectedNode(undefined);\n select(node?.id);\n };\n\n // Resolved from the drive each render, so a deleted node drops out on its own.\n const liveTarget = workflows.find((node) => node.id === selectedId) ?? null;\n const liveConnection =\n connections.find((node) => node.id === selectedId) ?? null;\n const openNode = fileNodes.find((node) => node.id === selectedNodeId);\n // A deleted node must not keep the hash pointing at nothing.\n const selectionExists = fileNodes.some((node) => node.id === selectedId);\n useEffect(() => {\n if (selectedId && fileNodes.length > 0 && !selectionExists)\n select(undefined);\n }, [fileNodes.length, select, selectedId, selectionExists]);\n const editedWorkflow = editorOpen\n ? (workflows.find((node) => node.id === selectedNodeId) ?? null)\n : null;\n // One feed per pane, shared by the header, the table and the toolbar: the\n // focused workflow's runs, or every run in this drive.\n const focusedWorkflow = editedWorkflow ?? liveTarget;\n const {\n runs,\n error: runsError,\n reload: reloadRuns,\n } = useRuns({\n workflowId: focusedWorkflow?.id,\n driveId: focusedWorkflow ? undefined : driveId,\n });\n\n // Manual fire only makes sense for core#manual triggers.\n const { data: targetDocument } = useDocumentSafe(liveTarget?.id ?? null);\n const manualTrigger =\n targetDocument?.header.documentType === WORKFLOW_TYPE &&\n (targetDocument as WorkflowDocument).state.global.trigger?.blockType ===\n \"core#manual\";\n\n return (\n <div className=\"flex h-full min-h-0\">\n <Sidebar\n workflows={workflows}\n connections={connections}\n activeId={selectedId}\n allRunsActive={!selectedId}\n creating={creating}\n onShowAllRuns={() => showRuns(null)}\n onOpenWorkflow={(node) => showRuns(node)}\n onEditWorkflow={(node) => {\n select(node.id);\n setSelectedNode(node.id);\n }}\n onOpenConnection={(node) => showRuns(node)}\n onEditConnection={(node) => {\n select(node.id);\n setSelectedNode(node.id);\n }}\n onCreateWorkflow={() =>\n create(WORKFLOW_TYPE, \"Workflow\", workflows.length)\n }\n onCreateConnection={() =>\n create(CONNECTION_TYPE, \"Connection\", connections.length)\n }\n />\n <main className=\"min-w-0 flex-1 overflow-y-auto\">\n {editorOpen ? (\n <div className=\"flex h-full min-h-0 flex-col\">\n <EditorToolbar\n node={openNode}\n runs={editedWorkflow ? runs : null}\n onBack={() => setSelectedNode(undefined)}\n />\n <div className=\"flex min-h-0 flex-1 flex-col [&>#document-editor-container]:min-h-0\">\n <DocumentErrorBoundary\n key={selectedNodeId}\n documentId={selectedNodeId}\n label={selectedNode?.name}\n onDismiss={() => setSelectedNode(undefined)}\n >\n {props.children}\n </DocumentErrorBoundary>\n </div>\n </div>\n ) : liveConnection ? (\n <ConnectionView\n key={liveConnection.id}\n node={liveConnection}\n onEdit={() => {\n select(liveConnection.id);\n setSelectedNode(liveConnection.id);\n }}\n onOpenWorkflow={(workflowId) => select(workflowId)}\n />\n ) : (\n <div className=\"mx-auto w-full max-w-5xl p-6\">\n {liveTarget ? (\n <WorkflowHeader\n key={liveTarget.id}\n node={liveTarget}\n runs={runs}\n onEdit={() => setSelectedNode(liveTarget.id)}\n />\n ) : null}\n <RunsView\n // The header already names the workflow; don't say it twice.\n title={liveTarget ? \"Runs\" : \"All runs in this drive\"}\n runs={runs}\n error={runsError}\n reload={reloadRuns}\n showWorkflow={liveTarget === null}\n onFire={\n liveTarget && manualTrigger\n ? () =>\n fireWorkflow(liveTarget.id).then((result) => result.error)\n : undefined\n }\n />\n </div>\n )}\n </main>\n </div>\n );\n}\n","import type { PHAppConfig } from \"@powerhousedao/reactor-browser\";\n\nexport const editorConfig: PHAppConfig = {\n isDragAndDropEnabled: true,\n allowedDocumentTypes: [\"powerhouse/workflow\", \"powerhouse/connection\"],\n};\n","/**\n * WARNING: DO NOT EDIT\n * This file is auto-generated and updated by codegen\n */\nimport { useSetPHAppConfig } from \"@powerhousedao/reactor-browser\";\nimport type { EditorProps } from \"document-model\";\nimport { useSyncWorkflowRuntimeUrl } from \"../workflow-editor/use-runtime-url.js\";\nimport { WorkflowStudio } from \"./components/WorkflowStudio.js\";\nimport { editorConfig } from \"./config.js\";\n\n/** Editor component for the app */\nexport default function Editor(props: EditorProps) {\n useSetPHAppConfig(editorConfig);\n useSyncWorkflowRuntimeUrl();\n return (\n <div className=\"h-full min-h-0 bg-background\">\n <WorkflowStudio>{props.children}</WorkflowStudio>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { E as packageFromConnectorId, s as fetchPieceCatalog } from "./runtime-api-JQ6lSS1Y.mjs";
|
|
2
2
|
import { i as useSelectedConnectionDocument } from "./connection-DGsS2Db3.mjs";
|
|
3
|
-
import { n as DocumentErrorBoundary, t as useSyncWorkflowRuntimeUrl } from "./use-runtime-url-
|
|
3
|
+
import { n as DocumentErrorBoundary, t as useSyncWorkflowRuntimeUrl } from "./use-runtime-url-BOooH4kU.mjs";
|
|
4
4
|
import { r as connectionCallbacks, t as ConnectionForm } from "./connection-form-CTNkgu_d.mjs";
|
|
5
5
|
import { t as CONNECTION_STATUS_STYLES } from "./status-CDRcDUMS.mjs";
|
|
6
6
|
import { showDeleteNodeModal, useSelectedDocumentId } from "@powerhousedao/reactor-browser";
|
|
@@ -131,4 +131,4 @@ function Editor() {
|
|
|
131
131
|
//#endregion
|
|
132
132
|
export { Editor as default };
|
|
133
133
|
|
|
134
|
-
//# sourceMappingURL=editor-
|
|
134
|
+
//# sourceMappingURL=editor-sBw5dTYS.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-
|
|
1
|
+
{"version":3,"file":"editor-sBw5dTYS.mjs","names":[],"sources":["../../editors/connection-editor/ConnectionToolbar.tsx","../../editors/connection-editor/editor.tsx"],"sourcesContent":["// Connection identity and state, in the same shape as the workflow editor's\n// toolbar: name, connector, status, and the one destructive action.\nimport { useEffect, useState } from \"react\";\nimport type { ConnectionState } from \"document-models/connection\";\nimport {\n fetchPieceCatalog,\n type PieceSummary,\n} from \"../workflow-editor/runtime-api.js\";\nimport { packageFromConnectorId } from \"./piece-auth.js\";\nimport { CONNECTION_STATUS_STYLES } from \"./status.js\";\n\nexport function ConnectionToolbar(props: {\n state: ConnectionState;\n onRename: (name: string) => void;\n onSetStatus: (status: \"OK\" | \"REVOKED\") => void;\n onDelete: () => void;\n}) {\n const { state } = props;\n const [catalog, setCatalog] = useState<PieceSummary[] | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n // Cached in the runtime client, so this costs nothing the form hasn't paid.\n fetchPieceCatalog().then(\n (pieces) => {\n if (!cancelled) setCatalog(pieces);\n },\n () => {\n if (!cancelled) setCatalog([]);\n },\n );\n return () => {\n cancelled = true;\n };\n }, []);\n\n const packageName = packageFromConnectorId(state.connectorId);\n const piece = catalog?.find((entry) => entry.name === packageName);\n const revoked = state.status === \"REVOKED\";\n\n return (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-solid border-slate-200 px-4 py-2\">\n <input\n key={state.name}\n className=\"min-w-0 max-w-72 rounded border border-transparent px-1 py-0.5 text-sm font-semibold text-slate-800 hover:border-slate-200 focus:border-slate-300 focus:outline-none\"\n defaultValue={state.name}\n placeholder=\"Untitled connection\"\n spellCheck={false}\n aria-label=\"Connection name\"\n onKeyDown={(event) => {\n if (event.key === \"Enter\") event.currentTarget.blur();\n }}\n onBlur={(event) => {\n const name = event.target.value.trim();\n if (name && name !== state.name) props.onRename(name);\n }}\n />\n {piece ? (\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <img\n src={piece.logoUrl}\n alt=\"\"\n className=\"h-4 w-4 shrink-0 object-contain\"\n />\n <span className=\"truncate text-xs text-slate-600\">\n {piece.displayName}\n </span>\n </span>\n ) : packageName ? (\n <span className=\"truncate text-xs text-slate-400\">{packageName}</span>\n ) : (\n <span className=\"text-xs text-slate-400\">No connector picked</span>\n )}\n <span\n className={`rounded px-2 py-0.5 text-[11px] font-semibold ${CONNECTION_STATUS_STYLES[state.status]}`}\n >\n {state.status}\n </span>\n {state.accountLabel ? (\n <span className=\"truncate text-xs text-slate-500\">\n {state.accountLabel}\n </span>\n ) : null}\n <span className=\"ml-auto flex items-center gap-3\">\n {state.lastCheckedAt ? (\n <span\n className=\"text-[11px] text-slate-400\"\n title={new Date(state.lastCheckedAt).toLocaleString()}\n >\n Checked {new Date(state.lastCheckedAt).toLocaleDateString()}\n </span>\n ) : (\n <span className=\"text-[11px] text-slate-400\">Never checked</span>\n )}\n <button\n type=\"button\"\n className=\"rounded border border-solid border-slate-300 bg-white px-2 py-1 text-xs font-medium text-slate-700 hover:border-slate-400 hover:bg-slate-50\"\n onClick={() => props.onSetStatus(revoked ? \"OK\" : \"REVOKED\")}\n >\n {revoked ? \"Reactivate\" : \"Revoke\"}\n </button>\n <button\n type=\"button\"\n className=\"rounded border border-solid border-red-200 bg-white px-2 py-1 text-xs font-medium text-red-600 hover:border-red-300 hover:bg-red-50\"\n onClick={props.onDelete}\n >\n Delete\n </button>\n </span>\n </div>\n );\n}\n","import { DocumentToolbar } from \"@powerhousedao/design-system/connect\";\nimport {\n showDeleteNodeModal,\n useSelectedDocumentId,\n} from \"@powerhousedao/reactor-browser\";\nimport { useSelectedConnectionDocument } from \"document-models/connection\";\nimport { DocumentErrorBoundary } from \"../shared/DocumentErrorBoundary.js\";\nimport { useSyncWorkflowRuntimeUrl } from \"../workflow-editor/use-runtime-url.js\";\nimport { connectionCallbacks } from \"./connection-callbacks.js\";\nimport { ConnectionForm } from \"./connection-form.js\";\nimport { ConnectionToolbar } from \"./ConnectionToolbar.js\";\n\nfunction ConnectionEditor() {\n useSyncWorkflowRuntimeUrl();\n const [document, dispatch] = useSelectedConnectionDocument();\n const state = document.state.global;\n\n const callbacks = connectionCallbacks(state, dispatch);\n\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <DocumentToolbar />\n <ConnectionToolbar\n state={state}\n onRename={callbacks.setName}\n onSetStatus={callbacks.setStatus}\n onDelete={() => showDeleteNodeModal(document.header.id)}\n />\n <div className=\"mx-auto w-full max-w-2xl p-6\">\n <ConnectionForm state={state} callbacks={callbacks} />\n </div>\n </div>\n );\n}\n\n// A drive node can point at a document the reactor cannot serve; the document\n// hooks throw for it. The boundary keeps that failure inside the editor pane.\nexport default function Editor() {\n const documentId = useSelectedDocumentId();\n return (\n <DocumentErrorBoundary documentId={documentId}>\n <ConnectionEditor />\n </DocumentErrorBoundary>\n );\n}\n"],"mappings":";;;;;;;;;;AAWA,SAAgB,kBAAkB,OAK/B;CACD,MAAM,EAAE,UAAU;CAClB,MAAM,CAAC,SAAS,cAAc,SAAgC,KAAK;AAEnE,iBAAgB;EACd,IAAI,YAAY;AAEhB,qBAAmB,CAAC,MACjB,WAAW;AACV,OAAI,CAAC,UAAW,YAAW,OAAO;WAE9B;AACJ,OAAI,CAAC,UAAW,YAAW,EAAE,CAAC;IAEjC;AACD,eAAa;AACX,eAAY;;IAEb,EAAE,CAAC;CAEN,MAAM,cAAc,uBAAuB,MAAM,YAAY;CAC7D,MAAM,QAAQ,SAAS,MAAM,UAAU,MAAM,SAAS,YAAY;CAClE,MAAM,UAAU,MAAM,WAAW;AAEjC,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,SAAD;IAEE,WAAU;IACV,cAAc,MAAM;IACpB,aAAY;IACZ,YAAY;IACZ,cAAW;IACX,YAAY,UAAU;AACpB,SAAI,MAAM,QAAQ,QAAS,OAAM,cAAc,MAAM;;IAEvD,SAAS,UAAU;KACjB,MAAM,OAAO,MAAM,OAAO,MAAM,MAAM;AACtC,SAAI,QAAQ,SAAS,MAAM,KAAM,OAAM,SAAS,KAAK;;IAEvD,EAbK,MAAM,KAaX;GACD,QACC,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,oBAAC,OAAD;KACE,KAAK,MAAM;KACX,KAAI;KACJ,WAAU;KACV,CAAA,EACF,oBAAC,QAAD;KAAM,WAAU;eACb,MAAM;KACF,CAAA,CACF;QACL,cACF,oBAAC,QAAD;IAAM,WAAU;cAAmC;IAAmB,CAAA,GAEtE,oBAAC,QAAD;IAAM,WAAU;cAAyB;IAA0B,CAAA;GAErE,oBAAC,QAAD;IACE,WAAW,iDAAiD,yBAAyB,MAAM;cAE1F,MAAM;IACF,CAAA;GACN,MAAM,eACL,oBAAC,QAAD;IAAM,WAAU;cACb,MAAM;IACF,CAAA,GACL;GACJ,qBAAC,QAAD;IAAM,WAAU;cAAhB;KACG,MAAM,gBACL,qBAAC,QAAD;MACE,WAAU;MACV,OAAO,IAAI,KAAK,MAAM,cAAc,CAAC,gBAAgB;gBAFvD,CAGC,YACU,IAAI,KAAK,MAAM,cAAc,CAAC,oBAAoB,CACtD;UAEP,oBAAC,QAAD;MAAM,WAAU;gBAA6B;MAAoB,CAAA;KAEnE,oBAAC,UAAD;MACE,MAAK;MACL,WAAU;MACV,eAAe,MAAM,YAAY,UAAU,OAAO,UAAU;gBAE3D,UAAU,eAAe;MACnB,CAAA;KACT,oBAAC,UAAD;MACE,MAAK;MACL,WAAU;MACV,SAAS,MAAM;gBAChB;MAEQ,CAAA;KACJ;;GACH;;;;;ACjGV,SAAS,mBAAmB;AAC1B,4BAA2B;CAC3B,MAAM,CAAC,UAAU,YAAY,+BAA+B;CAC5D,MAAM,QAAQ,SAAS,MAAM;CAE7B,MAAM,YAAY,oBAAoB,OAAO,SAAS;AAEtD,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,iBAAD,EAAmB,CAAA;GACnB,oBAAC,mBAAD;IACS;IACP,UAAU,UAAU;IACpB,aAAa,UAAU;IACvB,gBAAgB,oBAAoB,SAAS,OAAO,GAAG;IACvD,CAAA;GACF,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,gBAAD;KAAuB;KAAkB;KAAa,CAAA;IAClD,CAAA;GACF;;;AAMV,SAAwB,SAAS;AAE/B,QACE,oBAAC,uBAAD;EAAuB,YAFN,uBAAuB;YAGtC,oBAAC,kBAAD,EAAoB,CAAA;EACE,CAAA"}
|
|
@@ -2,7 +2,7 @@ import { lazy } from "react";
|
|
|
2
2
|
//#region editors/connection-editor/module.ts
|
|
3
3
|
/** Document editor module for the "powerhouse/connection" document type */
|
|
4
4
|
const ConnectionEditor = {
|
|
5
|
-
Component: lazy(() => import("../../editor-
|
|
5
|
+
Component: lazy(() => import("../../editor-sBw5dTYS.mjs")),
|
|
6
6
|
documentTypes: ["powerhouse/connection"],
|
|
7
7
|
config: {
|
|
8
8
|
id: "connection-editor",
|