@burdenoff/microfe-cosmicintersection 2026.805.1 → 2026.830.1

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.
Files changed (86) hide show
  1. package/dist/cosmicintersection/api/cosmicApi.d.ts +84 -2
  2. package/dist/cosmicintersection/api/cosmicApi.d.ts.map +1 -1
  3. package/dist/cosmicintersection/api/cosmicApi.js +135 -79
  4. package/dist/cosmicintersection/api/cosmicApi.js.map +1 -1
  5. package/dist/cosmicintersection/components/ActionMenu.d.ts +1 -1
  6. package/dist/cosmicintersection/components/ActionMenu.d.ts.map +1 -1
  7. package/dist/cosmicintersection/components/ActionMenu.js +51 -54
  8. package/dist/cosmicintersection/components/ActionMenu.js.map +1 -1
  9. package/dist/cosmicintersection/components/EntityFormShell.d.ts +1 -1
  10. package/dist/cosmicintersection/components/EntityFormShell.d.ts.map +1 -1
  11. package/dist/cosmicintersection/components/EntityFormShell.js +29 -27
  12. package/dist/cosmicintersection/components/EntityFormShell.js.map +1 -1
  13. package/dist/cosmicintersection/components/ErrorState.d.ts +1 -1
  14. package/dist/cosmicintersection/components/ErrorState.d.ts.map +1 -1
  15. package/dist/cosmicintersection/components/ErrorState.js +19 -17
  16. package/dist/cosmicintersection/components/ErrorState.js.map +1 -1
  17. package/dist/cosmicintersection/components/FileUploadField.d.ts.map +1 -1
  18. package/dist/cosmicintersection/components/FileUploadField.js +61 -60
  19. package/dist/cosmicintersection/components/FileUploadField.js.map +1 -1
  20. package/dist/cosmicintersection/components/LineageGraph.d.ts +6 -1
  21. package/dist/cosmicintersection/components/LineageGraph.d.ts.map +1 -1
  22. package/dist/cosmicintersection/components/LineageGraph.js.map +1 -1
  23. package/dist/cosmicintersection/components/LoadingState.d.ts +1 -1
  24. package/dist/cosmicintersection/components/LoadingState.d.ts.map +1 -1
  25. package/dist/cosmicintersection/components/LoadingState.js +15 -13
  26. package/dist/cosmicintersection/components/LoadingState.js.map +1 -1
  27. package/dist/cosmicintersection/components/PageLayout.d.ts.map +1 -1
  28. package/dist/cosmicintersection/components/PageLayout.js +28 -27
  29. package/dist/cosmicintersection/components/PageLayout.js.map +1 -1
  30. package/dist/cosmicintersection/components/Pagination.d.ts.map +1 -1
  31. package/dist/cosmicintersection/components/Pagination.js +38 -35
  32. package/dist/cosmicintersection/components/Pagination.js.map +1 -1
  33. package/dist/cosmicintersection/components/StatusBadge.d.ts.map +1 -1
  34. package/dist/cosmicintersection/components/StatusBadge.js +30 -9
  35. package/dist/cosmicintersection/components/StatusBadge.js.map +1 -1
  36. package/dist/cosmicintersection/components/StepDAG.d.ts.map +1 -1
  37. package/dist/cosmicintersection/components/StepDAG.js +22 -18
  38. package/dist/cosmicintersection/components/StepDAG.js.map +1 -1
  39. package/dist/cosmicintersection/pages/access/AccessPage.d.ts.map +1 -1
  40. package/dist/cosmicintersection/pages/access/AccessPage.js +147 -146
  41. package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
  42. package/dist/cosmicintersection/pages/analyses/AnalysesPage.d.ts.map +1 -1
  43. package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +260 -259
  44. package/dist/cosmicintersection/pages/analyses/AnalysesPage.js.map +1 -1
  45. package/dist/cosmicintersection/pages/collections/CollectionsPage.d.ts.map +1 -1
  46. package/dist/cosmicintersection/pages/collections/CollectionsPage.js +80 -65
  47. package/dist/cosmicintersection/pages/collections/CollectionsPage.js.map +1 -1
  48. package/dist/cosmicintersection/pages/dashboard/DashboardPage.d.ts.map +1 -1
  49. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +132 -131
  50. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -1
  51. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.d.ts.map +1 -1
  52. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +212 -164
  53. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
  54. package/dist/cosmicintersection/pages/datasets/DatasetsPage.d.ts.map +1 -1
  55. package/dist/cosmicintersection/pages/datasets/DatasetsPage.js +178 -177
  56. package/dist/cosmicintersection/pages/datasets/DatasetsPage.js.map +1 -1
  57. package/dist/cosmicintersection/pages/discovery/DiscoveryPage.d.ts.map +1 -1
  58. package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js +138 -145
  59. package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js.map +1 -1
  60. package/dist/cosmicintersection/pages/lineage/LineagePage.d.ts.map +1 -1
  61. package/dist/cosmicintersection/pages/lineage/LineagePage.js +78 -88
  62. package/dist/cosmicintersection/pages/lineage/LineagePage.js.map +1 -1
  63. package/dist/cosmicintersection/pages/notebooks/NotebooksPage.d.ts.map +1 -1
  64. package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js +125 -124
  65. package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js.map +1 -1
  66. package/dist/cosmicintersection/pages/pipelines/PipelinesPage.d.ts.map +1 -1
  67. package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js +152 -151
  68. package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js.map +1 -1
  69. package/dist/cosmicintersection/pages/releases/ReleasesPage.d.ts.map +1 -1
  70. package/dist/cosmicintersection/pages/releases/ReleasesPage.js +175 -174
  71. package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
  72. package/dist/cosmicintersection/pages/runs/RunDetailPage.d.ts.map +1 -1
  73. package/dist/cosmicintersection/pages/runs/RunDetailPage.js +252 -118
  74. package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
  75. package/dist/cosmicintersection/pages/runs/RunsPage.d.ts.map +1 -1
  76. package/dist/cosmicintersection/pages/runs/RunsPage.js +197 -188
  77. package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -1
  78. package/dist/cosmicintersection/pages/sources/SourcesPage.d.ts.map +1 -1
  79. package/dist/cosmicintersection/pages/sources/SourcesPage.js +65 -64
  80. package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -1
  81. package/dist/dev/main.d.ts.map +1 -1
  82. package/dist/shared/hooks/useTr.d.ts +12 -0
  83. package/dist/shared/hooks/useTr.d.ts.map +1 -0
  84. package/dist/shared/hooks/useTr.js +16 -0
  85. package/dist/shared/hooks/useTr.js.map +1 -0
  86. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RunDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/runs/RunDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport type { LucideIcon } from 'lucide-react';\nimport { Check, Circle, ListTree, Loader2, Plus, X } from 'lucide-react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAddRunStepMutation,\n useCosRunQuery,\n useCosRunStepsQuery,\n useCosTransitionRunMutation,\n type CosRunStatus,\n type CosStepKind,\n} from '../../api/cosmicApi';\nimport {\n ActivityFeedPanel,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\n\nconst STEP_KIND_OPTIONS: CosStepKind[] = [\n 'INGEST',\n 'CALIBRATE',\n 'TRANSFORM',\n 'ANALYZE',\n 'EXPORT',\n 'NOTIFY',\n];\n\n// Valid forward transitions for the run state machine. Terminal states have none.\nconst NEXT_STATUSES: Record<CosRunStatus, CosRunStatus[]> = {\n QUEUED: ['RUNNING', 'CANCELLED'],\n RUNNING: ['SUCCEEDED', 'FAILED', 'CANCELLED'],\n SUCCEEDED: [],\n FAILED: [],\n CANCELLED: [],\n};\n\n// Per-status timeline node: the icon rendered inside the spine circle + its\n// tone classes. Colour comes only from the semantic status token families.\nconst STEP_NODE: Record<CosRunStatus, { icon: LucideIcon; spin: boolean; wrap: string }> = {\n SUCCEEDED: {\n icon: Check,\n spin: false,\n wrap: 'border-status-success-border bg-status-success-bg-subtle text-status-success-text',\n },\n RUNNING: {\n icon: Loader2,\n spin: true,\n wrap: 'border-status-warning-border bg-status-warning-bg-subtle text-status-warning-text',\n },\n FAILED: {\n icon: X,\n spin: false,\n wrap: 'border-status-error-border bg-status-error-bg-subtle text-status-error-text',\n },\n QUEUED: {\n icon: Circle,\n spin: false,\n wrap: 'border-status-info-border bg-status-info-bg-subtle text-status-info-text',\n },\n CANCELLED: {\n icon: X,\n spin: false,\n wrap: 'border-border-default bg-bg-sunken text-text-secondary',\n },\n};\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction formatDuration(ms?: number | null): string {\n if (ms === null || ms === undefined) {\n return '—';\n }\n if (ms < 1000) {\n return `${ms} ms`;\n }\n const seconds = ms / 1000;\n if (seconds < 60) {\n return `${seconds.toFixed(1)} s`;\n }\n const minutes = Math.floor(seconds / 60);\n const rest = Math.round(seconds % 60);\n return `${minutes}m ${rest}s`;\n}\n\nfunction DetailRow({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1 border-b border-border-seam py-3 last:border-0 sm:flex-row sm:items-start sm:gap-4\">\n <span className=\"w-40 shrink-0 text-sm font-medium text-text-secondary\">{label}</span>\n <span className=\"min-w-0 text-sm text-text-primary\">{children}</span>\n </div>\n );\n}\n\nfunction JsonBlock({ value }: { value?: Record<string, unknown> | null }) {\n if (!value || Object.keys(value).length === 0) {\n return <span className=\"text-sm text-text-secondary\">—</span>;\n }\n return (\n <pre className=\"overflow-x-auto rounded-card border border-border-default bg-bg-sunken p-3 font-mono text-xs text-text-primary\">\n {JSON.stringify(value, null, 2)}\n </pre>\n );\n}\n\nexport default function RunDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosRunQuery(id);\n const {\n data: stepsData,\n loading: stepsLoading,\n error: stepsError,\n refetch: refetchSteps,\n } = useCosRunStepsQuery(id);\n\n const [transitionRun, { loading: transitioning }] = useCosTransitionRunMutation();\n const [addStep, { loading: addingStep }] = useCosAddRunStepMutation();\n\n const [stepDialogOpen, setStepDialogOpen] = useState(false);\n const [stepName, setStepName] = useState('');\n const [stepKind, setStepKind] = useState<CosStepKind>('INGEST');\n const [stepPosition, setStepPosition] = useState('');\n const [stepInputs, setStepInputs] = useState('');\n\n const run = data?.cosRun;\n const steps = useMemo(\n () => [...(stepsData?.cosListRunSteps ?? [])].sort((a, b) => a.position - b.position),\n [stepsData]\n );\n\n const handleTransition = async (nextStatus: CosRunStatus) => {\n if (!run) {\n return;\n }\n const response = await transitionRun({ variables: { id: run.id, status: nextStatus } });\n if (\n !mutationSucceeded(response, response.data?.cosTransitionRun?.id, 'Could not update the run')\n ) {\n return;\n }\n notify.success('Run updated', `Run #${run.runNumber} moved to ${formatEnumLabel(nextStatus)}.`);\n await Promise.all([refetch(), refetchSteps()]);\n };\n\n const resetStepForm = () => {\n setStepName('');\n setStepKind('INGEST');\n setStepPosition('');\n setStepInputs('');\n };\n\n const handleAddStep = async () => {\n if (!run) {\n return;\n }\n if (!stepName.trim()) {\n notify.error('Step name is required', 'Give the step a name before adding it.');\n return;\n }\n\n let inputs: Record<string, unknown> | undefined;\n if (stepInputs.trim()) {\n try {\n const parsed = JSON.parse(stepInputs.trim()) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('Inputs must be a JSON object.');\n }\n inputs = parsed as Record<string, unknown>;\n } catch (parseError) {\n notify.error(\n 'Invalid inputs JSON',\n describeError(parseError) ?? 'Please provide valid JSON.'\n );\n return;\n }\n }\n\n const positionValue = stepPosition.trim() ? Number(stepPosition.trim()) : undefined;\n if (positionValue !== undefined && (Number.isNaN(positionValue) || positionValue < 0)) {\n notify.error('Invalid position', 'Position must be a non-negative number.');\n return;\n }\n\n const response = await addStep({\n variables: {\n input: {\n runId: run.id,\n name: stepName.trim(),\n kind: stepKind,\n inputs,\n position: positionValue,\n },\n },\n });\n if (!mutationSucceeded(response, response.data?.cosAddRunStep?.id, 'Could not add the step')) {\n return;\n }\n notify.success('Step added', `“${stepName.trim()}” was added to the run.`);\n setStepDialogOpen(false);\n resetStepForm();\n await refetchSteps();\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <LoadingState label=\"Loading run…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <ErrorState onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!run) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <EmptyState\n title=\"Run not found\"\n description=\"This run may have been removed or you may not have access to it.\"\n action={\n <Button type=\"button\" variant=\"outline\" onClick={() => navigate('runs')}>\n Back to runs\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const validTransitions = NEXT_STATUSES[run.status] ?? [];\n\n return (\n <PageLayout\n title={`Run #${run.runNumber}`}\n description={run.pipeline ? `Pipeline: ${run.pipeline.name}` : undefined}\n backPath=\"runs\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n {validTransitions.map((next) => (\n <Button\n key={next}\n type=\"button\"\n variant={next === 'CANCELLED' || next === 'FAILED' ? 'outline' : 'default'}\n onClick={() => void handleTransition(next)}\n disabled={transitioning}\n >\n {`Mark ${formatEnumLabel(next)}`}\n </Button>\n ))}\n <Button type=\"button\" variant=\"outline\" onClick={() => setStepDialogOpen(true)}>\n <Plus className=\"size-4\" />\n Add step\n </Button>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Overview</CardTitle>\n </CardHeader>\n <CardContent>\n <DetailRow label=\"Status\">\n <StatusBadge status={run.status} />\n </DetailRow>\n <DetailRow label=\"Pipeline\">\n {run.pipeline ? (\n <button\n type=\"button\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n onClick={() => navigate(`pipelines/${run.pipelineId}`)}\n >\n {run.pipeline.name}\n </button>\n ) : (\n <span className=\"font-mono text-xs\">{run.pipelineId}</span>\n )}\n </DetailRow>\n <DetailRow label=\"Dataset\">\n {run.datasetId ? (\n <button\n type=\"button\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n onClick={() => navigate(`datasets/${run.datasetId}`)}\n >\n <span className=\"font-mono text-xs\">{run.datasetId}</span>\n </button>\n ) : (\n '—'\n )}\n </DetailRow>\n <DetailRow label=\"Triggered by\">{run.triggeredBy || '—'}</DetailRow>\n <DetailRow label=\"Started\">{formatDate(run.startedAt)}</DetailRow>\n <DetailRow label=\"Finished\">{formatDate(run.finishedAt)}</DetailRow>\n <DetailRow label=\"Duration\">{formatDuration(run.durationMs)}</DetailRow>\n {run.errorMessage ? (\n <DetailRow label=\"Error\">\n <span className=\"text-status-error-text\">{run.errorMessage}</span>\n </DetailRow>\n ) : null}\n {validTransitions.length === 0 ? (\n <DetailRow label=\"Discuss\">\n <SafeLink\n href=\"/conversations\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n >\n Open discussions\n </SafeLink>\n </DetailRow>\n ) : null}\n </CardContent>\n </Card>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Parameters</CardTitle>\n </CardHeader>\n <CardContent>\n <JsonBlock value={run.params} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Metrics</CardTitle>\n </CardHeader>\n <CardContent>\n <JsonBlock value={run.metrics} />\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Steps</CardTitle>\n </CardHeader>\n <CardContent>\n {stepsLoading ? (\n <LoadingState variant=\"rows\" rows={4} label=\"Loading steps…\" />\n ) : stepsError ? (\n <ErrorState message=\"Could not load steps.\" onRetry={() => void refetchSteps()} />\n ) : steps.length === 0 ? (\n <EmptyState\n icon={ListTree}\n title=\"No steps yet\"\n description=\"Add steps to record the ingest, calibration, transform, analyze or export stages of this run.\"\n action={\n <Button type=\"button\" onClick={() => setStepDialogOpen(true)}>\n <Plus className=\"size-4\" />\n Add step\n </Button>\n }\n />\n ) : (\n <ol className=\"flex flex-col\">\n {steps.map((step, index) => {\n const node = STEP_NODE[step.status] ?? STEP_NODE.QUEUED;\n const NodeIcon = node.icon;\n const isLast = index === steps.length - 1;\n return (\n <li key={step.id} className=\"flex gap-4\">\n {/* Spine: status node + connecting line to the next step. */}\n <div className=\"flex flex-col items-center\">\n <span\n className={`flex size-8 shrink-0 items-center justify-center rounded-full border ${node.wrap}`}\n >\n <NodeIcon\n className={`size-4 ${node.spin ? 'animate-spin' : ''}`}\n aria-hidden=\"true\"\n />\n </span>\n {!isLast ? (\n <span className=\"w-px flex-1 bg-border-default\" aria-hidden=\"true\" />\n ) : null}\n </div>\n\n <div\n className={`min-w-0 flex-1 rounded-card border border-border-default bg-bg-elevated p-4 ${\n isLast ? '' : 'mb-4'\n }`}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-semibold tabular-nums text-text-secondary\">\n {index + 1}.\n </span>\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {step.name}\n </span>\n <StatusBadge status={step.kind} tone=\"neutral\" />\n <StatusBadge status={step.status} className=\"ml-auto\" />\n </div>\n {step.errorMessage ? (\n <p className=\"mt-1.5 text-xs text-status-error-text\">\n {step.errorMessage}\n </p>\n ) : null}\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n Duration: {formatDuration(step.durationMs)}\n </p>\n </div>\n </li>\n );\n })}\n </ol>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent>\n <ActivityFeedPanel resourceId={run.id} resourceType=\"cosmicintersection-run\" />\n </CardContent>\n </Card>\n </div>\n\n <Dialog\n open={stepDialogOpen}\n onOpenChange={(next) => {\n if (addingStep) {\n return;\n }\n setStepDialogOpen(next);\n if (!next) {\n resetStepForm();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add step</DialogTitle>\n <DialogDescription>\n Record a stage of this run — its kind, order and optional inputs.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-name\">Name</Label>\n <Input\n id=\"step-name\"\n value={stepName}\n onChange={(event) => setStepName(event.target.value)}\n placeholder=\"e.g. Calibrate flat fields\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-kind\">Kind</Label>\n <Select\n value={stepKind}\n onValueChange={(value) => setStepKind(value as CosStepKind)}\n >\n <SelectTrigger id=\"step-kind\" aria-label=\"Step kind\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {STEP_KIND_OPTIONS.map((option) => (\n <SelectItem key={option} value={option}>\n {formatEnumLabel(option)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-position\">Position</Label>\n <Input\n id=\"step-position\"\n type=\"number\"\n min=\"0\"\n value={stepPosition}\n onChange={(event) => setStepPosition(event.target.value)}\n placeholder=\"Auto\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-inputs\">Inputs (JSON)</Label>\n <Textarea\n id=\"step-inputs\"\n value={stepInputs}\n onChange={(event) => setStepInputs(event.target.value)}\n rows={4}\n spellCheck={false}\n className=\"font-mono text-xs\"\n placeholder={'{\\n \"source\": \"raw-frames\"\\n}'}\n />\n <p className=\"text-xs text-text-secondary\">Optional. A JSON object of step inputs.</p>\n </div>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setStepDialogOpen(false);\n resetStepForm();\n }}\n disabled={addingStep}\n >\n Cancel\n </Button>\n <Button type=\"button\" onClick={() => void handleAddStep()} disabled={addingStep}>\n <Plus className=\"size-4\" />\n {addingStep ? 'Adding…' : 'Add step'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RunDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/runs/RunDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport type { LucideIcon } from 'lucide-react';\nimport { Check, Circle, ListTree, Loader2, Plus, SearchX, X } from 'lucide-react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAddRunStepMutation,\n useCosDatasetSummaryQuery,\n useCosPipelineFailedRunsQuery,\n useCosRunQuery,\n useCosRunStepsQuery,\n useCosTransitionRunMutation,\n type CosPipelineStep,\n type CosRunStatus,\n type CosStepKind,\n} from '../../api/cosmicApi';\nimport {\n ActivityFeedPanel,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\n\nconst STEP_KIND_OPTIONS: CosStepKind[] = [\n 'INGEST',\n 'CALIBRATE',\n 'TRANSFORM',\n 'ANALYZE',\n 'EXPORT',\n 'NOTIFY',\n];\n\n// Valid forward transitions for the run state machine. Terminal states have none.\nconst NEXT_STATUSES: Record<CosRunStatus, CosRunStatus[]> = {\n QUEUED: ['RUNNING', 'CANCELLED'],\n RUNNING: ['SUCCEEDED', 'FAILED', 'CANCELLED'],\n SUCCEEDED: [],\n FAILED: [],\n CANCELLED: [],\n};\n\n// Per-status timeline node: the icon rendered inside the spine circle + its\n// tone classes. Colour comes only from the semantic status token families.\nconst STEP_NODE: Record<CosRunStatus, { icon: LucideIcon; spin: boolean; wrap: string }> = {\n SUCCEEDED: {\n icon: Check,\n spin: false,\n wrap: 'border-status-success-border bg-status-success-bg-subtle text-status-success-text',\n },\n RUNNING: {\n icon: Loader2,\n spin: true,\n wrap: 'border-status-warning-border bg-status-warning-bg-subtle text-status-warning-text',\n },\n FAILED: {\n icon: X,\n spin: false,\n wrap: 'border-status-error-border bg-status-error-bg-subtle text-status-error-text',\n },\n QUEUED: {\n icon: Circle,\n spin: false,\n wrap: 'border-status-info-border bg-status-info-bg-subtle text-status-info-text',\n },\n CANCELLED: {\n icon: X,\n spin: false,\n wrap: 'border-border-default bg-bg-sunken text-text-secondary',\n },\n};\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction formatDuration(ms?: number | null): string {\n if (ms === null || ms === undefined) {\n return '—';\n }\n if (ms < 1000) {\n return `${ms} ms`;\n }\n const seconds = ms / 1000;\n if (seconds < 60) {\n return `${seconds.toFixed(1)} s`;\n }\n const minutes = Math.floor(seconds / 60);\n const rest = Math.round(seconds % 60);\n return `${minutes}m ${rest}s`;\n}\n\n/**\n * The step a run broke at — the earliest FAILED step by position. A run can end\n * FAILED with no step recorded at all (the failure predates step capture, or the\n * run was failed by hand), in which case this is null and callers fall back to\n * the run-level errorMessage.\n */\nfunction failingStep(steps: readonly CosPipelineStep[] | undefined): CosPipelineStep | null {\n const failed = (steps ?? []).filter((step) => step.status === 'FAILED');\n if (failed.length === 0) {\n return null;\n }\n return failed.reduce((earliest, step) => (step.position < earliest.position ? step : earliest));\n}\n\nfunction DetailRow({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1 border-b border-border-seam py-3 last:border-0 sm:flex-row sm:items-start sm:gap-4\">\n <span className=\"w-40 shrink-0 text-sm font-medium text-text-secondary\">{label}</span>\n <span className=\"min-w-0 text-sm text-text-primary\">{children}</span>\n </div>\n );\n}\n\nfunction JsonBlock({ value }: { value?: Record<string, unknown> | null }) {\n if (!value || Object.keys(value).length === 0) {\n return <span className=\"text-sm text-text-secondary\">—</span>;\n }\n return (\n <pre className=\"overflow-x-auto rounded-card border border-border-default bg-bg-sunken p-3 font-mono text-xs text-text-primary\">\n {JSON.stringify(value, null, 2)}\n </pre>\n );\n}\n\nexport default function RunDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosRunQuery(id);\n const {\n data: stepsData,\n loading: stepsLoading,\n error: stepsError,\n refetch: refetchSteps,\n } = useCosRunStepsQuery(id);\n\n const [transitionRun, { loading: transitioning }] = useCosTransitionRunMutation();\n const [addStep, { loading: addingStep }] = useCosAddRunStepMutation();\n\n const [stepDialogOpen, setStepDialogOpen] = useState(false);\n const [stepName, setStepName] = useState('');\n const [stepKind, setStepKind] = useState<CosStepKind>('INGEST');\n const [stepPosition, setStepPosition] = useState('');\n const [stepInputs, setStepInputs] = useState('');\n\n const run = data?.cosRun;\n const steps = useMemo(\n () => [...(stepsData?.cosListRunSteps ?? [])].sort((a, b) => a.position - b.position),\n [stepsData]\n );\n\n // `CosPipelineRun.datasetId` is a bare ID in the SDL (no relation field), so\n // resolve the name with the dedicated dataset lookup. Returns null when the\n // caller cannot read that dataset — we then keep showing the raw id.\n const { data: datasetSummaryData } = useCosDatasetSummaryQuery(run?.datasetId);\n const datasetName = datasetSummaryData?.cosDataset?.name ?? null;\n\n // Failure context: the other runs of this pipeline that also ended FAILED.\n // Only fetched for a failed run — there is nothing to compare on a green one.\n const runFailed = run?.status === 'FAILED';\n const {\n data: failedRunsData,\n loading: failedRunsLoading,\n error: failedRunsError,\n refetch: refetchFailedRuns,\n } = useCosPipelineFailedRunsQuery(run?.pipelineId, { skip: !runFailed });\n\n const currentFailingStep = useMemo(() => failingStep(steps), [steps]);\n\n const similarFailures = useMemo(() => {\n const items = failedRunsData?.cosListRuns.items ?? [];\n return items\n .filter((candidate) => candidate.id !== run?.id)\n .map((candidate) => {\n const brokenAt = failingStep(candidate.steps);\n return {\n id: candidate.id,\n runNumber: candidate.runNumber,\n step: brokenAt,\n // Prefer the step's own error; a run-level message is the fallback.\n error: brokenAt?.errorMessage ?? candidate.errorMessage ?? null,\n when: candidate.finishedAt ?? candidate.startedAt ?? candidate.createdAt,\n sameStep:\n currentFailingStep !== null &&\n brokenAt !== null &&\n brokenAt.name === currentFailingStep.name,\n };\n })\n .slice(0, 8);\n }, [failedRunsData, run?.id, currentFailingStep]);\n\n const handleTransition = async (nextStatus: CosRunStatus) => {\n if (!run) {\n return;\n }\n const response = await transitionRun({ variables: { id: run.id, status: nextStatus } });\n if (\n !mutationSucceeded(response, response.data?.cosTransitionRun?.id, 'Could not update the run')\n ) {\n return;\n }\n notify.success('Run updated', `Run #${run.runNumber} moved to ${formatEnumLabel(nextStatus)}.`);\n await Promise.all([refetch(), refetchSteps()]);\n };\n\n const resetStepForm = () => {\n setStepName('');\n setStepKind('INGEST');\n setStepPosition('');\n setStepInputs('');\n };\n\n const handleAddStep = async () => {\n if (!run) {\n return;\n }\n if (!stepName.trim()) {\n notify.error('Step name is required', 'Give the step a name before adding it.');\n return;\n }\n\n let inputs: Record<string, unknown> | undefined;\n if (stepInputs.trim()) {\n try {\n const parsed = JSON.parse(stepInputs.trim()) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('Inputs must be a JSON object.');\n }\n inputs = parsed as Record<string, unknown>;\n } catch (parseError) {\n notify.error(\n 'Invalid inputs JSON',\n describeError(parseError) ?? 'Please provide valid JSON.'\n );\n return;\n }\n }\n\n const positionValue = stepPosition.trim() ? Number(stepPosition.trim()) : undefined;\n if (positionValue !== undefined && (Number.isNaN(positionValue) || positionValue < 0)) {\n notify.error('Invalid position', 'Position must be a non-negative number.');\n return;\n }\n\n const response = await addStep({\n variables: {\n input: {\n runId: run.id,\n name: stepName.trim(),\n kind: stepKind,\n inputs,\n position: positionValue,\n },\n },\n });\n if (!mutationSucceeded(response, response.data?.cosAddRunStep?.id, 'Could not add the step')) {\n return;\n }\n notify.success('Step added', `“${stepName.trim()}” was added to the run.`);\n setStepDialogOpen(false);\n resetStepForm();\n await refetchSteps();\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <LoadingState label=\"Loading run…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <ErrorState onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!run) {\n return (\n <PageLayout title=\"Run\" backPath=\"runs\">\n <EmptyState\n title=\"Run not found\"\n description=\"This run may have been removed or you may not have access to it.\"\n action={\n <Button type=\"button\" variant=\"outline\" onClick={() => navigate('runs')}>\n Back to runs\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const validTransitions = NEXT_STATUSES[run.status] ?? [];\n\n return (\n <PageLayout\n title={`Run #${run.runNumber}`}\n description={run.pipeline ? `Pipeline: ${run.pipeline.name}` : undefined}\n backPath=\"runs\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n {validTransitions.map((next) => (\n <Button\n key={next}\n type=\"button\"\n variant={next === 'CANCELLED' || next === 'FAILED' ? 'outline' : 'default'}\n onClick={() => void handleTransition(next)}\n disabled={transitioning}\n >\n {`Mark ${formatEnumLabel(next)}`}\n </Button>\n ))}\n <Button type=\"button\" variant=\"outline\" onClick={() => setStepDialogOpen(true)}>\n <Plus className=\"size-4\" />\n Add step\n </Button>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Overview</CardTitle>\n </CardHeader>\n <CardContent>\n <DetailRow label=\"Status\">\n <StatusBadge status={run.status} />\n </DetailRow>\n <DetailRow label=\"Pipeline\">\n {run.pipeline ? (\n <button\n type=\"button\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n onClick={() => navigate(`pipelines/${run.pipelineId}`)}\n >\n {run.pipeline.name}\n </button>\n ) : (\n <span className=\"font-mono text-xs\">{run.pipelineId}</span>\n )}\n </DetailRow>\n <DetailRow label=\"Dataset\">\n {run.datasetId ? (\n <button\n type=\"button\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n onClick={() => navigate(`datasets/${run.datasetId}`)}\n >\n {datasetName ?? <span className=\"font-mono text-xs\">{run.datasetId}</span>}\n </button>\n ) : (\n '—'\n )}\n </DetailRow>\n {run.pipeline ? (\n <DetailRow label=\"Pipeline trigger\">\n {/* The PIPELINE's configured trigger. The SDL records no\n per-run trigger, so this is deliberately not labelled as\n how this particular run was started. */}\n <span className=\"inline-flex flex-wrap items-center gap-2\">\n <StatusBadge status={run.pipeline.trigger} tone=\"neutral\" />\n {run.pipeline.trigger === 'SCHEDULED' && run.pipeline.schedule ? (\n <span className=\"font-mono text-xs text-text-secondary\">\n {run.pipeline.schedule}\n </span>\n ) : null}\n </span>\n </DetailRow>\n ) : null}\n <DetailRow label=\"Triggered by\">{run.triggeredBy || '—'}</DetailRow>\n <DetailRow label=\"Started\">{formatDate(run.startedAt)}</DetailRow>\n <DetailRow label=\"Finished\">{formatDate(run.finishedAt)}</DetailRow>\n <DetailRow label=\"Duration\">{formatDuration(run.durationMs)}</DetailRow>\n {run.errorMessage ? (\n <DetailRow label=\"Error\">\n <span className=\"text-status-error-text\">{run.errorMessage}</span>\n </DetailRow>\n ) : null}\n {validTransitions.length === 0 ? (\n <DetailRow label=\"Discuss\">\n <SafeLink\n href=\"/conversations\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n >\n Open discussions\n </SafeLink>\n </DetailRow>\n ) : null}\n </CardContent>\n </Card>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Parameters</CardTitle>\n </CardHeader>\n <CardContent>\n <JsonBlock value={run.params} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Metrics</CardTitle>\n </CardHeader>\n <CardContent>\n <JsonBlock value={run.metrics} />\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Steps</CardTitle>\n </CardHeader>\n <CardContent>\n {stepsLoading ? (\n <LoadingState variant=\"rows\" rows={4} label=\"Loading steps…\" />\n ) : stepsError ? (\n <ErrorState message=\"Could not load steps.\" onRetry={() => void refetchSteps()} />\n ) : steps.length === 0 ? (\n <EmptyState\n icon={ListTree}\n title=\"No steps yet\"\n description=\"Add steps to record the ingest, calibration, transform, analyze or export stages of this run.\"\n action={\n <Button type=\"button\" onClick={() => setStepDialogOpen(true)}>\n <Plus className=\"size-4\" />\n Add step\n </Button>\n }\n />\n ) : (\n <ol className=\"flex flex-col\">\n {steps.map((step, index) => {\n const node = STEP_NODE[step.status] ?? STEP_NODE.QUEUED;\n const NodeIcon = node.icon;\n const isLast = index === steps.length - 1;\n return (\n <li key={step.id} className=\"flex gap-4\">\n {/* Spine: status node + connecting line to the next step. */}\n <div className=\"flex flex-col items-center\">\n <span\n className={`flex size-8 shrink-0 items-center justify-center rounded-full border ${node.wrap}`}\n >\n <NodeIcon\n className={`size-4 ${node.spin ? 'animate-spin' : ''}`}\n aria-hidden=\"true\"\n />\n </span>\n {!isLast ? (\n <span className=\"w-px flex-1 bg-border-default\" aria-hidden=\"true\" />\n ) : null}\n </div>\n\n <div\n className={`min-w-0 flex-1 rounded-card border border-border-default bg-bg-elevated p-4 ${\n isLast ? '' : 'mb-4'\n }`}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-semibold tabular-nums text-text-secondary\">\n {index + 1}.\n </span>\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {step.name}\n </span>\n <StatusBadge status={step.kind} tone=\"neutral\" />\n <StatusBadge status={step.status} className=\"ml-auto\" />\n </div>\n {step.errorMessage ? (\n <p className=\"mt-1.5 text-xs text-status-error-text\">\n {step.errorMessage}\n </p>\n ) : null}\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n Duration: {formatDuration(step.durationMs)}\n </p>\n </div>\n </li>\n );\n })}\n </ol>\n )}\n </CardContent>\n </Card>\n\n {/* Failure context — only meaningful once this run has actually failed. */}\n {runFailed ? (\n <Card>\n <CardHeader>\n <CardTitle>Similar failures</CardTitle>\n <p className=\"text-sm text-text-secondary\">\n {currentFailingStep\n ? `Other runs of this pipeline that ended in Failed. “Same step” marks the ones that broke at “${currentFailingStep.name}” too.`\n : 'Other runs of this pipeline that ended in Failed.'}\n </p>\n </CardHeader>\n <CardContent>\n {failedRunsLoading ? (\n <LoadingState variant=\"rows\" rows={3} label=\"Loading failure history…\" />\n ) : failedRunsError ? (\n <ErrorState\n message=\"Could not load the pipeline's failure history.\"\n onRetry={() => void refetchFailedRuns()}\n />\n ) : similarFailures.length === 0 ? (\n <EmptyState\n icon={SearchX}\n title=\"No other failed runs\"\n description=\"This is the only run of this pipeline that has failed so far.\"\n />\n ) : (\n <>\n {/* Desktop / tablet: table */}\n <div className=\"hidden overflow-hidden rounded-card border border-border-default md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Run</TableHead>\n <TableHead>Step</TableHead>\n <TableHead>Error</TableHead>\n <TableHead>When</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {similarFailures.map((failure) => (\n <TableRow\n key={failure.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`runs/${failure.id}`)}\n >\n <TableCell className=\"whitespace-nowrap font-medium text-text-primary\">\n Run #{failure.runNumber}\n </TableCell>\n <TableCell>\n {failure.step ? (\n <span className=\"inline-flex flex-wrap items-center gap-1.5\">\n <span className=\"text-sm text-text-primary\">\n {failure.step.name}\n </span>\n <StatusBadge status={failure.step.kind} tone=\"neutral\" />\n {failure.sameStep ? (\n <Badge\n variant=\"outline\"\n className=\"border-status-warning-border bg-status-warning-bg-subtle text-xs text-status-warning-text\"\n >\n Same step\n </Badge>\n ) : null}\n </span>\n ) : (\n <span className=\"text-sm text-text-secondary\">Not recorded</span>\n )}\n </TableCell>\n <TableCell className=\"max-w-md text-sm text-text-secondary\">\n <span className=\"line-clamp-2\">{failure.error ?? '—'}</span>\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(failure.when)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile: stacked cards */}\n <ul className=\"space-y-3 md:hidden\">\n {similarFailures.map((failure) => (\n <li key={failure.id}>\n <button\n type=\"button\"\n onClick={() => navigate(`runs/${failure.id}`)}\n className=\"flex w-full flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 text-left transition-colors hover:bg-bg-sunken focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <span className=\"font-medium text-text-primary\">\n Run #{failure.runNumber}\n </span>\n {failure.step ? (\n <StatusBadge status={failure.step.kind} tone=\"neutral\" />\n ) : null}\n {failure.sameStep ? (\n <Badge\n variant=\"outline\"\n className=\"border-status-warning-border bg-status-warning-bg-subtle text-xs text-status-warning-text\"\n >\n Same step\n </Badge>\n ) : null}\n </div>\n <p className=\"text-sm text-text-primary\">\n {failure.step ? failure.step.name : 'Step not recorded'}\n </p>\n <p className=\"text-xs text-text-secondary\">{failure.error ?? '—'}</p>\n <p className=\"text-xs text-text-tertiary\">{formatDate(failure.when)}</p>\n </button>\n </li>\n ))}\n </ul>\n </>\n )}\n </CardContent>\n </Card>\n ) : null}\n\n <Card>\n <CardHeader>\n <CardTitle>Activity</CardTitle>\n </CardHeader>\n <CardContent>\n <ActivityFeedPanel resourceId={run.id} resourceType=\"cosmicintersection-run\" />\n </CardContent>\n </Card>\n </div>\n\n <Dialog\n open={stepDialogOpen}\n onOpenChange={(next) => {\n if (addingStep) {\n return;\n }\n setStepDialogOpen(next);\n if (!next) {\n resetStepForm();\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add step</DialogTitle>\n <DialogDescription>\n Record a stage of this run — its kind, order and optional inputs.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-name\">Name</Label>\n <Input\n id=\"step-name\"\n value={stepName}\n onChange={(event) => setStepName(event.target.value)}\n placeholder=\"e.g. Calibrate flat fields\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-kind\">Kind</Label>\n <Select\n value={stepKind}\n onValueChange={(value) => setStepKind(value as CosStepKind)}\n >\n <SelectTrigger id=\"step-kind\" aria-label=\"Step kind\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {STEP_KIND_OPTIONS.map((option) => (\n <SelectItem key={option} value={option}>\n {formatEnumLabel(option)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-position\">Position</Label>\n <Input\n id=\"step-position\"\n type=\"number\"\n min=\"0\"\n value={stepPosition}\n onChange={(event) => setStepPosition(event.target.value)}\n placeholder=\"Auto\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"step-inputs\">Inputs (JSON)</Label>\n <Textarea\n id=\"step-inputs\"\n value={stepInputs}\n onChange={(event) => setStepInputs(event.target.value)}\n rows={4}\n spellCheck={false}\n className=\"font-mono text-xs\"\n placeholder={'{\\n \"source\": \"raw-frames\"\\n}'}\n />\n <p className=\"text-xs text-text-secondary\">Optional. A JSON object of step inputs.</p>\n </div>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setStepDialogOpen(false);\n resetStepForm();\n }}\n disabled={addingStep}\n >\n Cancel\n </Button>\n <Button type=\"button\" onClick={() => void handleAddStep()} disabled={addingStep}>\n <Plus className=\"size-4\" />\n {addingStep ? 'Adding…' : 'Add step'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RunsPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/runs/RunsPage.tsx"],"names":[],"mappings":"AAyDA,MAAM,CAAC,OAAO,UAAU,QAAQ,4CAyN/B"}
