@shipfox/client-workflows 16.0.0 → 18.0.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +32 -0
- package/dist/components/identifier/identifier.js +2 -2
- package/dist/components/identifier/identifier.js.map +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.js +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -1
- package/dist/components/job-detail/job-context-panel.d.ts +6 -0
- package/dist/components/job-detail/job-context-panel.d.ts.map +1 -0
- package/dist/components/job-detail/job-context-panel.js +228 -0
- package/dist/components/job-detail/job-context-panel.js.map +1 -0
- package/dist/components/job-detail/job-detail-header.d.ts +3 -1
- package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-header.js +54 -48
- package/dist/components/job-detail/job-detail-header.js.map +1 -1
- package/dist/components/job-detail/job-detail-view.d.ts +1 -1
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-view.js +100 -57
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/job-empty-states.d.ts +4 -0
- package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
- package/dist/components/job-detail/job-empty-states.js +60 -11
- package/dist/components/job-detail/job-empty-states.js.map +1 -1
- package/dist/components/job-detail/job-execution-switcher.js +4 -4
- package/dist/components/job-detail/job-execution-switcher.js.map +1 -1
- package/dist/components/job-detail/json-code.d.ts +14 -0
- package/dist/components/job-detail/json-code.d.ts.map +1 -0
- package/dist/components/job-detail/json-code.js +93 -0
- package/dist/components/job-detail/json-code.js.map +1 -0
- package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.js +9 -6
- package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
- package/dist/components/job-detail/step-troubleshooting.d.ts +18 -0
- package/dist/components/job-detail/step-troubleshooting.d.ts.map +1 -0
- package/dist/components/job-detail/step-troubleshooting.js +497 -0
- package/dist/components/job-detail/step-troubleshooting.js.map +1 -0
- package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +5 -4
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/job-graph/job-node.js +3 -3
- package/dist/components/job-graph/job-node.js.map +1 -1
- package/dist/components/step-list/index.d.ts +1 -0
- package/dist/components/step-list/index.d.ts.map +1 -1
- package/dist/components/step-list/index.js.map +1 -1
- package/dist/components/step-list/step-list-model.d.ts.map +1 -1
- package/dist/components/step-list/step-list-model.js +6 -0
- package/dist/components/step-list/step-list-model.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +5 -1
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js +117 -82
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-duration-label.js +1 -1
- package/dist/components/workflow-run-duration-label.js.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.js +6 -6
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js +4 -4
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +6 -6
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +7 -7
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +0 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +8 -13
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/index.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js +2 -2
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts +9 -2
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-list.js +28 -19
- package/dist/components/workflow-run-tabs/run-annotation-list.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +5 -5
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +11 -10
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +6 -6
- package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +72 -12
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +9 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job.d.ts +10 -1
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/job.js.map +1 -1
- package/dist/core/entities/step-attempt.d.ts +29 -0
- package/dist/core/entities/step-attempt.d.ts.map +1 -1
- package/dist/core/entities/step-attempt.js.map +1 -1
- package/dist/core/entities/step.d.ts +3 -1
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/run-annotation.d.ts +6 -0
- package/dist/core/run-annotation.d.ts.map +1 -1
- package/dist/core/run-annotation.js.map +1 -1
- package/dist/core/workflow-run.d.ts +1 -1
- package/dist/core/workflow-run.d.ts.map +1 -1
- package/dist/core/workflow-run.js.map +1 -1
- package/dist/hooks/api/annotations.d.ts +63 -0
- package/dist/hooks/api/annotations.d.ts.map +1 -0
- package/dist/hooks/api/annotations.js +145 -0
- package/dist/hooks/api/annotations.js.map +1 -0
- package/dist/hooks/api/step-attempt-detail.d.ts +14 -0
- package/dist/hooks/api/step-attempt-detail.d.ts.map +1 -0
- package/dist/hooks/api/step-attempt-detail.js +43 -0
- package/dist/hooks/api/step-attempt-detail.js.map +1 -0
- package/dist/hooks/api/workflow-run-mapper.d.ts +9 -2
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +48 -0
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/pages/project-workflows-page.js +19 -19
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-run-list-page.js +1 -1
- package/dist/pages/workflow-run-list-page.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/components/identifier/identifier.tsx +2 -2
- package/src/components/job-detail/agent-config-failure-callout.tsx +5 -1
- package/src/components/job-detail/job-context-panel.test.tsx +72 -0
- package/src/components/job-detail/job-context-panel.tsx +241 -0
- package/src/components/job-detail/job-detail-header.tsx +52 -46
- package/src/components/job-detail/job-detail-view.stories.tsx +555 -53
- package/src/components/job-detail/job-detail-view.tsx +105 -59
- package/src/components/job-detail/job-empty-states.test.ts +105 -1
- package/src/components/job-detail/job-empty-states.tsx +77 -10
- package/src/components/job-detail/job-execution-switcher.tsx +5 -5
- package/src/components/job-detail/json-code.tsx +120 -0
- package/src/components/job-detail/step-attempt-log-panel.test.tsx +1 -0
- package/src/components/job-detail/step-attempt-log-panel.tsx +17 -6
- package/src/components/job-detail/step-troubleshooting.stories.tsx +120 -0
- package/src/components/job-detail/step-troubleshooting.test.tsx +337 -0
- package/src/components/job-detail/step-troubleshooting.tsx +541 -0
- package/src/components/job-graph/job-graph-content.tsx +4 -3
- package/src/components/job-graph/job-node.tsx +3 -3
- package/src/components/step-list/index.ts +1 -0
- package/src/components/step-list/step-list-model.ts +6 -0
- package/src/components/step-list/step-list.test.tsx +75 -2
- package/src/components/step-list/step-list.tsx +73 -20
- package/src/components/workflow-run-duration-label.tsx +1 -1
- package/src/components/workflow-run-list/job-status-strip.tsx +6 -6
- package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-filters.tsx +4 -4
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +6 -6
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-row.tsx +7 -7
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +1 -1
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +1 -1
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +11 -11
- package/src/components/workflow-run-tabs/index.ts +5 -1
- package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +2 -2
- package/src/components/workflow-run-tabs/run-annotation-list.tsx +25 -10
- package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +5 -5
- package/src/components/workflow-run-view/run-workspace-nav.tsx +18 -11
- package/src/components/workflow-run-view/workflow-run-states.tsx +6 -6
- package/src/components/workflow-run-view/workflow-run-view.tsx +114 -14
- package/src/core/entities/job-execution.ts +9 -0
- package/src/core/entities/job.ts +12 -1
- package/src/core/entities/step-attempt.ts +33 -0
- package/src/core/entities/step.ts +3 -1
- package/src/core/run-annotation.ts +6 -0
- package/src/core/workflow-run.ts +4 -0
- package/src/hooks/api/annotations.test.ts +84 -0
- package/src/hooks/api/annotations.ts +240 -0
- package/src/hooks/api/step-attempt-detail.ts +67 -0
- package/src/hooks/api/workflow-run-mapper.ts +47 -0
- package/src/hooks/api/workflow-runs.test.tsx +61 -1
- package/src/pages/project-workflows-page.tsx +19 -19
- package/src/pages/workflow-job-detail-page.test.tsx +52 -1
- package/src/pages/workflow-run-list-page.tsx +1 -1
- package/test/fixtures/workflow-run.ts +7 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -26,16 +26,17 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
|
26
26
|
intervalMs: 1000,
|
|
27
27
|
reducedMotionIntervalMs: 10_000,
|
|
28
28
|
children: /*#__PURE__*/ _jsx("aside", {
|
|
29
|
-
className: "w-full shrink-0 border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r",
|
|
29
|
+
className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r",
|
|
30
30
|
children: /*#__PURE__*/ _jsxs(Collapsible, {
|
|
31
31
|
open: mobileOpen,
|
|
32
32
|
onOpenChange: setMobileOpen,
|
|
33
|
+
className: "flex min-h-0 flex-col min-[768px]:flex-1",
|
|
33
34
|
children: [
|
|
34
35
|
/*#__PURE__*/ _jsx(CollapsibleTrigger, {
|
|
35
36
|
asChild: true,
|
|
36
37
|
children: /*#__PURE__*/ _jsxs("button", {
|
|
37
38
|
type: "button",
|
|
38
|
-
className: "flex min-h-44 w-full items-center justify-between gap-
|
|
39
|
+
className: "flex min-h-44 w-full items-center justify-between gap-cluster px-row text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden",
|
|
39
40
|
"aria-label": "Toggle run navigation",
|
|
40
41
|
children: [
|
|
41
42
|
/*#__PURE__*/ _jsxs("span", {
|
|
@@ -63,7 +64,7 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
|
63
64
|
})
|
|
64
65
|
}),
|
|
65
66
|
/*#__PURE__*/ _jsx("div", {
|
|
66
|
-
className: cn('max-h-[50vh] overflow-y-auto p-
|
|
67
|
+
className: cn('flex min-h-0 max-h-[50vh] flex-col overflow-y-auto p-tight scrollbar min-[768px]:min-h-0 min-[768px]:max-h-none min-[768px]:flex-1 min-[768px]:flex min-[768px]:overflow-hidden min-[768px]:p-[12px]', !mobileOpen && 'hidden'),
|
|
67
68
|
children: /*#__PURE__*/ _jsx(RunWorkspaceNavContent, {
|
|
68
69
|
workspaceSlug: workspaceSlug,
|
|
69
70
|
projectSlug: projectSlug,
|
|
@@ -105,7 +106,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
105
106
|
]);
|
|
106
107
|
return /*#__PURE__*/ _jsxs("nav", {
|
|
107
108
|
"aria-label": "Run workspace",
|
|
108
|
-
className: "flex min-w-0 flex-col gap-
|
|
109
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col gap-group",
|
|
109
110
|
children: [
|
|
110
111
|
/*#__PURE__*/ _jsx("ul", {
|
|
111
112
|
children: /*#__PURE__*/ _jsx("li", {
|
|
@@ -122,10 +123,10 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
122
123
|
}),
|
|
123
124
|
/*#__PURE__*/ _jsxs("section", {
|
|
124
125
|
"aria-labelledby": "run-workspace-jobs-heading",
|
|
125
|
-
className: "min-w-0",
|
|
126
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col",
|
|
126
127
|
children: [
|
|
127
128
|
/*#__PURE__*/ _jsxs("div", {
|
|
128
|
-
className: "flex items-center justify-between gap-
|
|
129
|
+
className: "flex items-center justify-between gap-inline px-tight pb-[6px]",
|
|
129
130
|
children: [
|
|
130
131
|
/*#__PURE__*/ _jsx(Text, {
|
|
131
132
|
as: "h2",
|
|
@@ -144,7 +145,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
144
145
|
]
|
|
145
146
|
}),
|
|
146
147
|
/*#__PURE__*/ _jsx("ol", {
|
|
147
|
-
className: "
|
|
148
|
+
className: "min-h-0 flex-1 overflow-y-auto scrollbar",
|
|
148
149
|
children: jobs.map((job)=>{
|
|
149
150
|
const current = job.id === currentJobId;
|
|
150
151
|
const execution = defaultJobExecution(job);
|
|
@@ -164,7 +165,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
164
165
|
}),
|
|
165
166
|
onClick: onNavigate,
|
|
166
167
|
"aria-current": current ? 'page' : undefined,
|
|
167
|
-
className: cn('flex min-h-32 min-w-0 items-center gap-
|
|
168
|
+
className: cn('flex min-h-32 min-w-0 items-center gap-inline rounded-4 px-tight text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44', current && 'bg-background-neutral-hover'),
|
|
168
169
|
children: [
|
|
169
170
|
/*#__PURE__*/ _jsx(WorkflowStatusIcon, {
|
|
170
171
|
status: deriveJobDisplayStatus(job),
|
|
@@ -196,7 +197,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
196
197
|
id: "run-workspace-details-heading",
|
|
197
198
|
size: "xs",
|
|
198
199
|
bold: true,
|
|
199
|
-
className: "px-
|
|
200
|
+
className: "px-tight pb-[6px] text-foreground-neutral-muted",
|
|
200
201
|
children: "Run details"
|
|
201
202
|
}),
|
|
202
203
|
/*#__PURE__*/ _jsxs("ul", {
|
|
@@ -251,7 +252,7 @@ function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section
|
|
|
251
252
|
onClick: onNavigate,
|
|
252
253
|
"aria-current": current ? 'page' : undefined,
|
|
253
254
|
"aria-label": count ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}` : undefined,
|
|
254
|
-
className: cn('flex min-h-32 items-center gap-
|
|
255
|
+
className: cn('flex min-h-32 items-center gap-inline rounded-4 px-tight text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44', current && 'bg-background-neutral-hover'),
|
|
255
256
|
children: [
|
|
256
257
|
sectionLabel(section),
|
|
257
258
|
count ? /*#__PURE__*/ _jsxs("span", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"sourcesContent":["import {Collapsible, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n type Job,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobExecutionTimeText} from '../job-detail/job-execution-time-text.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface RunWorkspaceNavProps {\n workspaceSlug: string;\n projectSlug: string;\n run: WorkflowRunDetail;\n activeSection: RunWorkspaceSection;\n currentJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n annotationSummary?: RunAnnotationSummary | undefined;\n}\n\n/**\n * The stable navigation model shared by run-level and job-level routes. The graph explains\n * topology; this compact index makes moving between dedicated job pages predictable.\n */\nexport function RunWorkspaceNav({\n workspaceSlug,\n projectSlug,\n run,\n activeSection,\n currentJobId,\n jobSearch = {},\n annotationSummary,\n}: RunWorkspaceNavProps) {\n const jobs = useMemo(() => [...run.jobs].sort(compareJobs), [run.jobs]);\n const [mobileOpen, setMobileOpen] = useState(false);\n const currentJob = jobs.find((job) => job.id === currentJobId);\n const currentLabel = currentJob?.displayName ?? sectionLabel(activeSection);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside className=\"w-full shrink-0 border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r\">\n <Collapsible open={mobileOpen} onOpenChange={setMobileOpen}>\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex min-h-44 w-full items-center justify-between gap-12 px-16 text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden\"\n aria-label=\"Toggle run navigation\"\n >\n <span className=\"min-w-0\">\n <Text as=\"span\" size=\"xs\" className=\"block text-foreground-neutral-muted\">\n Run navigation\n </Text>\n <span className=\"block truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {currentLabel}\n </span>\n </span>\n <Icon\n name=\"chevronDown\"\n size={14}\n aria-hidden=\"true\"\n className={cn(\n 'shrink-0 text-foreground-neutral-muted transition-transform',\n mobileOpen && 'rotate-180',\n )}\n />\n </button>\n </CollapsibleTrigger>\n <div\n className={cn(\n 'max-h-[50vh] overflow-y-auto p-8 min-[768px]:block min-[768px]:max-h-none min-[768px]:p-12',\n !mobileOpen && 'hidden',\n )}\n >\n <RunWorkspaceNavContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={run}\n jobs={jobs}\n activeSection={activeSection}\n currentJobId={currentJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n mobileOpen={mobileOpen}\n onNavigate={() => setMobileOpen(false)}\n />\n </div>\n </Collapsible>\n </aside>\n </TimeTickerProvider>\n );\n}\n\nfunction RunWorkspaceNavContent({\n workspaceSlug,\n projectSlug,\n run,\n jobs,\n activeSection,\n currentJobId,\n jobSearch,\n annotationSummary,\n mobileOpen,\n onNavigate,\n}: RunWorkspaceNavProps & {\n jobs: Job[];\n jobSearch: WorkflowJobSearch;\n mobileOpen: boolean;\n onNavigate: () => void;\n}) {\n const currentRowRef = useRef<HTMLAnchorElement>(null);\n const runAttempt = jobSearch.runAttempt ?? run.runAttempt.attempt;\n\n useEffect(() => {\n if (!currentJobId || mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n useEffect(() => {\n if (!currentJobId || !mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n return (\n <nav aria-label=\"Run workspace\" className=\"flex min-w-0 flex-col gap-16\">\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"summary\"\n current={!currentJobId && activeSection === 'summary'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n\n <section aria-labelledby=\"run-workspace-jobs-heading\" className=\"min-w-0\">\n <div className=\"flex items-center justify-between gap-8 px-8 pb-6\">\n <Text\n as=\"h2\"\n id=\"run-workspace-jobs-heading\"\n size=\"xs\"\n bold\n className=\"text-foreground-neutral-muted\"\n >\n Jobs\n </Text>\n <Text as=\"span\" size=\"xs\" className=\"font-code text-foreground-neutral-subtle\">\n {jobs.length}\n </Text>\n </div>\n <ol className=\"max-h-[320px] overflow-y-auto\">\n {jobs.map((job) => {\n const current = job.id === currentJobId;\n const execution = defaultJobExecution(job);\n const duration = execution?.displayDuration ?? job.displayDuration;\n\n return (\n <li key={job.id}>\n <Link\n ref={current ? currentRowRef : undefined}\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id, jobId: job.id}}\n search={workflowJobSearchParams({runAttempt}) as never}\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n className={cn(\n 'flex min-h-32 min-w-0 items-center gap-8 rounded-4 px-8 text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n <WorkflowStatusIcon\n status={deriveJobDisplayStatus(job)}\n size={12}\n tooltip={false}\n />\n <span className=\"min-w-0 truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {job.displayName}\n </span>\n <span className=\"ml-auto shrink-0 font-code text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n {duration ? <JobExecutionTimeText time={duration} /> : '—'}\n </span>\n </Link>\n </li>\n );\n })}\n </ol>\n </section>\n\n <section aria-labelledby=\"run-workspace-details-heading\">\n <Text\n as=\"h2\"\n id=\"run-workspace-details-heading\"\n size=\"xs\"\n bold\n className=\"px-8 pb-6 text-foreground-neutral-muted\"\n >\n Run details\n </Text>\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"annotations\"\n current={!currentJobId && activeSection === 'annotations'}\n count={annotationSummary?.total}\n countTruncated={annotationSummary?.truncated}\n onNavigate={onNavigate}\n />\n </li>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"source\"\n current={!currentJobId && activeSection === 'source'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n </section>\n </nav>\n );\n}\n\nfunction RunSectionLink({\n workspaceSlug,\n projectSlug,\n runId,\n runAttempt,\n section,\n current,\n count,\n countTruncated = false,\n onNavigate,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n runAttempt: number;\n section: RunWorkspaceSection;\n current: boolean;\n count?: number | undefined;\n /** The read hit its page budget, so the count is a lower bound and renders as `N+`. */\n countTruncated?: boolean | undefined;\n onNavigate?: (() => void) | undefined;\n}) {\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId}}\n search={\n workflowRunSearchParams(\n {runAttempt, ...(section === 'summary' ? {} : {tab: section})},\n {runAttempt},\n ) as never\n }\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n aria-label={\n count\n ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}`\n : undefined\n }\n className={cn(\n 'flex min-h-32 items-center gap-8 rounded-4 px-8 text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n {sectionLabel(section)}\n {count ? (\n <span\n aria-hidden=\"true\"\n className=\"ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums\"\n >\n {count}\n {countTruncated ? '+' : ''}\n </span>\n ) : null}\n </Link>\n );\n}\n\nfunction sectionLabel(section: RunWorkspaceSection): string {\n if (section === 'annotations') return 'Annotations';\n if (section === 'source') return 'Source';\n return 'Summary';\n}\n\nfunction compareJobs(left: Job, right: Job): number {\n return left.position - right.position || left.id.localeCompare(right.id);\n}\n"],"names":["Collapsible","CollapsibleTrigger","Icon","TimeTickerProvider","Text","cn","Link","useEffect","useMemo","useRef","useState","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","workflowJobSearchParams","workflowRunSearchParams","JobExecutionTimeText","RunWorkspaceNav","workspaceSlug","projectSlug","run","activeSection","currentJobId","jobSearch","annotationSummary","jobs","sort","compareJobs","mobileOpen","setMobileOpen","currentJob","find","job","id","currentLabel","displayName","sectionLabel","intervalMs","reducedMotionIntervalMs","aside","className","open","onOpenChange","asChild","button","type","aria-label","span","as","size","name","aria-hidden","div","RunWorkspaceNavContent","onNavigate","currentRowRef","runAttempt","attempt","current","scrollIntoView","block","nav","ul","li","RunSectionLink","runId","section","aria-labelledby","bold","length","ol","map","execution","duration","displayDuration","ref","undefined","to","params","workflowRunId","jobId","search","onClick","aria-current","status","tooltip","time","count","total","countTruncated","truncated","tab","left","right","position","localeCompare"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"sourcesContent":["import {Collapsible, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n type Job,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobExecutionTimeText} from '../job-detail/job-execution-time-text.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface RunWorkspaceNavProps {\n workspaceSlug: string;\n projectSlug: string;\n run: WorkflowRunDetail;\n activeSection: RunWorkspaceSection;\n currentJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n annotationSummary?: RunAnnotationSummary | undefined;\n}\n\n/**\n * The stable navigation model shared by run-level and job-level routes. The graph explains\n * topology; this compact index makes moving between dedicated job pages predictable.\n */\nexport function RunWorkspaceNav({\n workspaceSlug,\n projectSlug,\n run,\n activeSection,\n currentJobId,\n jobSearch = {},\n annotationSummary,\n}: RunWorkspaceNavProps) {\n const jobs = useMemo(() => [...run.jobs].sort(compareJobs), [run.jobs]);\n const [mobileOpen, setMobileOpen] = useState(false);\n const currentJob = jobs.find((job) => job.id === currentJobId);\n const currentLabel = currentJob?.displayName ?? sectionLabel(activeSection);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside className=\"flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r\">\n <Collapsible\n open={mobileOpen}\n onOpenChange={setMobileOpen}\n className=\"flex min-h-0 flex-col min-[768px]:flex-1\"\n >\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex min-h-44 w-full items-center justify-between gap-cluster px-row text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden\"\n aria-label=\"Toggle run navigation\"\n >\n <span className=\"min-w-0\">\n <Text as=\"span\" size=\"xs\" className=\"block text-foreground-neutral-muted\">\n Run navigation\n </Text>\n <span className=\"block truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {currentLabel}\n </span>\n </span>\n <Icon\n name=\"chevronDown\"\n size={14}\n aria-hidden=\"true\"\n className={cn(\n 'shrink-0 text-foreground-neutral-muted transition-transform',\n mobileOpen && 'rotate-180',\n )}\n />\n </button>\n </CollapsibleTrigger>\n <div\n className={cn(\n 'flex min-h-0 max-h-[50vh] flex-col overflow-y-auto p-tight scrollbar min-[768px]:min-h-0 min-[768px]:max-h-none min-[768px]:flex-1 min-[768px]:flex min-[768px]:overflow-hidden min-[768px]:p-[12px]',\n !mobileOpen && 'hidden',\n )}\n >\n <RunWorkspaceNavContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={run}\n jobs={jobs}\n activeSection={activeSection}\n currentJobId={currentJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n mobileOpen={mobileOpen}\n onNavigate={() => setMobileOpen(false)}\n />\n </div>\n </Collapsible>\n </aside>\n </TimeTickerProvider>\n );\n}\n\nfunction RunWorkspaceNavContent({\n workspaceSlug,\n projectSlug,\n run,\n jobs,\n activeSection,\n currentJobId,\n jobSearch,\n annotationSummary,\n mobileOpen,\n onNavigate,\n}: RunWorkspaceNavProps & {\n jobs: Job[];\n jobSearch: WorkflowJobSearch;\n mobileOpen: boolean;\n onNavigate: () => void;\n}) {\n const currentRowRef = useRef<HTMLAnchorElement>(null);\n const runAttempt = jobSearch.runAttempt ?? run.runAttempt.attempt;\n\n useEffect(() => {\n if (!currentJobId || mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n useEffect(() => {\n if (!currentJobId || !mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n return (\n <nav aria-label=\"Run workspace\" className=\"flex min-h-0 min-w-0 flex-1 flex-col gap-group\">\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"summary\"\n current={!currentJobId && activeSection === 'summary'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n\n <section\n aria-labelledby=\"run-workspace-jobs-heading\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n >\n <div className=\"flex items-center justify-between gap-inline px-tight pb-[6px]\">\n <Text\n as=\"h2\"\n id=\"run-workspace-jobs-heading\"\n size=\"xs\"\n bold\n className=\"text-foreground-neutral-muted\"\n >\n Jobs\n </Text>\n <Text as=\"span\" size=\"xs\" className=\"font-code text-foreground-neutral-subtle\">\n {jobs.length}\n </Text>\n </div>\n <ol className=\"min-h-0 flex-1 overflow-y-auto scrollbar\">\n {jobs.map((job) => {\n const current = job.id === currentJobId;\n const execution = defaultJobExecution(job);\n const duration = execution?.displayDuration ?? job.displayDuration;\n\n return (\n <li key={job.id}>\n <Link\n ref={current ? currentRowRef : undefined}\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id, jobId: job.id}}\n search={workflowJobSearchParams({runAttempt}) as never}\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n className={cn(\n 'flex min-h-32 min-w-0 items-center gap-inline rounded-4 px-tight text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n <WorkflowStatusIcon\n status={deriveJobDisplayStatus(job)}\n size={12}\n tooltip={false}\n />\n <span className=\"min-w-0 truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {job.displayName}\n </span>\n <span className=\"ml-auto shrink-0 font-code text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n {duration ? <JobExecutionTimeText time={duration} /> : '—'}\n </span>\n </Link>\n </li>\n );\n })}\n </ol>\n </section>\n\n <section aria-labelledby=\"run-workspace-details-heading\">\n <Text\n as=\"h2\"\n id=\"run-workspace-details-heading\"\n size=\"xs\"\n bold\n className=\"px-tight pb-[6px] text-foreground-neutral-muted\"\n >\n Run details\n </Text>\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"annotations\"\n current={!currentJobId && activeSection === 'annotations'}\n count={annotationSummary?.total}\n countTruncated={annotationSummary?.truncated}\n onNavigate={onNavigate}\n />\n </li>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"source\"\n current={!currentJobId && activeSection === 'source'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n </section>\n </nav>\n );\n}\n\nfunction RunSectionLink({\n workspaceSlug,\n projectSlug,\n runId,\n runAttempt,\n section,\n current,\n count,\n countTruncated = false,\n onNavigate,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n runAttempt: number;\n section: RunWorkspaceSection;\n current: boolean;\n count?: number | undefined;\n /** The read hit its page budget, so the count is a lower bound and renders as `N+`. */\n countTruncated?: boolean | undefined;\n onNavigate?: (() => void) | undefined;\n}) {\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId}}\n search={\n workflowRunSearchParams(\n {runAttempt, ...(section === 'summary' ? {} : {tab: section})},\n {runAttempt},\n ) as never\n }\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n aria-label={\n count\n ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}`\n : undefined\n }\n className={cn(\n 'flex min-h-32 items-center gap-inline rounded-4 px-tight text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n {sectionLabel(section)}\n {count ? (\n <span\n aria-hidden=\"true\"\n className=\"ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums\"\n >\n {count}\n {countTruncated ? '+' : ''}\n </span>\n ) : null}\n </Link>\n );\n}\n\nfunction sectionLabel(section: RunWorkspaceSection): string {\n if (section === 'annotations') return 'Annotations';\n if (section === 'source') return 'Source';\n return 'Summary';\n}\n\nfunction compareJobs(left: Job, right: Job): number {\n return left.position - right.position || left.id.localeCompare(right.id);\n}\n"],"names":["Collapsible","CollapsibleTrigger","Icon","TimeTickerProvider","Text","cn","Link","useEffect","useMemo","useRef","useState","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","workflowJobSearchParams","workflowRunSearchParams","JobExecutionTimeText","RunWorkspaceNav","workspaceSlug","projectSlug","run","activeSection","currentJobId","jobSearch","annotationSummary","jobs","sort","compareJobs","mobileOpen","setMobileOpen","currentJob","find","job","id","currentLabel","displayName","sectionLabel","intervalMs","reducedMotionIntervalMs","aside","className","open","onOpenChange","asChild","button","type","aria-label","span","as","size","name","aria-hidden","div","RunWorkspaceNavContent","onNavigate","currentRowRef","runAttempt","attempt","current","scrollIntoView","block","nav","ul","li","RunSectionLink","runId","section","aria-labelledby","bold","length","ol","map","execution","duration","displayDuration","ref","undefined","to","params","workflowRunId","jobId","search","onClick","aria-current","status","tooltip","time","count","total","countTruncated","truncated","tab","left","right","position","localeCompare"],"mappings":"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"}
|
|
@@ -7,12 +7,12 @@ import { Text } from '@shipfox/react-ui/typography';
|
|
|
7
7
|
export function WorkflowRunSkeleton() {
|
|
8
8
|
return /*#__PURE__*/ _jsx("section", {
|
|
9
9
|
"aria-label": "Loading workflow run",
|
|
10
|
-
className: "bg-background-neutral-background px-
|
|
10
|
+
className: "bg-background-neutral-background px-row py-row",
|
|
11
11
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
12
|
-
className: "flex min-w-0 flex-wrap items-center gap-x-
|
|
12
|
+
className: "flex min-w-0 flex-wrap items-center gap-x-cluster gap-y-inline",
|
|
13
13
|
children: [
|
|
14
14
|
/*#__PURE__*/ _jsxs("div", {
|
|
15
|
-
className: "flex min-w-0 items-center gap-
|
|
15
|
+
className: "flex min-w-0 items-center gap-inline",
|
|
16
16
|
children: [
|
|
17
17
|
/*#__PURE__*/ _jsx(Skeleton, {
|
|
18
18
|
className: "size-8 rounded-full"
|
|
@@ -51,7 +51,7 @@ export function WorkflowRunSkeleton() {
|
|
|
51
51
|
export function WorkflowRunContentSkeleton() {
|
|
52
52
|
return /*#__PURE__*/ _jsx("section", {
|
|
53
53
|
"aria-label": "Loading workflow run content",
|
|
54
|
-
className: "min-h-160 rounded-8 border border-border-neutral-base bg-background-components-base p-
|
|
54
|
+
className: "min-h-160 rounded-8 border border-border-neutral-base bg-background-components-base p-panel-compact",
|
|
55
55
|
children: /*#__PURE__*/ _jsx(Skeleton, {
|
|
56
56
|
className: "h-160 w-full rounded-6"
|
|
57
57
|
})
|
|
@@ -70,12 +70,12 @@ export function WorkflowRunNotFound() {
|
|
|
70
70
|
* screen with an inline retry instead of being wiped by a full error placeholder.
|
|
71
71
|
*/ export function WorkflowRunStaleError({ query }) {
|
|
72
72
|
return /*#__PURE__*/ _jsx("div", {
|
|
73
|
-
className: "border-b border-border-neutral-base p-
|
|
73
|
+
className: "border-b border-border-neutral-base p-tight",
|
|
74
74
|
children: /*#__PURE__*/ _jsx(Callout, {
|
|
75
75
|
role: "alert",
|
|
76
76
|
type: "error",
|
|
77
77
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
78
|
-
className: "flex items-center justify-between gap-
|
|
78
|
+
className: "flex items-center justify-between gap-inline",
|
|
79
79
|
children: [
|
|
80
80
|
/*#__PURE__*/ _jsx(Text, {
|
|
81
81
|
size: "xs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-view/workflow-run-states.tsx"],"sourcesContent":["import type {QueryLoadErrorQuery} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\n\nexport function WorkflowRunSkeleton() {\n return (\n <section\n aria-label=\"Loading workflow run\"\n className=\"bg-background-neutral-background px-
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-view/workflow-run-states.tsx"],"sourcesContent":["import type {QueryLoadErrorQuery} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\n\nexport function WorkflowRunSkeleton() {\n return (\n <section\n aria-label=\"Loading workflow run\"\n className=\"bg-background-neutral-background px-row py-row\"\n >\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-cluster gap-y-inline\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Skeleton className=\"size-8 rounded-full\" />\n <Skeleton className=\"h-24 w-180 rounded-6\" />\n </div>\n <Skeleton className=\"h-24 w-88 rounded-6\" />\n <span\n aria-hidden=\"true\"\n className=\"hidden h-20 w-px shrink-0 bg-border-neutral-base sm:block\"\n />\n <Skeleton className=\"h-20 w-64 rounded-4\" />\n <Skeleton className=\"h-20 w-112 rounded-4\" />\n <span className=\"min-w-0 flex-1\" />\n <Skeleton className=\"h-20 w-88 rounded-4\" />\n <Skeleton className=\"h-20 w-88 rounded-4\" />\n </div>\n </section>\n );\n}\n\nexport function WorkflowRunContentSkeleton() {\n return (\n <section\n aria-label=\"Loading workflow run content\"\n className=\"min-h-160 rounded-8 border border-border-neutral-base bg-background-components-base p-panel-compact\"\n >\n <Skeleton className=\"h-160 w-full rounded-6\" />\n </section>\n );\n}\n\nexport function WorkflowRunNotFound() {\n return (\n <EmptyState\n icon=\"pulseLine\"\n title=\"Run not found\"\n description=\"This run does not exist or is no longer available.\"\n />\n );\n}\n\n/**\n * Slim non-blocking banner shown when a background refetch fails after the run already\n * loaded (active-run polling can hit a transient API error), so the loaded run stays on\n * screen with an inline retry instead of being wiped by a full error placeholder.\n */\nexport function WorkflowRunStaleError({query}: {query: QueryLoadErrorQuery}) {\n return (\n <div className=\"border-b border-border-neutral-base p-tight\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\">Could not refresh this run.</Text>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n isLoading={query.isFetching}\n onClick={() => {\n void query.refetch();\n }}\n >\n Retry\n </Button>\n </div>\n </Callout>\n </div>\n );\n}\n"],"names":["Button","Callout","EmptyState","Skeleton","Text","WorkflowRunSkeleton","section","aria-label","className","div","span","aria-hidden","WorkflowRunContentSkeleton","WorkflowRunNotFound","icon","title","description","WorkflowRunStaleError","query","role","type","size","variant","isLoading","isFetching","onClick","refetch"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,IAAI,QAAO,+BAA+B;AAElD,OAAO,SAASC;IACd,qBACE,KAACC;QACCC,cAAW;QACXC,WAAU;kBAEV,cAAA,MAACC;YAAID,WAAU;;8BACb,MAACC;oBAAID,WAAU;;sCACb,KAACL;4BAASK,WAAU;;sCACpB,KAACL;4BAASK,WAAU;;;;8BAEtB,KAACL;oBAASK,WAAU;;8BACpB,KAACE;oBACCC,eAAY;oBACZH,WAAU;;8BAEZ,KAACL;oBAASK,WAAU;;8BACpB,KAACL;oBAASK,WAAU;;8BACpB,KAACE;oBAAKF,WAAU;;8BAChB,KAACL;oBAASK,WAAU;;8BACpB,KAACL;oBAASK,WAAU;;;;;AAI5B;AAEA,OAAO,SAASI;IACd,qBACE,KAACN;QACCC,cAAW;QACXC,WAAU;kBAEV,cAAA,KAACL;YAASK,WAAU;;;AAG1B;AAEA,OAAO,SAASK;IACd,qBACE,KAACX;QACCY,MAAK;QACLC,OAAM;QACNC,aAAY;;AAGlB;AAEA;;;;CAIC,GACD,OAAO,SAASC,sBAAsB,EAACC,KAAK,EAA+B;IACzE,qBACE,KAACT;QAAID,WAAU;kBACb,cAAA,KAACP;YAAQkB,MAAK;YAAQC,MAAK;sBACzB,cAAA,MAACX;gBAAID,WAAU;;kCACb,KAACJ;wBAAKiB,MAAK;kCAAK;;kCAChB,KAACrB;wBACCoB,MAAK;wBACLC,MAAK;wBACLC,SAAQ;wBACRC,WAAWL,MAAMM,UAAU;wBAC3BC,SAAS;4BACP,KAAKP,MAAMQ,OAAO;wBACpB;kCACD;;;;;;AAOX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-run-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-run-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAezD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAqB3B,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC3C,GAAG,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,EACT,GAAG,EACH,WAAW,EACX,SAAS,EACT,UAAU,GACX,EAAE,oBAAoB,+BA0CtB"}
|
|
@@ -245,7 +245,7 @@ function RunViewContent({ workspaceSlug, projectSlug, query, annotations, rerunM
|
|
|
245
245
|
sourceSnapshot: sourceSnapshot,
|
|
246
246
|
highlightedLineRange: highlightedLineRange
|
|
247
247
|
}) : /*#__PURE__*/ _jsx("div", {
|
|
248
|
-
className: "min-h-0 flex-1 overflow-auto p-
|
|
248
|
+
className: "min-h-0 flex-1 overflow-auto p-panel",
|
|
249
249
|
children: loadingOrError
|
|
250
250
|
})
|
|
251
251
|
})
|
|
@@ -258,9 +258,9 @@ function RunSectionContent({ section, run, annotations, annotationSummary, works
|
|
|
258
258
|
if (section === 'summary') {
|
|
259
259
|
return /*#__PURE__*/ _jsx("section", {
|
|
260
260
|
"aria-label": "All jobs summary",
|
|
261
|
-
className: "min-h-0 flex-1 overflow-auto pb-
|
|
261
|
+
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
262
262
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
263
|
-
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-
|
|
263
|
+
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame",
|
|
264
264
|
children: [
|
|
265
265
|
/*#__PURE__*/ _jsx(Text, {
|
|
266
266
|
as: "h2",
|
|
@@ -292,9 +292,9 @@ function RunSectionContent({ section, run, annotations, annotationSummary, works
|
|
|
292
292
|
}
|
|
293
293
|
return /*#__PURE__*/ _jsx("section", {
|
|
294
294
|
"aria-label": "Workflow source",
|
|
295
|
-
className: "min-h-0 flex-1 overflow-auto pb-
|
|
295
|
+
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
296
296
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
297
|
-
className: "mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-
|
|
297
|
+
className: "mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-frame",
|
|
298
298
|
children: [
|
|
299
299
|
/*#__PURE__*/ _jsx(Text, {
|
|
300
300
|
as: "h2",
|
|
@@ -330,11 +330,29 @@ function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceS
|
|
|
330
330
|
selectedJob?.id,
|
|
331
331
|
severity
|
|
332
332
|
]);
|
|
333
|
+
const derivedAnnotations = useMemo(()=>{
|
|
334
|
+
if (!records) return undefined;
|
|
335
|
+
const jobsWithAnnotations = new Set(records.map((annotation)=>annotation.jobId));
|
|
336
|
+
return run.jobs.filter((job)=>{
|
|
337
|
+
const style = job.status === 'failed' ? 'error' : 'warning';
|
|
338
|
+
return (!selectedJob || selectedJob.id === job.id) && !jobsWithAnnotations.has(job.id) && (job.status === 'failed' || job.status === 'skipped') && job.jobExecutions.length === 0 && matchesDerivedAnnotationFilters(style, selection);
|
|
339
|
+
}).map((job)=>({
|
|
340
|
+
id: `derived-${job.id}`,
|
|
341
|
+
style: job.status === 'failed' ? 'error' : 'warning',
|
|
342
|
+
body: derivedJobAnnotation(job)
|
|
343
|
+
}));
|
|
344
|
+
}, [
|
|
345
|
+
records,
|
|
346
|
+
run.jobs,
|
|
347
|
+
selectedJob,
|
|
348
|
+
selection
|
|
349
|
+
]);
|
|
350
|
+
const hasSynthesizedJobAnnotations = run.jobs.some((job)=>(job.status === 'failed' || job.status === 'skipped') && job.jobExecutions.length === 0);
|
|
333
351
|
return /*#__PURE__*/ _jsx("section", {
|
|
334
352
|
"aria-label": "Run annotations",
|
|
335
|
-
className: "min-h-0 flex-1 overflow-auto pb-
|
|
353
|
+
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
336
354
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
337
|
-
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-
|
|
355
|
+
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame",
|
|
338
356
|
children: [
|
|
339
357
|
/*#__PURE__*/ _jsx(Text, {
|
|
340
358
|
as: "h2",
|
|
@@ -342,7 +360,7 @@ function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceS
|
|
|
342
360
|
children: "Annotations"
|
|
343
361
|
}),
|
|
344
362
|
/*#__PURE__*/ _jsxs("div", {
|
|
345
|
-
className: "flex flex-wrap items-center justify-between gap-
|
|
363
|
+
className: "flex flex-wrap items-center justify-between gap-inline",
|
|
346
364
|
children: [
|
|
347
365
|
/*#__PURE__*/ _jsx(RunAnnotationSummaryLine, {
|
|
348
366
|
summary: annotationSummary,
|
|
@@ -361,12 +379,13 @@ function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceS
|
|
|
361
379
|
/*#__PURE__*/ _jsx(RunAnnotationList, {
|
|
362
380
|
query: annotations.query,
|
|
363
381
|
entries: entries,
|
|
382
|
+
derivedAnnotations: derivedAnnotations,
|
|
364
383
|
workspaceSlug: workspaceSlug,
|
|
365
384
|
projectSlug: projectSlug,
|
|
366
385
|
workflowRunId: run.id,
|
|
367
386
|
runAttempt: run.runAttempt.attempt,
|
|
368
387
|
// A run with no annotations at all offers no filter to clear, whatever the URL says.
|
|
369
|
-
filtered: Boolean((severity || selectedJob) && (annotationSummary?.total ?? 0) > 0),
|
|
388
|
+
filtered: Boolean((severity || selectedJob || selection?.annotation) && ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations)),
|
|
370
389
|
filteredJobName: selectedJob?.displayName,
|
|
371
390
|
filteredSeverity: severity,
|
|
372
391
|
onClearFilters: onClearAnnotationFilters,
|
|
@@ -376,6 +395,47 @@ function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceS
|
|
|
376
395
|
})
|
|
377
396
|
});
|
|
378
397
|
}
|
|
398
|
+
function matchesDerivedAnnotationFilters(style, selection) {
|
|
399
|
+
if (selection?.severity && style !== selection.severity) return false;
|
|
400
|
+
// A selected annotation is a deep-link to a real annotation record. Synthetic diagnostics
|
|
401
|
+
// have no id or context, so they must not remain visible behind that selection.
|
|
402
|
+
return !selection?.annotation;
|
|
403
|
+
}
|
|
404
|
+
function derivedJobAnnotation(job) {
|
|
405
|
+
const reason = job.statusReason ? `Reason: \`${job.statusReason}\`` : null;
|
|
406
|
+
const traceSummary = formatConditionEvaluation(job.evaluationTrace);
|
|
407
|
+
const details = [
|
|
408
|
+
reason,
|
|
409
|
+
traceSummary
|
|
410
|
+
].filter(Boolean).join('\n');
|
|
411
|
+
if (job.status === 'skipped') {
|
|
412
|
+
return [
|
|
413
|
+
`**${job.displayName}** was skipped before an execution was created.`,
|
|
414
|
+
'',
|
|
415
|
+
'Review its dependencies or condition before re-running.',
|
|
416
|
+
details
|
|
417
|
+
].filter(Boolean).join('\n');
|
|
418
|
+
}
|
|
419
|
+
return [
|
|
420
|
+
`**${job.displayName}** failed before an execution was created.`,
|
|
421
|
+
'',
|
|
422
|
+
'Check runner availability and workflow configuration before re-running.',
|
|
423
|
+
details
|
|
424
|
+
].filter(Boolean).join('\n');
|
|
425
|
+
}
|
|
426
|
+
function formatConditionEvaluation(trace) {
|
|
427
|
+
if (!trace?.length) return null;
|
|
428
|
+
return [
|
|
429
|
+
'Condition evaluation:',
|
|
430
|
+
...trace.map((entry)=>{
|
|
431
|
+
if ('dropped' in entry) {
|
|
432
|
+
return `- ${entry.dropped} additional evaluation${entry.dropped === 1 ? '' : 's'} not recorded`;
|
|
433
|
+
}
|
|
434
|
+
const value = entry.value === undefined || entry.value === '' ? '(empty)' : `\`${entry.value}\``;
|
|
435
|
+
return `- \`${entry.field}\` evaluated \`${entry.expression}\` to ${value}${entry.degraded ? ' (degraded)' : ''}`;
|
|
436
|
+
})
|
|
437
|
+
].join('\n');
|
|
438
|
+
}
|
|
379
439
|
const ALL_ANNOTATION_JOBS = 'all-jobs';
|
|
380
440
|
function AnnotationJobFilter({ jobs, selectedJobId, onSelect }) {
|
|
381
441
|
const sortedJobs = [
|
|
@@ -410,15 +470,15 @@ function AnnotationJobFilter({ jobs, selectedJobId, onSelect }) {
|
|
|
410
470
|
function RunWorkspaceNavSkeleton() {
|
|
411
471
|
return /*#__PURE__*/ _jsx("aside", {
|
|
412
472
|
"aria-label": "Loading run navigation",
|
|
413
|
-
className: "hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-
|
|
473
|
+
className: "hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-panel-compact min-[768px]:block",
|
|
414
474
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
415
|
-
className: "flex flex-col gap-
|
|
475
|
+
className: "flex flex-col gap-group",
|
|
416
476
|
children: [
|
|
417
477
|
/*#__PURE__*/ _jsx("div", {
|
|
418
478
|
className: "h-32 rounded-4 bg-background-components-subtle"
|
|
419
479
|
}),
|
|
420
480
|
/*#__PURE__*/ _jsxs("div", {
|
|
421
|
-
className: "flex flex-col gap-
|
|
481
|
+
className: "flex flex-col gap-inline",
|
|
422
482
|
children: [
|
|
423
483
|
/*#__PURE__*/ _jsx("div", {
|
|
424
484
|
className: "h-16 w-64 rounded-4 bg-background-components-subtle"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@shipfox/react-ui/select';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useNavigate} from '@tanstack/react-router';\nimport {type ReactNode, useEffect, useMemo} from 'react';\nimport {buildRunAnnotationList, type RunAnnotationSummary} from '#core/run-annotation.js';\nimport {isWorkflowRunTerminal, type Job, type WorkflowRunRerunMode} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {useRunAnnotationsQuery} from '#hooks/api/run-annotations.js';\nimport {\n useCancelWorkflowRunMutation,\n useRerunWorkflowRunMutation,\n useWorkflowRunAttemptQuery,\n} from '#hooks/api/workflow-runs.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunsSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobGraph} from '../job-graph/index.js';\nimport type {JobGraphSelectionSource} from '../job-graph/types.js';\nimport {WorkflowRunSummary} from '../workflow-run-summary/index.js';\nimport {RunAnnotationList, RunAnnotationSummaryLine} from '../workflow-run-tabs/index.js';\nimport {WorkflowSourceContent} from '../workflow-source-panel/index.js';\nimport {RunWorkspaceNav} from './run-workspace-nav.js';\nimport {resolveWorkflowRunSelection} from './workflow-run-selection.js';\nimport {\n WorkflowRunContentSkeleton,\n WorkflowRunNotFound,\n WorkflowRunSkeleton,\n WorkflowRunStaleError,\n} from './workflow-run-states.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface WorkflowRunViewProps {\n projectId: string;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n workflowRunId?: string | undefined;\n runAttempt?: number | undefined;\n selection?: WorkflowRunsSearch | undefined;\n tab?: WorkflowRunTab | undefined;\n activeJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n jobContent?: ReactNode | undefined;\n}\n\n/**\n * The persistent run workspace. Run-level sections and dedicated job routes share the same\n * header and job index, while the all-jobs Summary always opens on the dependency graph.\n */\nexport function WorkflowRunView({\n projectId,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n selection,\n tab,\n activeJobId,\n jobSearch,\n jobContent,\n}: WorkflowRunViewProps) {\n const runQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: selection?.runAttempt ?? runAttempt,\n });\n const rerunMutation = useRerunWorkflowRunMutation(projectId);\n // Annotations are read on their own cadence rather than hydrated into the run, so the two\n // modules stay decoupled. The key is shared, so the job page's count chip costs no extra fetch.\n //\n // Polling is scoped to the surface that renders bodies. The read has no counts-only mode, so\n // every poll transfers whole Markdown bodies; doing that every four seconds behind Summary,\n // Source, and the job log spends megabytes to keep one rail number warm. Off that surface the\n // counts still refresh on navigation and on window focus.\n const annotationsQuery = useRunAnnotationsQuery({\n workflowRunId,\n runAttempt: runQuery.data?.runAttempt.attempt,\n live:\n runWorkspaceSection(tab) === 'annotations' &&\n !activeJobId &&\n Boolean(runQuery.data) &&\n !isWorkflowRunTerminal(runQuery.data?.runAttempt.status ?? 'pending'),\n });\n\n return (\n <RelativeTimeProvider>\n <div className=\"flex min-h-0 min-w-0 flex-1 overflow-hidden\">\n <RunViewContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n query={runQuery}\n annotations={annotationsQuery}\n rerunMutation={rerunMutation}\n runAttempt={runAttempt}\n selection={selection}\n tab={tab}\n activeJobId={activeJobId}\n jobSearch={jobSearch}\n jobContent={jobContent}\n />\n </div>\n </RelativeTimeProvider>\n );\n}\n\nfunction RunViewContent({\n workspaceSlug,\n projectSlug,\n query,\n annotations,\n rerunMutation,\n runAttempt,\n selection,\n tab,\n activeJobId,\n jobSearch,\n jobContent,\n}: {\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n query: ReturnType<typeof useWorkflowRunAttemptQuery>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n rerunMutation: ReturnType<typeof useRerunWorkflowRunMutation>;\n runAttempt: number | undefined;\n selection: WorkflowRunsSearch | undefined;\n tab: WorkflowRunTab | undefined;\n activeJobId: string | undefined;\n jobSearch: WorkflowJobSearch | undefined;\n jobContent: ReactNode | undefined;\n}) {\n const navigate = useNavigate();\n const runData = query.data;\n const annotationSummary = annotations.summary;\n const activeSection = runWorkspaceSection(tab);\n const cancelMutation = useCancelWorkflowRunMutation(runData);\n const sourceSnapshot = runData?.sourceSnapshot ?? null;\n const resolvedSelection =\n runData && selection ? resolveWorkflowRunSelection({run: runData, selection}) : undefined;\n const highlightedLineRange = resolvedSelection?.step?.sourceLocation ?? null;\n\n useEffect(() => {\n const hasLegacyJobSelection = Boolean(\n selection?.jobId ||\n selection?.jobExecutionId ||\n selection?.stepId ||\n selection?.stepAttemptId,\n );\n if (\n activeJobId ||\n activeSection !== 'summary' ||\n !hasLegacyJobSelection ||\n !resolvedSelection?.job ||\n !runData ||\n !workspaceSlug ||\n !projectSlug\n ) {\n return;\n }\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',\n params: {\n workspaceSlug,\n projectSlug,\n workflowRunId: runData.id,\n jobId: resolvedSelection.job.id,\n },\n search: workflowJobSearchParams({\n jobExecutionId: selection?.jobExecutionId,\n stepId: selection?.stepId,\n stepAttemptId: selection?.stepAttemptId,\n runAttempt: selection?.runAttempt,\n }) as never,\n replace: true,\n });\n }, [\n activeJobId,\n activeSection,\n navigate,\n projectSlug,\n resolvedSelection?.job,\n runData,\n selection,\n workspaceSlug,\n ]);\n\n async function rerun(mode: WorkflowRunRerunMode) {\n if (!runData || !workspaceSlug || !projectSlug) {\n toast.error('Could not start re-run from this route.');\n return;\n }\n try {\n const run = await rerunMutation.mutateAsync({workflowRunId: runData.id, mode});\n toast.success('Re-run started');\n await navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: run.id},\n search: ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never,\n });\n } catch (error) {\n toast.error(error instanceof ApiError ? error.message : 'Could not start re-run');\n }\n }\n\n function selectGraphJob(jobId: string | undefined, source: JobGraphSelectionSource = 'pointer') {\n if (source !== 'pointer' || !jobId || !runData || !workspaceSlug || !projectSlug) return;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id, jobId},\n search: workflowJobSearchParams({\n runAttempt: selection?.runAttempt ?? runAttempt ?? runData.runAttempt.attempt,\n }) as never,\n });\n }\n\n function selectAnnotationJob(jobId: string | undefined) {\n if (!runData || !workspaceSlug || !projectSlug) return;\n const nextSearch: WorkflowRunsSearch = {...selection, tab: 'annotations'};\n if (jobId) nextSearch.jobId = jobId;\n else delete nextSearch.jobId;\n delete nextSearch.jobExecutionId;\n delete nextSearch.stepId;\n delete nextSearch.stepAttemptId;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id},\n search: workflowRunSearchParams(nextSearch, nextSearch) as never,\n });\n }\n\n function clearAnnotationFilters() {\n if (!runData || !workspaceSlug || !projectSlug) return;\n const nextSearch: WorkflowRunsSearch = {...selection, tab: 'annotations'};\n delete nextSearch.jobId;\n delete nextSearch.jobExecutionId;\n delete nextSearch.stepId;\n delete nextSearch.stepAttemptId;\n delete nextSearch.severity;\n delete nextSearch.annotation;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id},\n search: workflowRunSearchParams(nextSearch, nextSearch) as never,\n replace: true,\n });\n }\n\n function cancelRun() {\n cancelMutation.mutate(undefined, {\n onError: (error) => toast.error(cancelErrorMessage(error)),\n });\n }\n\n const fatalError = query.isError && runData === undefined;\n const loadingOrError = fatalError ? (\n query.error instanceof ApiError && query.error.status === 404 ? (\n <WorkflowRunNotFound />\n ) : (\n <QueryLoadError query={query} subject=\"workflow run\" icon=\"pulseLine\" />\n )\n ) : query.isPending || runData === undefined ? (\n <WorkflowRunContentSkeleton />\n ) : null;\n\n return (\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {runData ? (\n <WorkflowRunSummary\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={runData}\n cancelling={cancelMutation.isPending}\n onCancel={cancelRun}\n rerunPending={rerunMutation.isPending}\n onRerun={(mode) => void rerun(mode)}\n latestAttempt={runData.latestAttempt}\n />\n ) : (\n <WorkflowRunSkeleton />\n )}\n {runData && query.isError ? <WorkflowRunStaleError query={query} /> : null}\n\n <div\n data-run-workspace-layout\n className=\"flex min-h-0 min-w-0 flex-1 flex-col border-t border-border-neutral-base min-[768px]:flex-row\"\n >\n {runData && workspaceSlug && projectSlug ? (\n <RunWorkspaceNav\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={runData}\n activeSection={activeSection}\n currentJobId={activeJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n />\n ) : (\n <RunWorkspaceNavSkeleton />\n )}\n\n <div\n data-run-workspace-content\n className=\"flex min-h-0 min-w-0 flex-1 flex-col bg-background-neutral-base\"\n >\n {runData && jobContent ? (\n jobContent\n ) : runData ? (\n <RunSectionContent\n section={activeSection}\n run={runData}\n annotations={annotations}\n annotationSummary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n selection={selection}\n selectedJobId={selection?.jobId}\n onSelectGraphJob={selectGraphJob}\n onSelectAnnotationJob={selectAnnotationJob}\n onClearAnnotationFilters={clearAnnotationFilters}\n sourceSnapshot={sourceSnapshot}\n highlightedLineRange={highlightedLineRange}\n />\n ) : (\n <div className=\"min-h-0 flex-1 overflow-auto p-24\">{loadingOrError}</div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction RunSectionContent({\n section,\n run,\n annotations,\n annotationSummary,\n workspaceSlug,\n projectSlug,\n selection,\n selectedJobId,\n onSelectGraphJob,\n onSelectAnnotationJob,\n onClearAnnotationFilters,\n sourceSnapshot,\n highlightedLineRange,\n}: {\n section: RunWorkspaceSection;\n run: NonNullable<ReturnType<typeof useWorkflowRunAttemptQuery>['data']>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n annotationSummary: RunAnnotationSummary | undefined;\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n selection: WorkflowRunsSearch | undefined;\n selectedJobId: string | undefined;\n onSelectGraphJob: (jobId: string | undefined, source?: JobGraphSelectionSource) => void;\n onSelectAnnotationJob: (jobId: string | undefined) => void;\n onClearAnnotationFilters: () => void;\n sourceSnapshot: NonNullable<\n ReturnType<typeof useWorkflowRunAttemptQuery>['data']\n >['sourceSnapshot'];\n highlightedLineRange: NonNullable<\n ReturnType<typeof useWorkflowRunAttemptQuery>['data']\n >['jobs'][number]['jobExecutions'][number]['steps'][number]['sourceLocation'];\n}) {\n if (section === 'summary') {\n return (\n <section aria-label=\"All jobs summary\" className=\"min-h-0 flex-1 overflow-auto pb-24 pt-16\">\n <div className=\"mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24\">\n <Text as=\"h2\" className=\"sr-only\">\n All jobs summary\n </Text>\n <JobGraph\n run={run}\n selectedJobId={selectedJobId}\n onSelectedJobChange={onSelectGraphJob}\n className=\"min-h-160 overflow-hidden\"\n />\n </div>\n </section>\n );\n }\n\n if (section === 'annotations') {\n return (\n <RunAnnotationsSection\n run={run}\n annotations={annotations}\n annotationSummary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n selection={selection}\n selectedJobId={selectedJobId}\n onSelectAnnotationJob={onSelectAnnotationJob}\n onClearAnnotationFilters={onClearAnnotationFilters}\n />\n );\n }\n\n return (\n <section aria-label=\"Workflow source\" className=\"min-h-0 flex-1 overflow-auto pb-24 pt-16\">\n <div className=\"mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-24\">\n <Text as=\"h2\" className=\"sr-only\">\n Workflow source\n </Text>\n {sourceSnapshot ? (\n <WorkflowSourceContent\n source={sourceSnapshot}\n highlightedLineRange={highlightedLineRange}\n scrollHighlightedIntoView\n />\n ) : (\n <EmptyState\n className=\"min-h-160 w-full\"\n icon=\"fileDamageLine\"\n title=\"Source snapshot unavailable\"\n description={\n run.isTemporary\n ? 'Temporary runs do not capture workflow source.'\n : 'This run was created before workflow source snapshots were captured.'\n }\n />\n )}\n </div>\n </section>\n );\n}\n\nfunction RunAnnotationsSection({\n run,\n annotations,\n annotationSummary,\n workspaceSlug,\n projectSlug,\n selection,\n selectedJobId,\n onSelectAnnotationJob,\n onClearAnnotationFilters,\n}: {\n run: NonNullable<ReturnType<typeof useWorkflowRunAttemptQuery>['data']>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n annotationSummary: RunAnnotationSummary | undefined;\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n selection: WorkflowRunsSearch | undefined;\n selectedJobId: string | undefined;\n onSelectAnnotationJob: (jobId: string | undefined) => void;\n onClearAnnotationFilters: () => void;\n}) {\n const selectedJob = run.jobs.find((job) => job.id === selectedJobId);\n const severity = selection?.severity;\n const records = annotations.annotations;\n\n const entries = useMemo(\n () =>\n records\n ? buildRunAnnotationList({\n annotations: records,\n jobs: run.jobs,\n severity,\n jobId: selectedJob?.id,\n })\n : undefined,\n [records, run.jobs, selectedJob?.id, severity],\n );\n\n return (\n <section aria-label=\"Run annotations\" className=\"min-h-0 flex-1 overflow-auto pb-24 pt-16\">\n <div className=\"mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24\">\n <Text as=\"h2\" className=\"sr-only\">\n Annotations\n </Text>\n <div className=\"flex flex-wrap items-center justify-between gap-8\">\n <RunAnnotationSummaryLine\n summary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n search={selection}\n />\n <AnnotationJobFilter\n jobs={run.jobs}\n selectedJobId={selectedJob?.id}\n onSelect={onSelectAnnotationJob}\n />\n </div>\n <RunAnnotationList\n // Remounting on a filter or run-attempt change resets the render window, so the next\n // list never inherits a \"show more\" position from different data.\n key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}\n query={annotations.query}\n entries={entries}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n runAttempt={run.runAttempt.attempt}\n // A run with no annotations at all offers no filter to clear, whatever the URL says.\n filtered={Boolean((severity || selectedJob) && (annotationSummary?.total ?? 0) > 0)}\n filteredJobName={selectedJob?.displayName}\n filteredSeverity={severity}\n onClearFilters={onClearAnnotationFilters}\n selectedAnnotationId={selection?.annotation}\n />\n </div>\n </section>\n );\n}\n\nconst ALL_ANNOTATION_JOBS = 'all-jobs';\n\nfunction AnnotationJobFilter({\n jobs,\n selectedJobId,\n onSelect,\n}: {\n jobs: Job[];\n selectedJobId: string | undefined;\n onSelect: (jobId: string | undefined) => void;\n}) {\n const sortedJobs = [...jobs].sort(\n (left, right) => left.position - right.position || left.id.localeCompare(right.id),\n );\n\n return (\n <Select\n value={selectedJobId ?? ALL_ANNOTATION_JOBS}\n onValueChange={(value) => onSelect(value === ALL_ANNOTATION_JOBS ? undefined : value)}\n >\n <SelectTrigger\n size=\"small\"\n aria-label=\"Filter annotations by job\"\n className=\"w-full min-[480px]:w-240\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent align=\"end\">\n <SelectItem value={ALL_ANNOTATION_JOBS}>All jobs</SelectItem>\n {sortedJobs.map((job) => (\n <SelectItem key={job.id} value={job.id}>\n {job.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\nfunction RunWorkspaceNavSkeleton() {\n return (\n <aside\n aria-label=\"Loading run navigation\"\n className=\"hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-12 min-[768px]:block\"\n >\n <div className=\"flex flex-col gap-16\">\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n <div className=\"flex flex-col gap-6\">\n <div className=\"h-16 w-64 rounded-4 bg-background-components-subtle\" />\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n </div>\n </div>\n </aside>\n );\n}\n\nfunction runWorkspaceSection(tab: WorkflowRunTab | undefined): RunWorkspaceSection {\n return tab === 'annotations' || tab === 'source' ? tab : 'summary';\n}\n\nfunction cancelErrorMessage(error: unknown): string {\n if (error instanceof ApiError && error.code === 'run-already-finished') {\n return 'This workflow run has already finished.';\n }\n return 'Could not cancel workflow run.';\n}\n"],"names":["ApiError","QueryLoadError","EmptyState","RelativeTimeProvider","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","toast","Text","useNavigate","useEffect","useMemo","buildRunAnnotationList","isWorkflowRunTerminal","withoutWorkflowRunSelectionSearch","useRunAnnotationsQuery","useCancelWorkflowRunMutation","useRerunWorkflowRunMutation","useWorkflowRunAttemptQuery","workflowJobSearchParams","workflowRunSearchParams","JobGraph","WorkflowRunSummary","RunAnnotationList","RunAnnotationSummaryLine","WorkflowSourceContent","RunWorkspaceNav","resolveWorkflowRunSelection","WorkflowRunContentSkeleton","WorkflowRunNotFound","WorkflowRunSkeleton","WorkflowRunStaleError","WorkflowRunView","projectId","workspaceSlug","projectSlug","workflowRunId","runAttempt","selection","tab","activeJobId","jobSearch","jobContent","runQuery","rerunMutation","annotationsQuery","data","attempt","live","runWorkspaceSection","Boolean","status","div","className","RunViewContent","query","annotations","navigate","runData","annotationSummary","summary","activeSection","cancelMutation","sourceSnapshot","resolvedSelection","run","undefined","highlightedLineRange","step","sourceLocation","hasLegacyJobSelection","jobId","jobExecutionId","stepId","stepAttemptId","job","to","params","id","search","replace","rerun","mode","error","mutateAsync","success","previous","message","selectGraphJob","source","selectAnnotationJob","nextSearch","clearAnnotationFilters","severity","annotation","cancelRun","mutate","onError","cancelErrorMessage","fatalError","isError","loadingOrError","subject","icon","isPending","cancelling","onCancel","rerunPending","onRerun","latestAttempt","data-run-workspace-layout","currentJobId","RunWorkspaceNavSkeleton","data-run-workspace-content","RunSectionContent","section","selectedJobId","onSelectGraphJob","onSelectAnnotationJob","onClearAnnotationFilters","aria-label","as","onSelectedJobChange","RunAnnotationsSection","scrollHighlightedIntoView","title","description","isTemporary","selectedJob","jobs","find","records","entries","AnnotationJobFilter","onSelect","filtered","total","filteredJobName","displayName","filteredSeverity","onClearFilters","selectedAnnotationId","ALL_ANNOTATION_JOBS","sortedJobs","sort","left","right","position","localeCompare","value","onValueChange","size","align","map","aside","code"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@shipfox/react-ui/select';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useNavigate} from '@tanstack/react-router';\nimport {type ReactNode, useEffect, useMemo} from 'react';\nimport {buildRunAnnotationList, type RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n type EvaluationTraceEntry,\n isWorkflowRunTerminal,\n type Job,\n type WorkflowRunRerunMode,\n} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {useRunAnnotationsQuery} from '#hooks/api/run-annotations.js';\nimport {\n useCancelWorkflowRunMutation,\n useRerunWorkflowRunMutation,\n useWorkflowRunAttemptQuery,\n} from '#hooks/api/workflow-runs.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunsSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobGraph} from '../job-graph/index.js';\nimport type {JobGraphSelectionSource} from '../job-graph/types.js';\nimport {WorkflowRunSummary} from '../workflow-run-summary/index.js';\nimport {\n type DerivedRunAnnotation,\n RunAnnotationList,\n RunAnnotationSummaryLine,\n} from '../workflow-run-tabs/index.js';\nimport {WorkflowSourceContent} from '../workflow-source-panel/index.js';\nimport {RunWorkspaceNav} from './run-workspace-nav.js';\nimport {resolveWorkflowRunSelection} from './workflow-run-selection.js';\nimport {\n WorkflowRunContentSkeleton,\n WorkflowRunNotFound,\n WorkflowRunSkeleton,\n WorkflowRunStaleError,\n} from './workflow-run-states.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface WorkflowRunViewProps {\n projectId: string;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n workflowRunId?: string | undefined;\n runAttempt?: number | undefined;\n selection?: WorkflowRunsSearch | undefined;\n tab?: WorkflowRunTab | undefined;\n activeJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n jobContent?: ReactNode | undefined;\n}\n\n/**\n * The persistent run workspace. Run-level sections and dedicated job routes share the same\n * header and job index, while the all-jobs Summary always opens on the dependency graph.\n */\nexport function WorkflowRunView({\n projectId,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n selection,\n tab,\n activeJobId,\n jobSearch,\n jobContent,\n}: WorkflowRunViewProps) {\n const runQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: selection?.runAttempt ?? runAttempt,\n });\n const rerunMutation = useRerunWorkflowRunMutation(projectId);\n // Annotations are read on their own cadence rather than hydrated into the run, so the two\n // modules stay decoupled. The key is shared, so the job page's count chip costs no extra fetch.\n //\n // Polling is scoped to the surface that renders bodies. The read has no counts-only mode, so\n // every poll transfers whole Markdown bodies; doing that every four seconds behind Summary,\n // Source, and the job log spends megabytes to keep one rail number warm. Off that surface the\n // counts still refresh on navigation and on window focus.\n const annotationsQuery = useRunAnnotationsQuery({\n workflowRunId,\n runAttempt: runQuery.data?.runAttempt.attempt,\n live:\n runWorkspaceSection(tab) === 'annotations' &&\n !activeJobId &&\n Boolean(runQuery.data) &&\n !isWorkflowRunTerminal(runQuery.data?.runAttempt.status ?? 'pending'),\n });\n\n return (\n <RelativeTimeProvider>\n <div className=\"flex min-h-0 min-w-0 flex-1 overflow-hidden\">\n <RunViewContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n query={runQuery}\n annotations={annotationsQuery}\n rerunMutation={rerunMutation}\n runAttempt={runAttempt}\n selection={selection}\n tab={tab}\n activeJobId={activeJobId}\n jobSearch={jobSearch}\n jobContent={jobContent}\n />\n </div>\n </RelativeTimeProvider>\n );\n}\n\nfunction RunViewContent({\n workspaceSlug,\n projectSlug,\n query,\n annotations,\n rerunMutation,\n runAttempt,\n selection,\n tab,\n activeJobId,\n jobSearch,\n jobContent,\n}: {\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n query: ReturnType<typeof useWorkflowRunAttemptQuery>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n rerunMutation: ReturnType<typeof useRerunWorkflowRunMutation>;\n runAttempt: number | undefined;\n selection: WorkflowRunsSearch | undefined;\n tab: WorkflowRunTab | undefined;\n activeJobId: string | undefined;\n jobSearch: WorkflowJobSearch | undefined;\n jobContent: ReactNode | undefined;\n}) {\n const navigate = useNavigate();\n const runData = query.data;\n const annotationSummary = annotations.summary;\n const activeSection = runWorkspaceSection(tab);\n const cancelMutation = useCancelWorkflowRunMutation(runData);\n const sourceSnapshot = runData?.sourceSnapshot ?? null;\n const resolvedSelection =\n runData && selection ? resolveWorkflowRunSelection({run: runData, selection}) : undefined;\n const highlightedLineRange = resolvedSelection?.step?.sourceLocation ?? null;\n\n useEffect(() => {\n const hasLegacyJobSelection = Boolean(\n selection?.jobId ||\n selection?.jobExecutionId ||\n selection?.stepId ||\n selection?.stepAttemptId,\n );\n if (\n activeJobId ||\n activeSection !== 'summary' ||\n !hasLegacyJobSelection ||\n !resolvedSelection?.job ||\n !runData ||\n !workspaceSlug ||\n !projectSlug\n ) {\n return;\n }\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',\n params: {\n workspaceSlug,\n projectSlug,\n workflowRunId: runData.id,\n jobId: resolvedSelection.job.id,\n },\n search: workflowJobSearchParams({\n jobExecutionId: selection?.jobExecutionId,\n stepId: selection?.stepId,\n stepAttemptId: selection?.stepAttemptId,\n runAttempt: selection?.runAttempt,\n }) as never,\n replace: true,\n });\n }, [\n activeJobId,\n activeSection,\n navigate,\n projectSlug,\n resolvedSelection?.job,\n runData,\n selection,\n workspaceSlug,\n ]);\n\n async function rerun(mode: WorkflowRunRerunMode) {\n if (!runData || !workspaceSlug || !projectSlug) {\n toast.error('Could not start re-run from this route.');\n return;\n }\n try {\n const run = await rerunMutation.mutateAsync({workflowRunId: runData.id, mode});\n toast.success('Re-run started');\n await navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: run.id},\n search: ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never,\n });\n } catch (error) {\n toast.error(error instanceof ApiError ? error.message : 'Could not start re-run');\n }\n }\n\n function selectGraphJob(jobId: string | undefined, source: JobGraphSelectionSource = 'pointer') {\n if (source !== 'pointer' || !jobId || !runData || !workspaceSlug || !projectSlug) return;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id, jobId},\n search: workflowJobSearchParams({\n runAttempt: selection?.runAttempt ?? runAttempt ?? runData.runAttempt.attempt,\n }) as never,\n });\n }\n\n function selectAnnotationJob(jobId: string | undefined) {\n if (!runData || !workspaceSlug || !projectSlug) return;\n const nextSearch: WorkflowRunsSearch = {...selection, tab: 'annotations'};\n if (jobId) nextSearch.jobId = jobId;\n else delete nextSearch.jobId;\n delete nextSearch.jobExecutionId;\n delete nextSearch.stepId;\n delete nextSearch.stepAttemptId;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id},\n search: workflowRunSearchParams(nextSearch, nextSearch) as never,\n });\n }\n\n function clearAnnotationFilters() {\n if (!runData || !workspaceSlug || !projectSlug) return;\n const nextSearch: WorkflowRunsSearch = {...selection, tab: 'annotations'};\n delete nextSearch.jobId;\n delete nextSearch.jobExecutionId;\n delete nextSearch.stepId;\n delete nextSearch.stepAttemptId;\n delete nextSearch.severity;\n delete nextSearch.annotation;\n\n void navigate({\n to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',\n params: {workspaceSlug, projectSlug, workflowRunId: runData.id},\n search: workflowRunSearchParams(nextSearch, nextSearch) as never,\n replace: true,\n });\n }\n\n function cancelRun() {\n cancelMutation.mutate(undefined, {\n onError: (error) => toast.error(cancelErrorMessage(error)),\n });\n }\n\n const fatalError = query.isError && runData === undefined;\n const loadingOrError = fatalError ? (\n query.error instanceof ApiError && query.error.status === 404 ? (\n <WorkflowRunNotFound />\n ) : (\n <QueryLoadError query={query} subject=\"workflow run\" icon=\"pulseLine\" />\n )\n ) : query.isPending || runData === undefined ? (\n <WorkflowRunContentSkeleton />\n ) : null;\n\n return (\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col\">\n {runData ? (\n <WorkflowRunSummary\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={runData}\n cancelling={cancelMutation.isPending}\n onCancel={cancelRun}\n rerunPending={rerunMutation.isPending}\n onRerun={(mode) => void rerun(mode)}\n latestAttempt={runData.latestAttempt}\n />\n ) : (\n <WorkflowRunSkeleton />\n )}\n {runData && query.isError ? <WorkflowRunStaleError query={query} /> : null}\n\n <div\n data-run-workspace-layout\n className=\"flex min-h-0 min-w-0 flex-1 flex-col border-t border-border-neutral-base min-[768px]:flex-row\"\n >\n {runData && workspaceSlug && projectSlug ? (\n <RunWorkspaceNav\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={runData}\n activeSection={activeSection}\n currentJobId={activeJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n />\n ) : (\n <RunWorkspaceNavSkeleton />\n )}\n\n <div\n data-run-workspace-content\n className=\"flex min-h-0 min-w-0 flex-1 flex-col bg-background-neutral-base\"\n >\n {runData && jobContent ? (\n jobContent\n ) : runData ? (\n <RunSectionContent\n section={activeSection}\n run={runData}\n annotations={annotations}\n annotationSummary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n selection={selection}\n selectedJobId={selection?.jobId}\n onSelectGraphJob={selectGraphJob}\n onSelectAnnotationJob={selectAnnotationJob}\n onClearAnnotationFilters={clearAnnotationFilters}\n sourceSnapshot={sourceSnapshot}\n highlightedLineRange={highlightedLineRange}\n />\n ) : (\n <div className=\"min-h-0 flex-1 overflow-auto p-panel\">{loadingOrError}</div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction RunSectionContent({\n section,\n run,\n annotations,\n annotationSummary,\n workspaceSlug,\n projectSlug,\n selection,\n selectedJobId,\n onSelectGraphJob,\n onSelectAnnotationJob,\n onClearAnnotationFilters,\n sourceSnapshot,\n highlightedLineRange,\n}: {\n section: RunWorkspaceSection;\n run: NonNullable<ReturnType<typeof useWorkflowRunAttemptQuery>['data']>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n annotationSummary: RunAnnotationSummary | undefined;\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n selection: WorkflowRunsSearch | undefined;\n selectedJobId: string | undefined;\n onSelectGraphJob: (jobId: string | undefined, source?: JobGraphSelectionSource) => void;\n onSelectAnnotationJob: (jobId: string | undefined) => void;\n onClearAnnotationFilters: () => void;\n sourceSnapshot: NonNullable<\n ReturnType<typeof useWorkflowRunAttemptQuery>['data']\n >['sourceSnapshot'];\n highlightedLineRange: NonNullable<\n ReturnType<typeof useWorkflowRunAttemptQuery>['data']\n >['jobs'][number]['jobExecutions'][number]['steps'][number]['sourceLocation'];\n}) {\n if (section === 'summary') {\n return (\n <section\n aria-label=\"All jobs summary\"\n className=\"min-h-0 flex-1 overflow-auto pb-panel pt-[16px]\"\n >\n <div className=\"mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame\">\n <Text as=\"h2\" className=\"sr-only\">\n All jobs summary\n </Text>\n <JobGraph\n run={run}\n selectedJobId={selectedJobId}\n onSelectedJobChange={onSelectGraphJob}\n className=\"min-h-160 overflow-hidden\"\n />\n </div>\n </section>\n );\n }\n\n if (section === 'annotations') {\n return (\n <RunAnnotationsSection\n run={run}\n annotations={annotations}\n annotationSummary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n selection={selection}\n selectedJobId={selectedJobId}\n onSelectAnnotationJob={onSelectAnnotationJob}\n onClearAnnotationFilters={onClearAnnotationFilters}\n />\n );\n }\n\n return (\n <section\n aria-label=\"Workflow source\"\n className=\"min-h-0 flex-1 overflow-auto pb-panel pt-[16px]\"\n >\n <div className=\"mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-frame\">\n <Text as=\"h2\" className=\"sr-only\">\n Workflow source\n </Text>\n {sourceSnapshot ? (\n <WorkflowSourceContent\n source={sourceSnapshot}\n highlightedLineRange={highlightedLineRange}\n scrollHighlightedIntoView\n />\n ) : (\n <EmptyState\n className=\"min-h-160 w-full\"\n icon=\"fileDamageLine\"\n title=\"Source snapshot unavailable\"\n description={\n run.isTemporary\n ? 'Temporary runs do not capture workflow source.'\n : 'This run was created before workflow source snapshots were captured.'\n }\n />\n )}\n </div>\n </section>\n );\n}\n\nfunction RunAnnotationsSection({\n run,\n annotations,\n annotationSummary,\n workspaceSlug,\n projectSlug,\n selection,\n selectedJobId,\n onSelectAnnotationJob,\n onClearAnnotationFilters,\n}: {\n run: NonNullable<ReturnType<typeof useWorkflowRunAttemptQuery>['data']>;\n annotations: ReturnType<typeof useRunAnnotationsQuery>;\n annotationSummary: RunAnnotationSummary | undefined;\n workspaceSlug: string | undefined;\n projectSlug: string | undefined;\n selection: WorkflowRunsSearch | undefined;\n selectedJobId: string | undefined;\n onSelectAnnotationJob: (jobId: string | undefined) => void;\n onClearAnnotationFilters: () => void;\n}) {\n const selectedJob = run.jobs.find((job) => job.id === selectedJobId);\n const severity = selection?.severity;\n const records = annotations.annotations;\n\n const entries = useMemo(\n () =>\n records\n ? buildRunAnnotationList({\n annotations: records,\n jobs: run.jobs,\n severity,\n jobId: selectedJob?.id,\n })\n : undefined,\n [records, run.jobs, selectedJob?.id, severity],\n );\n const derivedAnnotations = useMemo<readonly DerivedRunAnnotation[] | undefined>(() => {\n if (!records) return undefined;\n const jobsWithAnnotations = new Set(records.map((annotation) => annotation.jobId));\n\n return run.jobs\n .filter((job) => {\n const style = job.status === 'failed' ? 'error' : 'warning';\n return (\n (!selectedJob || selectedJob.id === job.id) &&\n !jobsWithAnnotations.has(job.id) &&\n (job.status === 'failed' || job.status === 'skipped') &&\n job.jobExecutions.length === 0 &&\n matchesDerivedAnnotationFilters(style, selection)\n );\n })\n .map((job) => ({\n id: `derived-${job.id}`,\n style: job.status === 'failed' ? 'error' : 'warning',\n body: derivedJobAnnotation(job),\n }));\n }, [records, run.jobs, selectedJob, selection]);\n const hasSynthesizedJobAnnotations = run.jobs.some(\n (job) =>\n (job.status === 'failed' || job.status === 'skipped') && job.jobExecutions.length === 0,\n );\n\n return (\n <section\n aria-label=\"Run annotations\"\n className=\"min-h-0 flex-1 overflow-auto pb-panel pt-[16px]\"\n >\n <div className=\"mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame\">\n <Text as=\"h2\" className=\"sr-only\">\n Annotations\n </Text>\n <div className=\"flex flex-wrap items-center justify-between gap-inline\">\n <RunAnnotationSummaryLine\n summary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n search={selection}\n />\n <AnnotationJobFilter\n jobs={run.jobs}\n selectedJobId={selectedJob?.id}\n onSelect={onSelectAnnotationJob}\n />\n </div>\n <RunAnnotationList\n // Remounting on a filter or run-attempt change resets the render window, so the next\n // list never inherits a \"show more\" position from different data.\n key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}\n query={annotations.query}\n entries={entries}\n derivedAnnotations={derivedAnnotations}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n runAttempt={run.runAttempt.attempt}\n // A run with no annotations at all offers no filter to clear, whatever the URL says.\n filtered={Boolean(\n (severity || selectedJob || selection?.annotation) &&\n ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations),\n )}\n filteredJobName={selectedJob?.displayName}\n filteredSeverity={severity}\n onClearFilters={onClearAnnotationFilters}\n selectedAnnotationId={selection?.annotation}\n />\n </div>\n </section>\n );\n}\n\nfunction matchesDerivedAnnotationFilters(\n style: 'warning' | 'error',\n selection: WorkflowRunsSearch | undefined,\n): boolean {\n if (selection?.severity && style !== selection.severity) return false;\n // A selected annotation is a deep-link to a real annotation record. Synthetic diagnostics\n // have no id or context, so they must not remain visible behind that selection.\n return !selection?.annotation;\n}\n\nfunction derivedJobAnnotation(job: Job): string {\n const reason = job.statusReason ? `Reason: \\`${job.statusReason}\\`` : null;\n const traceSummary = formatConditionEvaluation(job.evaluationTrace);\n const details = [reason, traceSummary].filter(Boolean).join('\\n');\n\n if (job.status === 'skipped') {\n return [\n `**${job.displayName}** was skipped before an execution was created.`,\n '',\n 'Review its dependencies or condition before re-running.',\n details,\n ]\n .filter(Boolean)\n .join('\\n');\n }\n return [\n `**${job.displayName}** failed before an execution was created.`,\n '',\n 'Check runner availability and workflow configuration before re-running.',\n details,\n ]\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction formatConditionEvaluation(\n trace: readonly EvaluationTraceEntry[] | null | undefined,\n): string | null {\n if (!trace?.length) return null;\n\n return [\n 'Condition evaluation:',\n ...trace.map((entry) => {\n if ('dropped' in entry) {\n return `- ${entry.dropped} additional evaluation${entry.dropped === 1 ? '' : 's'} not recorded`;\n }\n const value =\n entry.value === undefined || entry.value === '' ? '(empty)' : `\\`${entry.value}\\``;\n return `- \\`${entry.field}\\` evaluated \\`${entry.expression}\\` to ${value}${entry.degraded ? ' (degraded)' : ''}`;\n }),\n ].join('\\n');\n}\n\nconst ALL_ANNOTATION_JOBS = 'all-jobs';\n\nfunction AnnotationJobFilter({\n jobs,\n selectedJobId,\n onSelect,\n}: {\n jobs: Job[];\n selectedJobId: string | undefined;\n onSelect: (jobId: string | undefined) => void;\n}) {\n const sortedJobs = [...jobs].sort(\n (left, right) => left.position - right.position || left.id.localeCompare(right.id),\n );\n\n return (\n <Select\n value={selectedJobId ?? ALL_ANNOTATION_JOBS}\n onValueChange={(value) => onSelect(value === ALL_ANNOTATION_JOBS ? undefined : value)}\n >\n <SelectTrigger\n size=\"small\"\n aria-label=\"Filter annotations by job\"\n className=\"w-full min-[480px]:w-240\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent align=\"end\">\n <SelectItem value={ALL_ANNOTATION_JOBS}>All jobs</SelectItem>\n {sortedJobs.map((job) => (\n <SelectItem key={job.id} value={job.id}>\n {job.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\nfunction RunWorkspaceNavSkeleton() {\n return (\n <aside\n aria-label=\"Loading run navigation\"\n className=\"hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-panel-compact min-[768px]:block\"\n >\n <div className=\"flex flex-col gap-group\">\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n <div className=\"flex flex-col gap-inline\">\n <div className=\"h-16 w-64 rounded-4 bg-background-components-subtle\" />\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n <div className=\"h-32 rounded-4 bg-background-components-subtle\" />\n </div>\n </div>\n </aside>\n );\n}\n\nfunction runWorkspaceSection(tab: WorkflowRunTab | undefined): RunWorkspaceSection {\n return tab === 'annotations' || tab === 'source' ? tab : 'summary';\n}\n\nfunction cancelErrorMessage(error: unknown): string {\n if (error instanceof ApiError && error.code === 'run-already-finished') {\n return 'This workflow run has already finished.';\n }\n return 'Could not cancel workflow run.';\n}\n"],"names":["ApiError","QueryLoadError","EmptyState","RelativeTimeProvider","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","toast","Text","useNavigate","useEffect","useMemo","buildRunAnnotationList","isWorkflowRunTerminal","withoutWorkflowRunSelectionSearch","useRunAnnotationsQuery","useCancelWorkflowRunMutation","useRerunWorkflowRunMutation","useWorkflowRunAttemptQuery","workflowJobSearchParams","workflowRunSearchParams","JobGraph","WorkflowRunSummary","RunAnnotationList","RunAnnotationSummaryLine","WorkflowSourceContent","RunWorkspaceNav","resolveWorkflowRunSelection","WorkflowRunContentSkeleton","WorkflowRunNotFound","WorkflowRunSkeleton","WorkflowRunStaleError","WorkflowRunView","projectId","workspaceSlug","projectSlug","workflowRunId","runAttempt","selection","tab","activeJobId","jobSearch","jobContent","runQuery","rerunMutation","annotationsQuery","data","attempt","live","runWorkspaceSection","Boolean","status","div","className","RunViewContent","query","annotations","navigate","runData","annotationSummary","summary","activeSection","cancelMutation","sourceSnapshot","resolvedSelection","run","undefined","highlightedLineRange","step","sourceLocation","hasLegacyJobSelection","jobId","jobExecutionId","stepId","stepAttemptId","job","to","params","id","search","replace","rerun","mode","error","mutateAsync","success","previous","message","selectGraphJob","source","selectAnnotationJob","nextSearch","clearAnnotationFilters","severity","annotation","cancelRun","mutate","onError","cancelErrorMessage","fatalError","isError","loadingOrError","subject","icon","isPending","cancelling","onCancel","rerunPending","onRerun","latestAttempt","data-run-workspace-layout","currentJobId","RunWorkspaceNavSkeleton","data-run-workspace-content","RunSectionContent","section","selectedJobId","onSelectGraphJob","onSelectAnnotationJob","onClearAnnotationFilters","aria-label","as","onSelectedJobChange","RunAnnotationsSection","scrollHighlightedIntoView","title","description","isTemporary","selectedJob","jobs","find","records","entries","derivedAnnotations","jobsWithAnnotations","Set","map","filter","style","has","jobExecutions","length","matchesDerivedAnnotationFilters","body","derivedJobAnnotation","hasSynthesizedJobAnnotations","some","AnnotationJobFilter","onSelect","filtered","total","filteredJobName","displayName","filteredSeverity","onClearFilters","selectedAnnotationId","reason","statusReason","traceSummary","formatConditionEvaluation","evaluationTrace","details","join","trace","entry","dropped","value","field","expression","degraded","ALL_ANNOTATION_JOBS","sortedJobs","sort","left","right","position","localeCompare","onValueChange","size","align","aside","code"],"mappings":"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"}
|