@shipfox/client-workflows 15.0.0 → 16.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/.storybook/preview.css +4 -0
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +21 -0
- package/dist/components/job-detail/job-detail-header.d.ts +8 -1
- package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-header.js +25 -12
- package/dist/components/job-detail/job-detail-header.js.map +1 -1
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-view.js +17 -2
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +1 -0
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +3 -0
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/index.js +3 -0
- package/dist/components/workflow-run-tabs/index.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.d.ts +16 -0
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js +50 -0
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-item.d.ts +20 -0
- package/dist/components/workflow-run-tabs/run-annotation-item.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-item.js +102 -0
- package/dist/components/workflow-run-tabs/run-annotation-item.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts +32 -0
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-list.js +202 -0
- package/dist/components/workflow-run-tabs/run-annotation-list.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts +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 +87 -22
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -1
- package/dist/components/workflow-run-tabs/severity-visuals.d.ts +20 -0
- package/dist/components/workflow-run-tabs/severity-visuals.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/severity-visuals.js +31 -0
- package/dist/components/workflow-run-tabs/severity-visuals.js.map +1 -0
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts +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 +9 -3
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts +1 -3
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +150 -52
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/core/run-annotation.d.ts +73 -0
- package/dist/core/run-annotation.d.ts.map +1 -0
- package/dist/core/run-annotation.js +125 -0
- package/dist/core/run-annotation.js.map +1 -0
- package/dist/hooks/api/run-annotation-mapper.d.ts +10 -0
- package/dist/hooks/api/run-annotation-mapper.d.ts.map +1 -0
- package/dist/hooks/api/run-annotation-mapper.js +22 -0
- package/dist/hooks/api/run-annotation-mapper.js.map +1 -0
- package/dist/hooks/api/run-annotations.d.ts +25 -0
- package/dist/hooks/api/run-annotations.d.ts.map +1 -0
- package/dist/hooks/api/run-annotations.js +78 -0
- package/dist/hooks/api/run-annotations.js.map +1 -0
- package/dist/routes/inputs.d.ts +7 -2
- package/dist/routes/inputs.d.ts.map +1 -1
- package/dist/routes/inputs.js +5 -6
- package/dist/routes/inputs.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -9
- package/src/components/job-detail/job-detail-header.test.tsx +3 -0
- package/src/components/job-detail/job-detail-header.tsx +30 -5
- package/src/components/job-detail/job-detail-view.stories.tsx +5 -0
- package/src/components/job-detail/job-detail-view.tsx +18 -1
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +1 -1
- package/src/components/workflow-run-tabs/index.ts +3 -0
- package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +63 -0
- package/src/components/workflow-run-tabs/run-annotation-item.tsx +123 -0
- package/src/components/workflow-run-tabs/run-annotation-list.tsx +258 -0
- package/src/components/workflow-run-tabs/run-annotation-summary-line.test.tsx +77 -3
- package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +92 -17
- package/src/components/workflow-run-tabs/run-annotations.stories.tsx +293 -0
- package/src/components/workflow-run-tabs/severity-visuals.ts +37 -0
- package/src/components/workflow-run-view/run-workspace-nav.test.tsx +44 -0
- package/src/components/workflow-run-view/run-workspace-nav.tsx +15 -2
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +246 -20
- package/src/components/workflow-run-view/workflow-run-view.tsx +148 -30
- package/src/core/run-annotation.test.ts +315 -0
- package/src/core/run-annotation.ts +238 -0
- package/src/hooks/api/run-annotation-mapper.ts +30 -0
- package/src/hooks/api/run-annotations.ts +137 -0
- package/src/pages/workflow-job-detail-page.test.tsx +66 -0
- package/src/routes/inputs.ts +7 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/core/workflow-run-tabs.d.ts +0 -9
- package/dist/core/workflow-run-tabs.d.ts.map +0 -1
- package/dist/core/workflow-run-tabs.js +0 -3
- package/dist/core/workflow-run-tabs.js.map +0 -1
- package/src/core/workflow-run-tabs.ts +0 -8
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IconName } from '@shipfox/react-ui/icon';
|
|
2
|
+
import type { RunAnnotationSeverity } from '#core/run-annotation.js';
|
|
3
|
+
/**
|
|
4
|
+
* The glyph vocabulary for annotation severity, shared by every count surface.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately the same marks the `Callout` uses on the cards themselves, so the glyph beside
|
|
7
|
+
* `1 error` in the summary is the glyph on the error card below it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SEVERITY_ICON: Record<RunAnnotationSeverity, IconName>;
|
|
10
|
+
/**
|
|
11
|
+
* Severity tone lives in the glyph, never in the label.
|
|
12
|
+
*
|
|
13
|
+
* Coloring the text would make severity compete with the brand accent, which this system
|
|
14
|
+
* reserves for links, focus, and "you are here". Shape plus tone in a 12px mark distinguishes
|
|
15
|
+
* an error from a warning without either of them shouting.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SEVERITY_ICON_TONE: Record<RunAnnotationSeverity, string>;
|
|
18
|
+
/** Hairline tone for a bordered count chip, matching the glyph it sits beside. */
|
|
19
|
+
export declare const SEVERITY_CHIP_TONE: Record<RunAnnotationSeverity, string>;
|
|
20
|
+
//# sourceMappingURL=severity-visuals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity-visuals.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-tabs/severity-visuals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,qBAAqB,EAAE,QAAQ,CAKjE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAKpE,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAKpE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The glyph vocabulary for annotation severity, shared by every count surface.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately the same marks the `Callout` uses on the cards themselves, so the glyph beside
|
|
5
|
+
* `1 error` in the summary is the glyph on the error card below it.
|
|
6
|
+
*/ export const SEVERITY_ICON = {
|
|
7
|
+
error: 'closeCircleFill',
|
|
8
|
+
warning: 'errorWarningFill',
|
|
9
|
+
info: 'info',
|
|
10
|
+
success: 'checkboxCircleFill'
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Severity tone lives in the glyph, never in the label.
|
|
14
|
+
*
|
|
15
|
+
* Coloring the text would make severity compete with the brand accent, which this system
|
|
16
|
+
* reserves for links, focus, and "you are here". Shape plus tone in a 12px mark distinguishes
|
|
17
|
+
* an error from a warning without either of them shouting.
|
|
18
|
+
*/ export const SEVERITY_ICON_TONE = {
|
|
19
|
+
error: 'text-tag-error-icon',
|
|
20
|
+
warning: 'text-tag-warning-icon',
|
|
21
|
+
info: 'text-tag-blue-icon',
|
|
22
|
+
success: 'text-tag-success-icon'
|
|
23
|
+
};
|
|
24
|
+
/** Hairline tone for a bordered count chip, matching the glyph it sits beside. */ export const SEVERITY_CHIP_TONE = {
|
|
25
|
+
error: 'border-tag-error-border text-tag-error-icon',
|
|
26
|
+
warning: 'border-tag-warning-border text-tag-warning-icon',
|
|
27
|
+
info: 'border-tag-blue-border text-tag-blue-icon',
|
|
28
|
+
success: 'border-tag-success-border text-tag-success-icon'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=severity-visuals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-tabs/severity-visuals.ts"],"sourcesContent":["import type {IconName} from '@shipfox/react-ui/icon';\nimport type {RunAnnotationSeverity} from '#core/run-annotation.js';\n\n/**\n * The glyph vocabulary for annotation severity, shared by every count surface.\n *\n * Deliberately the same marks the `Callout` uses on the cards themselves, so the glyph beside\n * `1 error` in the summary is the glyph on the error card below it.\n */\nexport const SEVERITY_ICON: Record<RunAnnotationSeverity, IconName> = {\n error: 'closeCircleFill',\n warning: 'errorWarningFill',\n info: 'info',\n success: 'checkboxCircleFill',\n};\n\n/**\n * Severity tone lives in the glyph, never in the label.\n *\n * Coloring the text would make severity compete with the brand accent, which this system\n * reserves for links, focus, and \"you are here\". Shape plus tone in a 12px mark distinguishes\n * an error from a warning without either of them shouting.\n */\nexport const SEVERITY_ICON_TONE: Record<RunAnnotationSeverity, string> = {\n error: 'text-tag-error-icon',\n warning: 'text-tag-warning-icon',\n info: 'text-tag-blue-icon',\n success: 'text-tag-success-icon',\n};\n\n/** Hairline tone for a bordered count chip, matching the glyph it sits beside. */\nexport const SEVERITY_CHIP_TONE: Record<RunAnnotationSeverity, string> = {\n error: 'border-tag-error-border text-tag-error-icon',\n warning: 'border-tag-warning-border text-tag-warning-icon',\n info: 'border-tag-blue-border text-tag-blue-icon',\n success: 'border-tag-success-border text-tag-success-icon',\n};\n"],"names":["SEVERITY_ICON","error","warning","info","success","SEVERITY_ICON_TONE","SEVERITY_CHIP_TONE"],"mappings":"AAGA;;;;;CAKC,GACD,OAAO,MAAMA,gBAAyD;IACpEC,OAAO;IACPC,SAAS;IACTC,MAAM;IACNC,SAAS;AACX,EAAE;AAEF;;;;;;CAMC,GACD,OAAO,MAAMC,qBAA4D;IACvEJ,OAAO;IACPC,SAAS;IACTC,MAAM;IACNC,SAAS;AACX,EAAE;AAEF,gFAAgF,GAChF,OAAO,MAAME,qBAA4D;IACvEL,OAAO;IACPC,SAAS;IACTC,MAAM;IACNC,SAAS;AACX,EAAE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { RunAnnotationSummary } from '#core/run-annotation.js';
|
|
1
2
|
import { type WorkflowRunDetail } from '#core/workflow-run.js';
|
|
2
|
-
import type { RunAnnotationSummary } from '#core/workflow-run-tabs.js';
|
|
3
3
|
import { type WorkflowJobSearch, type WorkflowRunTab } from '#routes/inputs.js';
|
|
4
4
|
type RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;
|
|
5
5
|
export interface RunWorkspaceNavProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-workspace-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"names":[],"mappings":"AAQA,OAAO,
|
|
1
|
+
{"version":3,"file":"run-workspace-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAG3B,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,iBAAiB,CAAC;IACvB,aAAa,EAAE,mBAAmB,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC1C,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACtD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,aAAa,EACb,WAAW,EACX,GAAG,EACH,aAAa,EACb,YAAY,EACZ,SAAc,EACd,iBAAiB,GAClB,EAAE,oBAAoB,+BA0DtB"}
|
|
@@ -210,6 +210,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
210
210
|
section: "annotations",
|
|
211
211
|
current: !currentJobId && activeSection === 'annotations',
|
|
212
212
|
count: annotationSummary?.total,
|
|
213
|
+
countTruncated: annotationSummary?.truncated,
|
|
213
214
|
onNavigate: onNavigate
|
|
214
215
|
})
|
|
215
216
|
}),
|
|
@@ -231,7 +232,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
231
232
|
]
|
|
232
233
|
});
|
|
233
234
|
}
|
|
234
|
-
function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section, current, count, onNavigate }) {
|
|
235
|
+
function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section, current, count, countTruncated = false, onNavigate }) {
|
|
235
236
|
return /*#__PURE__*/ _jsxs(Link, {
|
|
236
237
|
to: "/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId",
|
|
237
238
|
params: {
|
|
@@ -249,12 +250,17 @@ function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section
|
|
|
249
250
|
}),
|
|
250
251
|
onClick: onNavigate,
|
|
251
252
|
"aria-current": current ? 'page' : undefined,
|
|
253
|
+
"aria-label": count ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}` : undefined,
|
|
252
254
|
className: cn('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', current && 'bg-background-neutral-hover'),
|
|
253
255
|
children: [
|
|
254
256
|
sectionLabel(section),
|
|
255
|
-
count ? /*#__PURE__*/
|
|
257
|
+
count ? /*#__PURE__*/ _jsxs("span", {
|
|
258
|
+
"aria-hidden": "true",
|
|
256
259
|
className: "ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums",
|
|
257
|
-
children:
|
|
260
|
+
children: [
|
|
261
|
+
count,
|
|
262
|
+
countTruncated ? '+' : ''
|
|
263
|
+
]
|
|
258
264
|
}) : null
|
|
259
265
|
]
|
|
260
266
|
});
|
|
@@ -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 {\n defaultJobExecution,\n deriveJobDisplayStatus,\n type Job,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport type {RunAnnotationSummary} from '#core/workflow-run-tabs.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 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 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 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 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 className=\"ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums\">\n {count}\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","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=\"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,5 +1,4 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
import type { RunAnnotationSummary } from '#core/workflow-run-tabs.js';
|
|
3
2
|
import { type WorkflowJobSearch, type WorkflowRunsSearch, type WorkflowRunTab } from '#routes/inputs.js';
|
|
4
3
|
export interface WorkflowRunViewProps {
|
|
5
4
|
projectId: string;
|
|
@@ -9,7 +8,6 @@ export interface WorkflowRunViewProps {
|
|
|
9
8
|
runAttempt?: number | undefined;
|
|
10
9
|
selection?: WorkflowRunsSearch | undefined;
|
|
11
10
|
tab?: WorkflowRunTab | undefined;
|
|
12
|
-
annotationSummary?: RunAnnotationSummary | undefined;
|
|
13
11
|
activeJobId?: string | undefined;
|
|
14
12
|
jobSearch?: WorkflowJobSearch | undefined;
|
|
15
13
|
jobContent?: ReactNode | undefined;
|
|
@@ -18,5 +16,5 @@ export interface WorkflowRunViewProps {
|
|
|
18
16
|
* The persistent run workspace. Run-level sections and dedicated job routes share the same
|
|
19
17
|
* header and job index, while the all-jobs Summary always opens on the dependency graph.
|
|
20
18
|
*/
|
|
21
|
-
export declare function WorkflowRunView({ projectId, workspaceSlug, projectSlug, workflowRunId, runAttempt, selection, tab,
|
|
19
|
+
export declare function WorkflowRunView({ projectId, workspaceSlug, projectSlug, workflowRunId, runAttempt, selection, tab, activeJobId, jobSearch, jobContent, }: WorkflowRunViewProps): import("react").JSX.Element;
|
|
22
20
|
//# sourceMappingURL=workflow-run-view.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-run-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"names":[],"mappings":"
|
|
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;AAUzD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAiB3B,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"}
|
|
@@ -5,14 +5,18 @@ import { EmptyState } from '@shipfox/react-ui/empty-state';
|
|
|
5
5
|
import { RelativeTimeProvider } from '@shipfox/react-ui/relative-time';
|
|
6
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shipfox/react-ui/select';
|
|
7
7
|
import { toast } from '@shipfox/react-ui/toast';
|
|
8
|
+
import { Text } from '@shipfox/react-ui/typography';
|
|
8
9
|
import { useNavigate } from '@tanstack/react-router';
|
|
9
|
-
import { useEffect } from 'react';
|
|
10
|
+
import { useEffect, useMemo } from 'react';
|
|
11
|
+
import { buildRunAnnotationList } from '#core/run-annotation.js';
|
|
12
|
+
import { isWorkflowRunTerminal } from '#core/workflow-run.js';
|
|
10
13
|
import { withoutWorkflowRunSelectionSearch } from '#core/workflow-run-url-state.js';
|
|
14
|
+
import { useRunAnnotationsQuery } from '#hooks/api/run-annotations.js';
|
|
11
15
|
import { useCancelWorkflowRunMutation, useRerunWorkflowRunMutation, useWorkflowRunAttemptQuery } from '#hooks/api/workflow-runs.js';
|
|
12
16
|
import { workflowJobSearchParams, workflowRunSearchParams } from '#routes/inputs.js';
|
|
13
17
|
import { JobGraph } from '../job-graph/index.js';
|
|
14
18
|
import { WorkflowRunSummary } from '../workflow-run-summary/index.js';
|
|
15
|
-
import {
|
|
19
|
+
import { RunAnnotationList, RunAnnotationSummaryLine } from '../workflow-run-tabs/index.js';
|
|
16
20
|
import { WorkflowSourceContent } from '../workflow-source-panel/index.js';
|
|
17
21
|
import { RunWorkspaceNav } from './run-workspace-nav.js';
|
|
18
22
|
import { resolveWorkflowRunSelection } from './workflow-run-selection.js';
|
|
@@ -20,12 +24,24 @@ import { WorkflowRunContentSkeleton, WorkflowRunNotFound, WorkflowRunSkeleton, W
|
|
|
20
24
|
/**
|
|
21
25
|
* The persistent run workspace. Run-level sections and dedicated job routes share the same
|
|
22
26
|
* header and job index, while the all-jobs Summary always opens on the dependency graph.
|
|
23
|
-
*/ export function WorkflowRunView({ projectId, workspaceSlug, projectSlug, workflowRunId, runAttempt, selection, tab,
|
|
27
|
+
*/ export function WorkflowRunView({ projectId, workspaceSlug, projectSlug, workflowRunId, runAttempt, selection, tab, activeJobId, jobSearch, jobContent }) {
|
|
24
28
|
const runQuery = useWorkflowRunAttemptQuery({
|
|
25
29
|
workflowRunId,
|
|
26
30
|
runAttempt: selection?.runAttempt ?? runAttempt
|
|
27
31
|
});
|
|
28
32
|
const rerunMutation = useRerunWorkflowRunMutation(projectId);
|
|
33
|
+
// Annotations are read on their own cadence rather than hydrated into the run, so the two
|
|
34
|
+
// modules stay decoupled. The key is shared, so the job page's count chip costs no extra fetch.
|
|
35
|
+
//
|
|
36
|
+
// Polling is scoped to the surface that renders bodies. The read has no counts-only mode, so
|
|
37
|
+
// every poll transfers whole Markdown bodies; doing that every four seconds behind Summary,
|
|
38
|
+
// Source, and the job log spends megabytes to keep one rail number warm. Off that surface the
|
|
39
|
+
// counts still refresh on navigation and on window focus.
|
|
40
|
+
const annotationsQuery = useRunAnnotationsQuery({
|
|
41
|
+
workflowRunId,
|
|
42
|
+
runAttempt: runQuery.data?.runAttempt.attempt,
|
|
43
|
+
live: runWorkspaceSection(tab) === 'annotations' && !activeJobId && Boolean(runQuery.data) && !isWorkflowRunTerminal(runQuery.data?.runAttempt.status ?? 'pending')
|
|
44
|
+
});
|
|
29
45
|
return /*#__PURE__*/ _jsx(RelativeTimeProvider, {
|
|
30
46
|
children: /*#__PURE__*/ _jsx("div", {
|
|
31
47
|
className: "flex min-h-0 min-w-0 flex-1 overflow-hidden",
|
|
@@ -33,11 +49,11 @@ import { WorkflowRunContentSkeleton, WorkflowRunNotFound, WorkflowRunSkeleton, W
|
|
|
33
49
|
workspaceSlug: workspaceSlug,
|
|
34
50
|
projectSlug: projectSlug,
|
|
35
51
|
query: runQuery,
|
|
52
|
+
annotations: annotationsQuery,
|
|
36
53
|
rerunMutation: rerunMutation,
|
|
37
54
|
runAttempt: runAttempt,
|
|
38
55
|
selection: selection,
|
|
39
56
|
tab: tab,
|
|
40
|
-
annotationSummary: annotationSummary,
|
|
41
57
|
activeJobId: activeJobId,
|
|
42
58
|
jobSearch: jobSearch,
|
|
43
59
|
jobContent: jobContent
|
|
@@ -45,9 +61,10 @@ import { WorkflowRunContentSkeleton, WorkflowRunNotFound, WorkflowRunSkeleton, W
|
|
|
45
61
|
})
|
|
46
62
|
});
|
|
47
63
|
}
|
|
48
|
-
function RunViewContent({ workspaceSlug, projectSlug, query, rerunMutation, runAttempt, selection, tab,
|
|
64
|
+
function RunViewContent({ workspaceSlug, projectSlug, query, annotations, rerunMutation, runAttempt, selection, tab, activeJobId, jobSearch, jobContent }) {
|
|
49
65
|
const navigate = useNavigate();
|
|
50
66
|
const runData = query.data;
|
|
67
|
+
const annotationSummary = annotations.summary;
|
|
51
68
|
const activeSection = runWorkspaceSection(tab);
|
|
52
69
|
const cancelMutation = useCancelWorkflowRunMutation(runData);
|
|
53
70
|
const sourceSnapshot = runData?.sourceSnapshot ?? null;
|
|
@@ -147,6 +164,29 @@ function RunViewContent({ workspaceSlug, projectSlug, query, rerunMutation, runA
|
|
|
147
164
|
search: workflowRunSearchParams(nextSearch, nextSearch)
|
|
148
165
|
});
|
|
149
166
|
}
|
|
167
|
+
function clearAnnotationFilters() {
|
|
168
|
+
if (!runData || !workspaceSlug || !projectSlug) return;
|
|
169
|
+
const nextSearch = {
|
|
170
|
+
...selection,
|
|
171
|
+
tab: 'annotations'
|
|
172
|
+
};
|
|
173
|
+
delete nextSearch.jobId;
|
|
174
|
+
delete nextSearch.jobExecutionId;
|
|
175
|
+
delete nextSearch.stepId;
|
|
176
|
+
delete nextSearch.stepAttemptId;
|
|
177
|
+
delete nextSearch.severity;
|
|
178
|
+
delete nextSearch.annotation;
|
|
179
|
+
void navigate({
|
|
180
|
+
to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',
|
|
181
|
+
params: {
|
|
182
|
+
workspaceSlug,
|
|
183
|
+
projectSlug,
|
|
184
|
+
workflowRunId: runData.id
|
|
185
|
+
},
|
|
186
|
+
search: workflowRunSearchParams(nextSearch, nextSearch),
|
|
187
|
+
replace: true
|
|
188
|
+
});
|
|
189
|
+
}
|
|
150
190
|
function cancelRun() {
|
|
151
191
|
cancelMutation.mutate(undefined, {
|
|
152
192
|
onError: (error)=>toast.error(cancelErrorMessage(error))
|
|
@@ -193,6 +233,7 @@ function RunViewContent({ workspaceSlug, projectSlug, query, rerunMutation, runA
|
|
|
193
233
|
children: runData && jobContent ? jobContent : runData ? /*#__PURE__*/ _jsx(RunSectionContent, {
|
|
194
234
|
section: activeSection,
|
|
195
235
|
run: runData,
|
|
236
|
+
annotations: annotations,
|
|
196
237
|
annotationSummary: annotationSummary,
|
|
197
238
|
workspaceSlug: workspaceSlug,
|
|
198
239
|
projectSlug: projectSlug,
|
|
@@ -200,6 +241,7 @@ function RunViewContent({ workspaceSlug, projectSlug, query, rerunMutation, runA
|
|
|
200
241
|
selectedJobId: selection?.jobId,
|
|
201
242
|
onSelectGraphJob: selectGraphJob,
|
|
202
243
|
onSelectAnnotationJob: selectAnnotationJob,
|
|
244
|
+
onClearAnnotationFilters: clearAnnotationFilters,
|
|
203
245
|
sourceSnapshot: sourceSnapshot,
|
|
204
246
|
highlightedLineRange: highlightedLineRange
|
|
205
247
|
}) : /*#__PURE__*/ _jsx("div", {
|
|
@@ -212,69 +254,125 @@ function RunViewContent({ workspaceSlug, projectSlug, query, rerunMutation, runA
|
|
|
212
254
|
]
|
|
213
255
|
});
|
|
214
256
|
}
|
|
215
|
-
function RunSectionContent({ section, run, annotationSummary, workspaceSlug, projectSlug, selection, selectedJobId, onSelectGraphJob, onSelectAnnotationJob, sourceSnapshot, highlightedLineRange }) {
|
|
257
|
+
function RunSectionContent({ section, run, annotations, annotationSummary, workspaceSlug, projectSlug, selection, selectedJobId, onSelectGraphJob, onSelectAnnotationJob, onClearAnnotationFilters, sourceSnapshot, highlightedLineRange }) {
|
|
216
258
|
if (section === 'summary') {
|
|
217
259
|
return /*#__PURE__*/ _jsx("section", {
|
|
218
260
|
"aria-label": "All jobs summary",
|
|
219
261
|
className: "min-h-0 flex-1 overflow-auto pb-24 pt-16",
|
|
220
|
-
children: /*#__PURE__*/ _jsx("div", {
|
|
221
|
-
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24",
|
|
222
|
-
children: /*#__PURE__*/ _jsx(JobGraph, {
|
|
223
|
-
run: run,
|
|
224
|
-
selectedJobId: selectedJobId,
|
|
225
|
-
onSelectedJobChange: onSelectGraphJob,
|
|
226
|
-
className: "min-h-160 overflow-hidden"
|
|
227
|
-
})
|
|
228
|
-
})
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
if (section === 'annotations') {
|
|
232
|
-
const selectedJob = run.jobs.find((job)=>job.id === selectedJobId);
|
|
233
|
-
return /*#__PURE__*/ _jsx("section", {
|
|
234
|
-
"aria-label": "Run annotations",
|
|
235
|
-
className: "min-h-0 flex-1 overflow-auto pb-24 pt-16",
|
|
236
262
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
237
263
|
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24",
|
|
238
264
|
children: [
|
|
239
|
-
/*#__PURE__*/
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
summary: annotationSummary,
|
|
244
|
-
workspaceSlug: workspaceSlug,
|
|
245
|
-
projectSlug: projectSlug,
|
|
246
|
-
workflowRunId: run.id,
|
|
247
|
-
search: selection
|
|
248
|
-
}),
|
|
249
|
-
/*#__PURE__*/ _jsx(AnnotationJobFilter, {
|
|
250
|
-
jobs: run.jobs,
|
|
251
|
-
selectedJobId: selectedJob?.id,
|
|
252
|
-
onSelect: onSelectAnnotationJob
|
|
253
|
-
})
|
|
254
|
-
]
|
|
265
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
266
|
+
as: "h2",
|
|
267
|
+
className: "sr-only",
|
|
268
|
+
children: "All jobs summary"
|
|
255
269
|
}),
|
|
256
|
-
/*#__PURE__*/ _jsx(
|
|
257
|
-
|
|
270
|
+
/*#__PURE__*/ _jsx(JobGraph, {
|
|
271
|
+
run: run,
|
|
272
|
+
selectedJobId: selectedJobId,
|
|
273
|
+
onSelectedJobChange: onSelectGraphJob,
|
|
274
|
+
className: "min-h-160 overflow-hidden"
|
|
258
275
|
})
|
|
259
276
|
]
|
|
260
277
|
})
|
|
261
278
|
});
|
|
262
279
|
}
|
|
280
|
+
if (section === 'annotations') {
|
|
281
|
+
return /*#__PURE__*/ _jsx(RunAnnotationsSection, {
|
|
282
|
+
run: run,
|
|
283
|
+
annotations: annotations,
|
|
284
|
+
annotationSummary: annotationSummary,
|
|
285
|
+
workspaceSlug: workspaceSlug,
|
|
286
|
+
projectSlug: projectSlug,
|
|
287
|
+
selection: selection,
|
|
288
|
+
selectedJobId: selectedJobId,
|
|
289
|
+
onSelectAnnotationJob: onSelectAnnotationJob,
|
|
290
|
+
onClearAnnotationFilters: onClearAnnotationFilters
|
|
291
|
+
});
|
|
292
|
+
}
|
|
263
293
|
return /*#__PURE__*/ _jsx("section", {
|
|
264
294
|
"aria-label": "Workflow source",
|
|
265
295
|
className: "min-h-0 flex-1 overflow-auto pb-24 pt-16",
|
|
266
|
-
children: /*#__PURE__*/
|
|
267
|
-
className: "mx-auto flex min-h-full w-full max-w-[1120px] px-24",
|
|
268
|
-
children:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
296
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
297
|
+
className: "mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-24",
|
|
298
|
+
children: [
|
|
299
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
300
|
+
as: "h2",
|
|
301
|
+
className: "sr-only",
|
|
302
|
+
children: "Workflow source"
|
|
303
|
+
}),
|
|
304
|
+
sourceSnapshot ? /*#__PURE__*/ _jsx(WorkflowSourceContent, {
|
|
305
|
+
source: sourceSnapshot,
|
|
306
|
+
highlightedLineRange: highlightedLineRange,
|
|
307
|
+
scrollHighlightedIntoView: true
|
|
308
|
+
}) : /*#__PURE__*/ _jsx(EmptyState, {
|
|
309
|
+
className: "min-h-160 w-full",
|
|
310
|
+
icon: "fileDamageLine",
|
|
311
|
+
title: "Source snapshot unavailable",
|
|
312
|
+
description: run.isTemporary ? 'Temporary runs do not capture workflow source.' : 'This run was created before workflow source snapshots were captured.'
|
|
313
|
+
})
|
|
314
|
+
]
|
|
315
|
+
})
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceSlug, projectSlug, selection, selectedJobId, onSelectAnnotationJob, onClearAnnotationFilters }) {
|
|
319
|
+
const selectedJob = run.jobs.find((job)=>job.id === selectedJobId);
|
|
320
|
+
const severity = selection?.severity;
|
|
321
|
+
const records = annotations.annotations;
|
|
322
|
+
const entries = useMemo(()=>records ? buildRunAnnotationList({
|
|
323
|
+
annotations: records,
|
|
324
|
+
jobs: run.jobs,
|
|
325
|
+
severity,
|
|
326
|
+
jobId: selectedJob?.id
|
|
327
|
+
}) : undefined, [
|
|
328
|
+
records,
|
|
329
|
+
run.jobs,
|
|
330
|
+
selectedJob?.id,
|
|
331
|
+
severity
|
|
332
|
+
]);
|
|
333
|
+
return /*#__PURE__*/ _jsx("section", {
|
|
334
|
+
"aria-label": "Run annotations",
|
|
335
|
+
className: "min-h-0 flex-1 overflow-auto pb-24 pt-16",
|
|
336
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
337
|
+
className: "mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24",
|
|
338
|
+
children: [
|
|
339
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
340
|
+
as: "h2",
|
|
341
|
+
className: "sr-only",
|
|
342
|
+
children: "Annotations"
|
|
343
|
+
}),
|
|
344
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
345
|
+
className: "flex flex-wrap items-center justify-between gap-8",
|
|
346
|
+
children: [
|
|
347
|
+
/*#__PURE__*/ _jsx(RunAnnotationSummaryLine, {
|
|
348
|
+
summary: annotationSummary,
|
|
349
|
+
workspaceSlug: workspaceSlug,
|
|
350
|
+
projectSlug: projectSlug,
|
|
351
|
+
workflowRunId: run.id,
|
|
352
|
+
search: selection
|
|
353
|
+
}),
|
|
354
|
+
/*#__PURE__*/ _jsx(AnnotationJobFilter, {
|
|
355
|
+
jobs: run.jobs,
|
|
356
|
+
selectedJobId: selectedJob?.id,
|
|
357
|
+
onSelect: onSelectAnnotationJob
|
|
358
|
+
})
|
|
359
|
+
]
|
|
360
|
+
}),
|
|
361
|
+
/*#__PURE__*/ _jsx(RunAnnotationList, {
|
|
362
|
+
query: annotations.query,
|
|
363
|
+
entries: entries,
|
|
364
|
+
workspaceSlug: workspaceSlug,
|
|
365
|
+
projectSlug: projectSlug,
|
|
366
|
+
workflowRunId: run.id,
|
|
367
|
+
runAttempt: run.runAttempt.attempt,
|
|
368
|
+
// 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),
|
|
370
|
+
filteredJobName: selectedJob?.displayName,
|
|
371
|
+
filteredSeverity: severity,
|
|
372
|
+
onClearFilters: onClearAnnotationFilters,
|
|
373
|
+
selectedAnnotationId: selection?.annotation
|
|
374
|
+
}, `${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`)
|
|
375
|
+
]
|
|
278
376
|
})
|
|
279
377
|
});
|
|
280
378
|
}
|