1
+ {"version":3,"file":"RunsPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/runs/RunsPage.tsx"],"names":[],"mappings":"AA0DA,MAAM,CAAC,OAAO,UAAU,QAAQ,4CAsO/B"}
@@ -1,242 +1,251 @@
1
1
  import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
2
2
  import { useCosPipelinesQuery as t, useCosRunsQuery as n } from "../../api/cosmicApi.js";
3
- import r from "../../components/EmptyState.js";
4
- import i from "../../components/ErrorState.js";
5
- import a from "../../components/LoadingState.js";
6
- import o from "../../components/PageLayout.js";
7
- import s, { usePagination as c } from "../../components/Pagination.js";
8
- import l, { formatEnumLabel as u } from "../../components/StatusBadge.js";
3
+ import { useTr as r } from "../../../shared/hooks/useTr.js";
4
+ import i from "../../components/EmptyState.js";
5
+ import a from "../../components/ErrorState.js";
6
+ import o from "../../components/LoadingState.js";
7
+ import s from "../../components/PageLayout.js";
8
+ import c, { usePagination as l } from "../../components/Pagination.js";
9
+ import u, { formatEnumLabel as d } from "../../components/StatusBadge.js";
9
10
  import "../../components/index.js";
10
- import { useMemo as d, useState as f } from "react";
11
- import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
12
- import { Activity as g, Eye as _ } from "lucide-react";
13
- import { Button as v, Select as y, SelectContent as b, SelectItem as x, SelectTrigger as S, SelectValue as C, Table as w, TableBody as T, TableCell as E, TableHead as D, TableHeader as O, TableRow as k } from "@burdenoff/fe-libs/ui";
11
+ import { useMemo as f, useState as p } from "react";
12
+ import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
13
+ import { Activity as _, Eye as v } from "lucide-react";
14
+ import { Button as y, Select as b, SelectContent as x, SelectItem as S, SelectTrigger as C, SelectValue as w, Table as T, TableBody as E, TableCell as D, TableHead as O, TableHeader as k, TableRow as A } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/cosmicintersection/pages/runs/RunsPage.tsx
15
- var A = [
16
+ var j = [
16
17
  "QUEUED",
17
18
  "RUNNING",
18
19
  "SUCCEEDED",
19
20
  "FAILED",
20
21
  "CANCELLED"
21
- ], j = "ALL";
22
- function M(e) {
22
+ ], M = "ALL";
23
+ function N(e) {
23
24
  if (!e) return "—";
24
25
  let t = new Date(e);
25
26
  return Number.isNaN(t.getTime()) ? "—" : t.toLocaleString();
26
27
  }
27
- function N(e) {
28
+ function P(e) {
28
29
  if (e == null) return "—";
29
30
  if (e < 1e3) return `${e} ms`;
30
31
  let t = e / 1e3;
31
32
  return t < 60 ? `${t.toFixed(1)} s` : `${Math.floor(t / 60)}m ${Math.round(t % 60)}s`;
32
33
  }
33
- function P() {
34
- let { navigate: P } = e(), [F, I] = f(j), [L, R] = f(j), z = c({ resetKey: `${F}:${L}` }), { data: B } = t({ pagination: {
34
+ function F() {
35
+ let { navigate: F } = e(), I = r(), [L, R] = p(M), [z, B] = p(M), V = l({ resetKey: `${L}:${z}` }), { data: H } = t({ pagination: {
35
36
  limit: 100,
36
37
  offset: 0
37
- } }), V = d(() => B?.cosListPipelines.items ?? [], [B]), H = d(() => {
38
+ } }), U = f(() => H?.cosListPipelines.items ?? [], [H]), W = f(() => {
38
39
  let e = /* @__PURE__ */ new Map();
39
- return V.forEach((t) => e.set(t.id, t.name)), e;
40
- }, [V]), { data: U, loading: W, error: G, refetch: K } = n({
41
- status: F === j ? void 0 : F,
42
- pipelineId: L === j ? void 0 : L,
40
+ return U.forEach((t) => e.set(t.id, t.name)), e;
41
+ }, [U]), { data: G, loading: K, error: q, refetch: J } = n({
42
+ status: L === M ? void 0 : L,
43
+ pipelineId: z === M ? void 0 : z,
43
44
  pagination: {
44
- limit: z.limit,
45
- offset: z.offset
45
+ limit: V.limit,
46
+ offset: V.offset
46
47
  }
47
- }), q = d(() => U?.cosListRuns.items ?? [], [U]), J = U?.cosListRuns.pageInfo;
48
- return /* @__PURE__ */ m(o, {
49
- title: "Runs",
50
- description: "Every pipeline execution, with status, timings and outcomes.",
51
- actions: /* @__PURE__ */ h(v, {
48
+ }), Y = f(() => G?.cosListRuns.items ?? [], [G]), X = G?.cosListRuns.pageInfo;
49
+ return /* @__PURE__ */ h(s, {
50
+ title: I("cosmicintersection.pages.runs.title", "Runs"),
51
+ description: I("cosmicintersection.pages.runs.description", "Every pipeline execution, with status, timings and outcomes."),
52
+ actions: /* @__PURE__ */ g(y, {
52
53
  type: "button",
53
54
  variant: "outline",
54
- onClick: () => P("pipelines"),
55
- children: [/* @__PURE__ */ m(_, { className: "size-4" }), "View pipelines"]
55
+ onClick: () => F("pipelines"),
56
+ children: [/* @__PURE__ */ h(v, { className: "size-4" }), I("cosmicintersection.pages.runs.viewPipelines", "View pipelines")]
56
57
  }),
57
- children: /* @__PURE__ */ h("div", {
58
+ children: /* @__PURE__ */ g("div", {
58
59
  className: "space-y-4",
59
- children: [/* @__PURE__ */ h("div", {
60
+ children: [/* @__PURE__ */ g("div", {
60
61
  className: "flex flex-wrap items-center gap-3",
61
- children: [/* @__PURE__ */ h("label", {
62
+ children: [/* @__PURE__ */ g("label", {
62
63
  className: "flex items-center gap-2 text-sm text-text-secondary",
63
- children: [/* @__PURE__ */ m("span", { children: "Status" }), /* @__PURE__ */ h(y, {
64
- value: F,
65
- onValueChange: (e) => I(e),
66
- children: [/* @__PURE__ */ m(S, {
64
+ children: [/* @__PURE__ */ h("span", { children: "Status" }), /* @__PURE__ */ g(b, {
65
+ value: L,
66
+ onValueChange: (e) => R(e),
67
+ children: [/* @__PURE__ */ h(C, {
67
68
  "aria-label": "Filter by status",
68
69
  className: "w-40",
69
- children: /* @__PURE__ */ m(C, {})
70
- }), /* @__PURE__ */ h(b, { children: [/* @__PURE__ */ m(x, {
71
- value: j,
70
+ children: /* @__PURE__ */ h(w, {})
71
+ }), /* @__PURE__ */ g(x, { children: [/* @__PURE__ */ h(S, {
72
+ value: M,
72
73
  children: "All statuses"
73
- }), A.map((e) => /* @__PURE__ */ m(x, {
74
+ }), j.map((e) => /* @__PURE__ */ h(S, {
74
75
  value: e,
75
- children: u(e)
76
+ children: d(e)
76
77
  }, e))] })]
77
78
  })]
78
- }), /* @__PURE__ */ h("label", {
79
+ }), /* @__PURE__ */ g("label", {
79
80
  className: "flex items-center gap-2 text-sm text-text-secondary",
80
- children: [/* @__PURE__ */ m("span", { children: "Pipeline" }), /* @__PURE__ */ h(y, {
81
- value: L,
82
- onValueChange: (e) => R(e),
83
- children: [/* @__PURE__ */ m(S, {
81
+ children: [/* @__PURE__ */ h("span", { children: "Pipeline" }), /* @__PURE__ */ g(b, {
82
+ value: z,
83
+ onValueChange: (e) => B(e),
84
+ children: [/* @__PURE__ */ h(C, {
84
85
  "aria-label": "Filter by pipeline",
85
86
  className: "w-56",
86
- children: /* @__PURE__ */ m(C, {})
87
- }), /* @__PURE__ */ h(b, { children: [/* @__PURE__ */ m(x, {
88
- value: j,
87
+ children: /* @__PURE__ */ h(w, {})
88
+ }), /* @__PURE__ */ g(x, { children: [/* @__PURE__ */ h(S, {
89
+ value: M,
89
90
  children: "All pipelines"
90
- }), V.map((e) => /* @__PURE__ */ m(x, {
91
+ }), U.map((e) => /* @__PURE__ */ h(S, {
91
92
  value: e.id,
92
93
  children: e.name
93
94
  }, e.id))] })]
94
95
  })]
95
96
  })]
96
- }), W ? /* @__PURE__ */ m(a, {
97
- variant: "rows",
98
- rows: 6,
99
- label: "Loading runs…"
100
- }) : G ? /* @__PURE__ */ m(i, {
101
- message: "We could not load pipeline runs. Please try again.",
102
- onRetry: () => void K()
103
- }) : q.length === 0 ? /* @__PURE__ */ m(r, {
104
- icon: g,
105
- title: F === j && L === j ? "No runs yet" : "No runs match these filters",
106
- description: F === j && L === j ? "Runs appear here once you start a pipeline. Each run tracks its steps, timings and metrics." : "Try a different status or pipeline filter."
107
- }) : /* @__PURE__ */ h(p, { children: [
108
- /* @__PURE__ */ m("div", {
109
- className: "hidden rounded-card border border-border-default bg-bg-elevated md:block",
110
- children: /* @__PURE__ */ h(w, { children: [/* @__PURE__ */ m(O, { children: /* @__PURE__ */ h(k, { children: [
111
- /* @__PURE__ */ m(D, { children: "Run" }),
112
- /* @__PURE__ */ m(D, { children: "Pipeline" }),
113
- /* @__PURE__ */ m(D, { children: "Status" }),
114
- /* @__PURE__ */ m(D, { children: "Started" }),
115
- /* @__PURE__ */ m(D, { children: "Finished" }),
116
- /* @__PURE__ */ m(D, { children: "Duration" }),
117
- /* @__PURE__ */ m(D, { children: "Triggered by" })
118
- ] }) }), /* @__PURE__ */ m(T, { children: q.map((e) => /* @__PURE__ */ h(k, {
119
- className: "cursor-pointer",
120
- onClick: () => P(`runs/${e.id}`),
121
- children: [
122
- /* @__PURE__ */ h(E, {
123
- className: "font-medium text-text-primary",
124
- children: ["#", e.runNumber]
125
- }),
126
- /* @__PURE__ */ m(E, {
127
- className: "text-text-secondary",
128
- children: /* @__PURE__ */ m("span", {
129
- className: "truncate",
130
- children: H.get(e.pipelineId) ?? /* @__PURE__ */ m("span", {
131
- className: "font-mono text-xs",
132
- children: e.pipelineId
133
- })
134
- })
135
- }),
136
- /* @__PURE__ */ m(E, { children: /* @__PURE__ */ m(l, { status: e.status }) }),
137
- /* @__PURE__ */ m(E, {
138
- className: "whitespace-nowrap text-text-secondary",
139
- children: M(e.startedAt)
140
- }),
141
- /* @__PURE__ */ m(E, {
142
- className: "whitespace-nowrap text-text-secondary",
143
- children: M(e.finishedAt)
144
- }),
145
- /* @__PURE__ */ m(E, {
146
- className: "tabular-nums text-text-secondary",
147
- children: N(e.durationMs)
148
- }),
149
- /* @__PURE__ */ m(E, {
150
- className: "text-text-secondary",
151
- children: e.triggeredBy || "—"
152
- })
153
- ]
154
- }, e.id)) })] })
155
- }),
156
- /* @__PURE__ */ m("ul", {
157
- className: "space-y-3 md:hidden",
158
- children: q.map((e) => /* @__PURE__ */ m("li", { children: /* @__PURE__ */ h("button", {
159
- type: "button",
160
- onClick: () => P(`runs/${e.id}`),
161
- className: "flex w-full flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 text-left transition-colors hover:border-border-strong",
162
- children: [
163
- /* @__PURE__ */ h("div", {
164
- className: "flex items-center justify-between gap-2",
165
- children: [/* @__PURE__ */ h("span", {
97
+ }), (() => {
98
+ if (K) return /* @__PURE__ */ h(o, {
99
+ variant: "rows",
100
+ rows: 6,
101
+ label: I("cosmicintersection.pages.runs.loading", "Loading runs…")
102
+ });
103
+ if (q) return /* @__PURE__ */ h(a, {
104
+ message: I("cosmicintersection.pages.runs.error", "We could not load pipeline runs. Please try again."),
105
+ onRetry: () => void J()
106
+ });
107
+ if (Y.length === 0) {
108
+ let e = L === M && z === M;
109
+ return /* @__PURE__ */ h(i, {
110
+ icon: _,
111
+ title: e ? I("cosmicintersection.pages.runs.emptyTitle", "No runs yet") : I("cosmicintersection.pages.runs.emptyFilterTitle", "No runs match these filters"),
112
+ description: e ? I("cosmicintersection.pages.runs.emptyDescription", "Runs appear here once you start a pipeline. Each run tracks its steps, timings and metrics.") : I("cosmicintersection.pages.runs.emptyFilterDescription", "Try a different status or pipeline filter.")
113
+ });
114
+ }
115
+ return /* @__PURE__ */ g(m, { children: [
116
+ /* @__PURE__ */ h("div", {
117
+ className: "hidden rounded-card border border-border-default bg-bg-elevated md:block",
118
+ children: /* @__PURE__ */ g(T, { children: [/* @__PURE__ */ h(k, { children: /* @__PURE__ */ g(A, { children: [
119
+ /* @__PURE__ */ h(O, { children: "Run" }),
120
+ /* @__PURE__ */ h(O, { children: "Pipeline" }),
121
+ /* @__PURE__ */ h(O, { children: "Status" }),
122
+ /* @__PURE__ */ h(O, { children: "Started" }),
123
+ /* @__PURE__ */ h(O, { children: "Finished" }),
124
+ /* @__PURE__ */ h(O, { children: "Duration" }),
125
+ /* @__PURE__ */ h(O, { children: "Triggered by" })
126
+ ] }) }), /* @__PURE__ */ h(E, { children: Y.map((e) => /* @__PURE__ */ g(A, {
127
+ className: "cursor-pointer",
128
+ onClick: () => F(`runs/${e.id}`),
129
+ children: [
130
+ /* @__PURE__ */ g(D, {
166
131
  className: "font-medium text-text-primary",
167
132
  children: ["#", e.runNumber]
168
- }), /* @__PURE__ */ m(l, { status: e.status })]
169
- }),
170
- /* @__PURE__ */ m("p", {
171
- className: "truncate text-sm text-text-secondary",
172
- children: H.get(e.pipelineId) ?? /* @__PURE__ */ m("span", {
173
- className: "font-mono text-xs",
174
- children: e.pipelineId
133
+ }),
134
+ /* @__PURE__ */ h(D, {
135
+ className: "text-text-secondary",
136
+ children: /* @__PURE__ */ h("span", {
137
+ className: "truncate",
138
+ children: W.get(e.pipelineId) ?? /* @__PURE__ */ h("span", {
139
+ className: "font-mono text-xs",
140
+ children: e.pipelineId
141
+ })
142
+ })
143
+ }),
144
+ /* @__PURE__ */ h(D, { children: /* @__PURE__ */ h(u, { status: e.status }) }),
145
+ /* @__PURE__ */ h(D, {
146
+ className: "whitespace-nowrap text-text-secondary",
147
+ children: N(e.startedAt)
148
+ }),
149
+ /* @__PURE__ */ h(D, {
150
+ className: "whitespace-nowrap text-text-secondary",
151
+ children: N(e.finishedAt)
152
+ }),
153
+ /* @__PURE__ */ h(D, {
154
+ className: "tabular-nums text-text-secondary",
155
+ children: P(e.durationMs)
156
+ }),
157
+ /* @__PURE__ */ h(D, {
158
+ className: "text-text-secondary",
159
+ children: e.triggeredBy || "—"
175
160
  })
176
- }),
177
- /* @__PURE__ */ h("dl", {
178
- className: "grid grid-cols-2 gap-x-3 gap-y-1 text-xs",
179
- children: [
180
- /* @__PURE__ */ h("div", {
181
- className: "flex flex-col",
182
- children: [/* @__PURE__ */ m("dt", {
183
- className: "text-text-secondary",
184
- children: "Started"
185
- }), /* @__PURE__ */ m("dd", {
186
- className: "text-text-primary",
187
- children: M(e.startedAt)
188
- })]
189
- }),
190
- /* @__PURE__ */ h("div", {
191
- className: "flex flex-col",
192
- children: [/* @__PURE__ */ m("dt", {
193
- className: "text-text-secondary",
194
- children: "Duration"
195
- }), /* @__PURE__ */ m("dd", {
196
- className: "tabular-nums text-text-primary",
197
- children: N(e.durationMs)
198
- })]
199
- }),
200
- /* @__PURE__ */ h("div", {
201
- className: "flex flex-col",
202
- children: [/* @__PURE__ */ m("dt", {
203
- className: "text-text-secondary",
204
- children: "Finished"
205
- }), /* @__PURE__ */ m("dd", {
206
- className: "text-text-primary",
207
- children: M(e.finishedAt)
208
- })]
209
- }),
210
- /* @__PURE__ */ h("div", {
211
- className: "flex flex-col",
212
- children: [/* @__PURE__ */ m("dt", {
213
- className: "text-text-secondary",
214
- children: "Triggered by"
215
- }), /* @__PURE__ */ m("dd", {
216
- className: "text-text-primary",
217
- children: e.triggeredBy || "—"
218
- })]
161
+ ]
162
+ }, e.id)) })] })
163
+ }),
164
+ /* @__PURE__ */ h("ul", {
165
+ className: "space-y-3 md:hidden",
166
+ children: Y.map((e) => /* @__PURE__ */ h("li", { children: /* @__PURE__ */ g("button", {
167
+ type: "button",
168
+ onClick: () => F(`runs/${e.id}`),
169
+ className: "flex w-full flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 text-left transition-colors hover:border-border-strong",
170
+ children: [
171
+ /* @__PURE__ */ g("div", {
172
+ className: "flex items-center justify-between gap-2",
173
+ children: [/* @__PURE__ */ g("span", {
174
+ className: "font-medium text-text-primary",
175
+ children: ["#", e.runNumber]
176
+ }), /* @__PURE__ */ h(u, { status: e.status })]
177
+ }),
178
+ /* @__PURE__ */ h("p", {
179
+ className: "truncate text-sm text-text-secondary",
180
+ children: W.get(e.pipelineId) ?? /* @__PURE__ */ h("span", {
181
+ className: "font-mono text-xs",
182
+ children: e.pipelineId
219
183
  })
220
- ]
221
- })
222
- ]
223
- }) }, e.id))
224
- }),
225
- /* @__PURE__ */ m(s, {
226
- offset: z.offset,
227
- limit: z.limit,
228
- loadedCount: q.length,
229
- hasMore: J?.hasMore ?? !1,
230
- onPrev: z.prevPage,
231
- onNext: z.nextPage,
232
- itemLabel: "runs",
233
- loading: W
234
- })
235
- ] })]
184
+ }),
185
+ /* @__PURE__ */ g("dl", {
186
+ className: "grid grid-cols-2 gap-x-3 gap-y-1 text-xs",
187
+ children: [
188
+ /* @__PURE__ */ g("div", {
189
+ className: "flex flex-col",
190
+ children: [/* @__PURE__ */ h("dt", {
191
+ className: "text-text-secondary",
192
+ children: "Started"
193
+ }), /* @__PURE__ */ h("dd", {
194
+ className: "text-text-primary",
195
+ children: N(e.startedAt)
196
+ })]
197
+ }),
198
+ /* @__PURE__ */ g("div", {
199
+ className: "flex flex-col",
200
+ children: [/* @__PURE__ */ h("dt", {
201
+ className: "text-text-secondary",
202
+ children: "Duration"
203
+ }), /* @__PURE__ */ h("dd", {
204
+ className: "tabular-nums text-text-primary",
205
+ children: P(e.durationMs)
206
+ })]
207
+ }),
208
+ /* @__PURE__ */ g("div", {
209
+ className: "flex flex-col",
210
+ children: [/* @__PURE__ */ h("dt", {
211
+ className: "text-text-secondary",
212
+ children: "Finished"
213
+ }), /* @__PURE__ */ h("dd", {
214
+ className: "text-text-primary",
215
+ children: N(e.finishedAt)
216
+ })]
217
+ }),
218
+ /* @__PURE__ */ g("div", {
219
+ className: "flex flex-col",
220
+ children: [/* @__PURE__ */ h("dt", {
221
+ className: "text-text-secondary",
222
+ children: "Triggered by"
223
+ }), /* @__PURE__ */ h("dd", {
224
+ className: "text-text-primary",
225
+ children: e.triggeredBy || "—"
226
+ })]
227
+ })
228
+ ]
229
+ })
230
+ ]
231
+ }) }, e.id))
232
+ }),
233
+ /* @__PURE__ */ h(c, {
234
+ offset: V.offset,
235
+ limit: V.limit,
236
+ loadedCount: Y.length,
237
+ hasMore: X?.hasMore ?? !1,
238
+ onPrev: V.prevPage,
239
+ onNext: V.nextPage,
240
+ itemLabel: I("cosmicintersection.pages.runs.itemLabel", "runs"),
241
+ loading: K
242
+ })
243
+ ] });
244
+ })()]
236
245
  })
237
246
  });
238
247
  }
239
248
  //#endregion
240
- export { P as default };
249
+ export { F as default };
241
250
 
242
251
  //# sourceMappingURL=RunsPage.js.map