@shipfox/client-workflows 12.0.2 → 14.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/main.ts +16 -1
- package/.storybook/preview.tsx +3 -3
- package/.storybook/workspace-source.ts +31 -0
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +79 -0
- package/dist/components/job-graph/job-duration-format.d.ts +2 -2
- package/dist/components/job-graph/job-duration-format.d.ts.map +1 -1
- package/dist/components/job-graph/job-duration-format.js +4 -2
- package/dist/components/job-graph/job-duration-format.js.map +1 -1
- package/dist/components/job-graph/job-duration-label.js +1 -1
- package/dist/components/job-graph/job-duration-label.js.map +1 -1
- package/dist/components/job-graph/job-graph-content.d.ts +2 -1
- package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +3 -3
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/job-graph/job-graph-view.d.ts +2 -1
- package/dist/components/job-graph/job-graph-view.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-view.js +2 -2
- package/dist/components/job-graph/job-graph-view.js.map +1 -1
- package/dist/components/job-graph/job-node.d.ts +1 -1
- package/dist/components/job-graph/job-node.d.ts.map +1 -1
- package/dist/components/job-graph/job-node.js +10 -9
- package/dist/components/job-graph/job-node.js.map +1 -1
- package/dist/components/job-graph/types.d.ts +2 -1
- package/dist/components/job-graph/types.d.ts.map +1 -1
- package/dist/components/job-graph/types.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +2 -2
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- 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.d.ts +21 -0
- package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -0
- package/dist/components/workflow-run-list/job-status-strip.js +185 -0
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -0
- package/dist/components/workflow-run-list/run-display.d.ts +27 -3
- package/dist/components/workflow-run-list/run-display.d.ts.map +1 -1
- package/dist/components/workflow-run-list/run-display.js +78 -7
- package/dist/components/workflow-run-list/run-display.js.map +1 -1
- package/dist/components/workflow-run-list/types.d.ts +23 -24
- package/dist/components/workflow-run-list/types.d.ts.map +1 -1
- package/dist/components/workflow-run-list/types.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts +22 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js +68 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filters.d.ts +18 -0
- package/dist/components/workflow-run-list/workflow-run-filters.d.ts.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filters.js +236 -0
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-list-content.d.ts +8 -4
- package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-content.js +40 -12
- package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.d.ts +29 -2
- package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +103 -44
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +60 -43
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.js +20 -8
- package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts +19 -9
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +179 -112
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-number-label.d.ts +15 -0
- package/dist/components/workflow-run-number-label.d.ts.map +1 -0
- package/dist/components/workflow-run-number-label.js +41 -0
- package/dist/components/workflow-run-number-label.js.map +1 -0
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts +3 -3
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +10 -9
- 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 +4 -9
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +107 -74
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +6 -0
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/index.js +7 -0
- package/dist/components/workflow-run-tabs/index.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts +11 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +71 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts +2 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.js +11 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts +18 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.js +107 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts +6 -0
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-count.js +27 -0
- package/dist/components/workflow-run-tabs/run-tab-count.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts +8 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.js +82 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.js.map +1 -0
- package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts +2 -2
- package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts.map +1 -1
- package/dist/components/workflow-run-view/agent-config-failure-callout.js +4 -4
- package/dist/components/workflow-run-view/agent-config-failure-callout.js.map +1 -1
- package/dist/components/workflow-run-view/job-card.d.ts +2 -2
- package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
- package/dist/components/workflow-run-view/job-card.js +51 -32
- package/dist/components/workflow-run-view/job-card.js.map +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.d.ts +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.d.ts.map +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.js +20 -8
- package/dist/components/workflow-run-view/job-execution-switcher.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-selection.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-selection.js +40 -1
- package/dist/components/workflow-run-view/workflow-run-selection.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.d.ts +1 -0
- package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +10 -1
- package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts +10 -5
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +136 -85
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/components/workflow-source-panel/index.d.ts +1 -0
- package/dist/components/workflow-source-panel/index.d.ts.map +1 -1
- package/dist/components/workflow-source-panel/index.js +1 -0
- package/dist/components/workflow-source-panel/index.js.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.d.ts +12 -0
- package/dist/components/workflow-source-panel/workflow-source-content.d.ts.map +1 -0
- package/dist/components/workflow-source-panel/workflow-source-content.js +53 -0
- package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -0
- package/dist/components/workflow-source-panel/workflow-source-panel.d.ts +1 -1
- package/dist/components/workflow-source-panel/workflow-source-panel.d.ts.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-panel.js +7 -54
- package/dist/components/workflow-source-panel/workflow-source-panel.js.map +1 -1
- package/dist/components/workflow-status/status-visuals.d.ts +4 -4
- package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
- package/dist/components/workflow-status/status-visuals.js +7 -0
- package/dist/components/workflow-status/status-visuals.js.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.d.ts +3 -4
- package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.js +6 -4
- package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +10 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js +11 -0
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job.d.ts +4 -2
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/job.js +8 -1
- package/dist/core/entities/job.js.map +1 -1
- package/dist/core/entities/step.d.ts +1 -1
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js +2 -0
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +52 -4
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js +22 -3
- package/dist/core/entities/workflow-run.js.map +1 -1
- package/dist/core/workflow-run-tabs.d.ts +9 -0
- package/dist/core/workflow-run-tabs.d.ts.map +1 -0
- package/dist/core/workflow-run-tabs.js +3 -0
- package/dist/core/workflow-run-tabs.js.map +1 -0
- package/dist/core/workflow-run.d.ts +6 -6
- package/dist/core/workflow-run.d.ts.map +1 -1
- package/dist/core/workflow-run.js +3 -3
- package/dist/core/workflow-run.js.map +1 -1
- package/dist/feature.d.ts +7 -7
- package/dist/feature.js +5 -5
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.d.ts +4 -3
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +31 -3
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/hooks/api/workflow-runs.d.ts +4 -4
- package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
- package/dist/hooks/api/workflow-runs.js +12 -4
- package/dist/hooks/api/workflow-runs.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/pages/project-workflows-page.js +46 -1
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-run-detail-page.d.ts +11 -0
- package/dist/pages/workflow-run-detail-page.d.ts.map +1 -0
- package/dist/pages/workflow-run-detail-page.js +52 -0
- package/dist/pages/workflow-run-detail-page.js.map +1 -0
- package/dist/pages/workflow-run-list-page.d.ts +10 -0
- package/dist/pages/workflow-run-list-page.d.ts.map +1 -0
- package/dist/pages/workflow-run-list-page.js +43 -0
- package/dist/pages/workflow-run-list-page.js.map +1 -0
- package/dist/routes/inputs.d.ts +94 -5
- package/dist/routes/inputs.d.ts.map +1 -1
- package/dist/routes/inputs.js +199 -13
- package/dist/routes/inputs.js.map +1 -1
- package/dist/routes/project-route.d.ts +6 -0
- package/dist/routes/project-route.d.ts.map +1 -0
- package/dist/routes/project-route.js +25 -0
- package/dist/routes/project-route.js.map +1 -0
- package/dist/routes/run-detail.d.ts.map +1 -1
- package/dist/routes/run-detail.js +12 -7
- package/dist/routes/run-detail.js.map +1 -1
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/runs.js +11 -6
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +6 -5
- package/dist/routes/workflows.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/components/job-graph/job-duration-format.ts +11 -2
- package/src/components/job-graph/job-duration-label.tsx +5 -1
- package/src/components/job-graph/job-graph-content.tsx +7 -4
- package/src/components/job-graph/job-graph-view.test.tsx +19 -8
- package/src/components/job-graph/job-graph-view.tsx +6 -3
- package/src/components/job-graph/job-graph.stories.tsx +24 -20
- package/src/components/job-graph/job-node.stories.tsx +11 -6
- package/src/components/job-graph/job-node.test.tsx +82 -12
- package/src/components/job-graph/job-node.tsx +22 -15
- package/src/components/job-graph/types.ts +5 -1
- package/src/components/step-list/step-list.stories.tsx +2 -3
- package/src/components/step-list/step-list.tsx +3 -2
- package/src/components/workflow-run-duration-label.tsx +1 -1
- package/src/components/workflow-run-list/job-status-strip.tsx +189 -0
- package/src/components/workflow-run-list/run-display.test.ts +169 -30
- package/src/components/workflow-run-list/run-display.ts +116 -9
- package/src/components/workflow-run-list/types.ts +21 -17
- package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +100 -0
- package/src/components/workflow-run-list/workflow-run-filters.tsx +243 -0
- package/src/components/workflow-run-list/workflow-run-list-content.tsx +44 -16
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +128 -27
- package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +441 -104
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +73 -43
- package/src/components/workflow-run-list/workflow-run-list.stories.tsx +140 -20
- package/src/components/workflow-run-list/workflow-run-list.tsx +20 -10
- package/src/components/workflow-run-list/workflow-run-row.tsx +173 -106
- package/src/components/workflow-run-number-label.test.tsx +45 -0
- package/src/components/workflow-run-number-label.tsx +47 -0
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +7 -8
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +15 -14
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +29 -38
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +30 -24
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +102 -77
- package/src/components/workflow-run-tabs/index.ts +5 -0
- package/src/components/workflow-run-tabs/run-annotation-summary-line.test.tsx +69 -0
- package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +97 -0
- package/src/components/workflow-run-tabs/run-annotations-empty.tsx +11 -0
- package/src/components/workflow-run-tabs/run-jobs-list.tsx +151 -0
- package/src/components/workflow-run-tabs/run-tab-count.tsx +28 -0
- package/src/components/workflow-run-tabs/run-tab-strip.stories.tsx +52 -0
- package/src/components/workflow-run-tabs/run-tab-strip.test.tsx +117 -0
- package/src/components/workflow-run-tabs/run-tab-strip.tsx +97 -0
- package/src/components/workflow-run-view/agent-config-failure-callout.stories.tsx +2 -3
- package/src/components/workflow-run-view/agent-config-failure-callout.tsx +4 -4
- package/src/components/workflow-run-view/job-card.stories.tsx +11 -10
- package/src/components/workflow-run-view/job-card.test.tsx +115 -0
- package/src/components/workflow-run-view/job-card.tsx +74 -35
- package/src/components/workflow-run-view/job-execution-switcher.tsx +31 -9
- package/src/components/workflow-run-view/workflow-run-selection.test.ts +48 -0
- package/src/components/workflow-run-view/workflow-run-selection.ts +48 -1
- package/src/components/workflow-run-view/workflow-run-states.tsx +12 -1
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +152 -94
- package/src/components/workflow-run-view/workflow-run-view.tsx +219 -95
- package/src/components/workflow-source-panel/index.ts +1 -0
- package/src/components/workflow-source-panel/workflow-source-content.tsx +84 -0
- package/src/components/workflow-source-panel/workflow-source-panel.tsx +14 -81
- package/src/components/workflow-status/status-visuals.test.ts +9 -0
- package/src/components/workflow-status/status-visuals.ts +6 -4
- package/src/components/workflow-status/workflow-status-icon.stories.tsx +10 -2
- package/src/components/workflow-status/workflow-status-icon.test.tsx +18 -0
- package/src/components/workflow-status/workflow-status-icon.tsx +17 -24
- package/src/core/entities/job-execution.ts +22 -0
- package/src/core/entities/job-status.test.ts +104 -0
- package/src/core/entities/job.ts +18 -3
- package/src/core/entities/step.ts +4 -0
- package/src/core/entities/workflow-run.ts +76 -7
- package/src/core/workflow-run-tabs.ts +8 -0
- package/src/core/workflow-run.test.ts +24 -9
- package/src/core/workflow-run.ts +17 -2
- package/src/feature.ts +5 -5
- package/src/hooks/api/workflow-run-mapper.ts +30 -3
- package/src/hooks/api/workflow-runs.test.tsx +2 -0
- package/src/hooks/api/workflow-runs.ts +12 -7
- package/src/index.ts +7 -2
- package/src/page-harness-budget.test.ts +1 -1
- package/src/pages/project-workflows-page.test.tsx +59 -5
- package/src/pages/project-workflows-page.tsx +34 -1
- package/src/pages/workflow-run-detail-page.tsx +72 -0
- package/src/pages/workflow-run-list-page.tsx +65 -0
- package/src/pages/workflow-run-pages.test.tsx +823 -0
- package/src/routes/inputs.test.ts +240 -12
- package/src/routes/inputs.ts +215 -11
- package/src/routes/project-route.tsx +25 -0
- package/src/routes/run-detail.tsx +15 -8
- package/src/routes/runs.tsx +14 -7
- package/src/routes/workflows.tsx +5 -4
- package/src/storybook-config.test.ts +27 -0
- package/test/fixtures/workflow-run.ts +76 -7
- package/test/pages.tsx +18 -8
- package/test/render.tsx +8 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.test.json +7 -1
- package/dist/components/workflow-run-list/workflow-run-list-header.d.ts +0 -10
- package/dist/components/workflow-run-list/workflow-run-list-header.d.ts.map +0 -1
- package/dist/components/workflow-run-list/workflow-run-list-header.js +0 -55
- package/dist/components/workflow-run-list/workflow-run-list-header.js.map +0 -1
- package/dist/pages/workflow-run-first-time-use.d.ts +0 -6
- package/dist/pages/workflow-run-first-time-use.d.ts.map +0 -1
- package/dist/pages/workflow-run-first-time-use.js +0 -17
- package/dist/pages/workflow-run-first-time-use.js.map +0 -1
- package/dist/pages/workflow-run-page.d.ts +0 -10
- package/dist/pages/workflow-run-page.d.ts.map +0 -1
- package/dist/pages/workflow-run-page.js +0 -90
- package/dist/pages/workflow-run-page.js.map +0 -1
- package/src/components/workflow-run-list/workflow-run-list-header.tsx +0 -53
- package/src/pages/workflow-run-first-time-use.tsx +0 -17
- package/src/pages/workflow-run-page.test.tsx +0 -519
- package/src/pages/workflow-run-page.tsx +0 -94
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {BadgeVariant} from '@shipfox/react-ui/badge';
|
|
2
2
|
import type {DotVariant} from '@shipfox/react-ui/dot';
|
|
3
|
-
import type {
|
|
3
|
+
import type {WorkflowDisplayStatus} from '#core/workflow-run.js';
|
|
4
4
|
|
|
5
|
-
export type {
|
|
5
|
+
export type {WorkflowDisplayStatus};
|
|
6
6
|
|
|
7
7
|
export interface WorkflowStatusVisual {
|
|
8
|
-
kind:
|
|
8
|
+
kind: WorkflowDisplayStatus;
|
|
9
9
|
label: string;
|
|
10
10
|
dot: DotVariant;
|
|
11
11
|
badge: BadgeVariant;
|
|
@@ -15,12 +15,14 @@ export interface WorkflowStatusVisual {
|
|
|
15
15
|
// WorkflowStatusIcon (which renders the glyph per kind). The exhaustive switch turns any new
|
|
16
16
|
// status the API grows into (DESIGN.md section 9) into a compile error; reserve the `warning`
|
|
17
17
|
// tone for the queued/awaiting-* states when they land.
|
|
18
|
-
export function getWorkflowStatusVisual(status:
|
|
18
|
+
export function getWorkflowStatusVisual(status: WorkflowDisplayStatus): WorkflowStatusVisual {
|
|
19
19
|
switch (status) {
|
|
20
20
|
case 'pending':
|
|
21
21
|
return {kind: 'pending', label: 'Pending', dot: 'neutral', badge: 'neutral'};
|
|
22
22
|
case 'running':
|
|
23
23
|
return {kind: 'running', label: 'Running', dot: 'info', badge: 'info'};
|
|
24
|
+
case 'listening':
|
|
25
|
+
return {kind: 'listening', label: 'Listening', dot: 'info', badge: 'info'};
|
|
24
26
|
case 'succeeded':
|
|
25
27
|
return {kind: 'succeeded', label: 'Succeeded', dot: 'success', badge: 'success'};
|
|
26
28
|
case 'failed':
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import {Code, Text} from '@shipfox/react-ui/typography';
|
|
2
2
|
import type {Meta, StoryObj} from '@storybook/react';
|
|
3
|
-
import type {
|
|
3
|
+
import type {WorkflowDisplayStatus} from '#core/workflow-run.js';
|
|
4
4
|
import {getWorkflowStatusVisual} from './status-visuals.js';
|
|
5
5
|
import {WorkflowStatusIcon} from './workflow-status-icon.js';
|
|
6
6
|
|
|
7
|
-
const statuses:
|
|
7
|
+
const statuses: WorkflowDisplayStatus[] = [
|
|
8
|
+
'pending',
|
|
9
|
+
'running',
|
|
10
|
+
'listening',
|
|
11
|
+
'succeeded',
|
|
12
|
+
'failed',
|
|
13
|
+
'cancelled',
|
|
14
|
+
'skipped',
|
|
15
|
+
];
|
|
8
16
|
|
|
9
17
|
const meta = {
|
|
10
18
|
title: 'Workflows/StatusIcon',
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {render, screen} from '@testing-library/react';
|
|
2
|
+
import {WorkflowStatusIcon} from './workflow-status-icon.js';
|
|
3
|
+
|
|
4
|
+
describe('WorkflowStatusIcon', () => {
|
|
5
|
+
test('keeps a running status as a dot', () => {
|
|
6
|
+
const {container} = render(<WorkflowStatusIcon status="running" tooltip={false} />);
|
|
7
|
+
|
|
8
|
+
expect(screen.getByRole('img', {name: 'Running'})).toBeInTheDocument();
|
|
9
|
+
expect(container.querySelector('svg')).toBeNull();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('uses the pulse glyph for the listening status', () => {
|
|
13
|
+
const {container} = render(<WorkflowStatusIcon status="listening" tooltip={false} />);
|
|
14
|
+
|
|
15
|
+
expect(screen.getByRole('img', {name: 'Listening'})).toBeInTheDocument();
|
|
16
|
+
expect(container.querySelector('svg')).not.toBeNull();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -3,7 +3,7 @@ import {Icon, type IconName} from '@shipfox/react-ui/icon';
|
|
|
3
3
|
import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';
|
|
4
4
|
import {cn} from '@shipfox/react-ui/utils';
|
|
5
5
|
import type {ReactNode} from 'react';
|
|
6
|
-
import {getWorkflowStatusVisual, type
|
|
6
|
+
import {getWorkflowStatusVisual, type WorkflowDisplayStatus} from './status-visuals.js';
|
|
7
7
|
|
|
8
8
|
// Status glyphs use the same saturated accent tokens as IconBadge/StatusBadge.
|
|
9
9
|
const toneByVariant: Record<DotVariant, string> = {
|
|
@@ -17,7 +17,7 @@ const toneByVariant: Record<DotVariant, string> = {
|
|
|
17
17
|
|
|
18
18
|
// Terminal states are self-contained solid discs; the shape names the state. Running and
|
|
19
19
|
// pending render their own shapes (the live Dot and a bold ring), so they aren't here.
|
|
20
|
-
const glyphByKind: Partial<Record<
|
|
20
|
+
const glyphByKind: Partial<Record<WorkflowDisplayStatus, IconName>> = {
|
|
21
21
|
succeeded: 'checkCircleSolid',
|
|
22
22
|
failed: 'xCircleSolid',
|
|
23
23
|
cancelled: 'forbid2Fill',
|
|
@@ -45,8 +45,7 @@ const dotSizeClass: Record<number, string> = {
|
|
|
45
45
|
const PENDING_RING_MASK = 'radial-gradient(circle closest-side, transparent 0 52%, #000 56%)';
|
|
46
46
|
|
|
47
47
|
export interface WorkflowStatusIconProps {
|
|
48
|
-
status:
|
|
49
|
-
jobMode?: 'one_shot' | 'listening';
|
|
48
|
+
status: WorkflowDisplayStatus;
|
|
50
49
|
/** Optical diameter in px: 14 in the DAG node and run row. */
|
|
51
50
|
size?: number;
|
|
52
51
|
/** Pulsing halo for the running state. */
|
|
@@ -66,7 +65,6 @@ export interface WorkflowStatusIconProps {
|
|
|
66
65
|
*/
|
|
67
66
|
export function WorkflowStatusIcon({
|
|
68
67
|
status,
|
|
69
|
-
jobMode = 'one_shot',
|
|
70
68
|
size = 14,
|
|
71
69
|
ripple = true,
|
|
72
70
|
tooltip = true,
|
|
@@ -76,25 +74,20 @@ export function WorkflowStatusIcon({
|
|
|
76
74
|
const box = dotSizeClass[size] ?? 'size-14';
|
|
77
75
|
|
|
78
76
|
let glyph: ReactNode;
|
|
79
|
-
if (visual.kind === '
|
|
80
|
-
glyph =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
/>
|
|
94
|
-
</span>
|
|
95
|
-
) : (
|
|
96
|
-
<Dot variant="info" ripple={ripple} className={box} />
|
|
97
|
-
);
|
|
77
|
+
if (visual.kind === 'listening') {
|
|
78
|
+
glyph = (
|
|
79
|
+
<span
|
|
80
|
+
className={cn(
|
|
81
|
+
'inline-flex shrink-0 items-center justify-center rounded-full bg-current',
|
|
82
|
+
box,
|
|
83
|
+
toneByVariant.info,
|
|
84
|
+
)}
|
|
85
|
+
>
|
|
86
|
+
<Icon name="pulseLine" size={Math.max(8, Math.round(size * 0.7))} className="text-white" />
|
|
87
|
+
</span>
|
|
88
|
+
);
|
|
89
|
+
} else if (visual.kind === 'running') {
|
|
90
|
+
glyph = <Dot variant="info" ripple={ripple} className={box} />;
|
|
98
91
|
} else if (visual.kind === 'pending') {
|
|
99
92
|
glyph = (
|
|
100
93
|
<span
|
|
@@ -2,11 +2,16 @@ import {type Duration, intervalToDuration} from 'date-fns';
|
|
|
2
2
|
import type {Step} from './step.js';
|
|
3
3
|
|
|
4
4
|
export type JobExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
5
|
+
export type JobExecutionDisplayStatus = JobExecutionStatus;
|
|
5
6
|
export interface WorkflowExecutionEvent {
|
|
6
7
|
source: string;
|
|
7
8
|
event: string;
|
|
8
9
|
deliveryId: string;
|
|
9
10
|
receivedAt: string;
|
|
11
|
+
project: {id: string} | null;
|
|
12
|
+
repository: string | null;
|
|
13
|
+
ref: string | null;
|
|
14
|
+
commit: string | null;
|
|
10
15
|
data: unknown;
|
|
11
16
|
}
|
|
12
17
|
export type JobExecutionTime =
|
|
@@ -53,6 +58,10 @@ export class JobExecution {
|
|
|
53
58
|
Object.assign(this, fields);
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
get displayName(): string {
|
|
62
|
+
return this.name;
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
get queueTime(): JobExecutionTime | null {
|
|
57
66
|
return jobExecutionQueueTimeFromTimestamps(this);
|
|
58
67
|
}
|
|
@@ -66,6 +75,19 @@ export class JobExecution {
|
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
export function deriveJobExecutionDisplayStatus({
|
|
79
|
+
status,
|
|
80
|
+
steps,
|
|
81
|
+
}: Pick<JobExecution, 'status' | 'steps'>): JobExecutionDisplayStatus {
|
|
82
|
+
if (isTerminalJobExecutionStatus(status)) return status;
|
|
83
|
+
if (steps.some((step) => step.status === 'running')) return 'running';
|
|
84
|
+
return 'pending';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isTerminalJobExecutionStatus(status: JobExecutionStatus): boolean {
|
|
88
|
+
return status === 'succeeded' || status === 'failed' || status === 'cancelled';
|
|
89
|
+
}
|
|
90
|
+
|
|
69
91
|
export function jobExecutionQueueTimeFromTimestamps({
|
|
70
92
|
queuedAt,
|
|
71
93
|
startedAt,
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {deriveJobDisplayStatus, type JobDisplayStatus} from './job.js';
|
|
2
|
+
import {deriveJobExecutionDisplayStatus, type JobExecutionStatus} from './job-execution.js';
|
|
3
|
+
|
|
4
|
+
type DisplayStep = Parameters<typeof deriveJobExecutionDisplayStatus>[0]['steps'][number];
|
|
5
|
+
|
|
6
|
+
function displayStep(status: string): DisplayStep {
|
|
7
|
+
return {status} as DisplayStep;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const EXECUTION_STATUSES = ['pending', 'running', 'succeeded', 'failed', 'cancelled'] as const;
|
|
11
|
+
const TERMINAL_EXECUTION_STATUSES = ['succeeded', 'failed', 'cancelled'] as const;
|
|
12
|
+
|
|
13
|
+
describe('deriveJobExecutionDisplayStatus', () => {
|
|
14
|
+
test.each(
|
|
15
|
+
EXECUTION_STATUSES,
|
|
16
|
+
)('%s without a running step displays Pending unless terminal', (status) => {
|
|
17
|
+
const displayStatus = deriveJobExecutionDisplayStatus({status, steps: []});
|
|
18
|
+
|
|
19
|
+
expect(displayStatus).toBe(
|
|
20
|
+
TERMINAL_EXECUTION_STATUSES.includes(status as (typeof TERMINAL_EXECUTION_STATUSES)[number])
|
|
21
|
+
? status
|
|
22
|
+
: 'pending',
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test.each([
|
|
27
|
+
'pending',
|
|
28
|
+
'running',
|
|
29
|
+
] as const)('%s with a running step displays Running', (status) => {
|
|
30
|
+
expect(deriveJobExecutionDisplayStatus({status, steps: [displayStep('running')]})).toBe(
|
|
31
|
+
'running',
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test.each(TERMINAL_EXECUTION_STATUSES)('%s wins over a running child step', (status) => {
|
|
36
|
+
expect(deriveJobExecutionDisplayStatus({status, steps: [displayStep('running')]})).toBe(status);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('deriveJobDisplayStatus', () => {
|
|
41
|
+
test('uses the execution activity for a one-shot job', () => {
|
|
42
|
+
const statuses: Array<[JobExecutionStatus, string[], JobDisplayStatus]> = [
|
|
43
|
+
['pending', [], 'pending'],
|
|
44
|
+
['pending', ['running'], 'running'],
|
|
45
|
+
['running', [], 'pending'],
|
|
46
|
+
['running', ['running'], 'running'],
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
for (const [status, stepStatuses, expected] of statuses) {
|
|
50
|
+
expect(
|
|
51
|
+
deriveJobDisplayStatus({
|
|
52
|
+
mode: 'one_shot',
|
|
53
|
+
status: 'running',
|
|
54
|
+
listenerStatus: 'inactive',
|
|
55
|
+
jobExecutions: [
|
|
56
|
+
{
|
|
57
|
+
status,
|
|
58
|
+
steps: stepStatuses.map(displayStep),
|
|
59
|
+
sequence: 1,
|
|
60
|
+
},
|
|
61
|
+
] as never,
|
|
62
|
+
}),
|
|
63
|
+
).toBe(expected);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test.each([
|
|
68
|
+
'succeeded',
|
|
69
|
+
'failed',
|
|
70
|
+
'cancelled',
|
|
71
|
+
'skipped',
|
|
72
|
+
] as const)('terminal job status %s wins over child activity', (status) => {
|
|
73
|
+
expect(
|
|
74
|
+
deriveJobDisplayStatus({
|
|
75
|
+
mode: 'one_shot',
|
|
76
|
+
status,
|
|
77
|
+
listenerStatus: 'inactive',
|
|
78
|
+
jobExecutions: [{status: 'running', steps: [{status: 'running'}], sequence: 1}] as never,
|
|
79
|
+
}),
|
|
80
|
+
).toBe(status);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('keeps an active listener as Listening without executions', () => {
|
|
84
|
+
expect(
|
|
85
|
+
deriveJobDisplayStatus({
|
|
86
|
+
mode: 'listening',
|
|
87
|
+
status: 'running',
|
|
88
|
+
listenerStatus: 'listening',
|
|
89
|
+
jobExecutions: [],
|
|
90
|
+
}),
|
|
91
|
+
).toBe('listening');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('uses the terminal job status when an active listener has resolved', () => {
|
|
95
|
+
expect(
|
|
96
|
+
deriveJobDisplayStatus({
|
|
97
|
+
mode: 'listening',
|
|
98
|
+
status: 'succeeded',
|
|
99
|
+
listenerStatus: 'listening',
|
|
100
|
+
jobExecutions: [],
|
|
101
|
+
}),
|
|
102
|
+
).toBe('succeeded');
|
|
103
|
+
});
|
|
104
|
+
});
|
package/src/core/entities/job.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
deriveJobExecutionDisplayStatus,
|
|
3
|
+
type JobExecution,
|
|
4
|
+
type JobExecutionDisplayDuration,
|
|
5
|
+
} from './job-execution.js';
|
|
2
6
|
|
|
3
7
|
export type JobStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';
|
|
8
|
+
export type JobDisplayStatus = JobStatus | 'listening';
|
|
4
9
|
export type JobMode = 'one_shot' | 'listening';
|
|
5
10
|
export type ListenerStatus = 'inactive' | 'listening' | 'resolved';
|
|
6
11
|
export type ResolutionReason = 'until' | 'timeout' | 'max_executions' | 'cancelled';
|
|
@@ -103,7 +108,7 @@ export class Job {
|
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
get displayName(): string {
|
|
106
|
-
return this.name
|
|
111
|
+
return this.name ?? this.key;
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
get displayDuration(): JobDisplayDuration | null {
|
|
@@ -123,6 +128,16 @@ export function isTerminalJobStatus(status: JobStatus): boolean {
|
|
|
123
128
|
return TERMINAL_JOB_STATUS_SET.has(status);
|
|
124
129
|
}
|
|
125
130
|
|
|
131
|
+
export function deriveJobDisplayStatus(
|
|
132
|
+
job: Pick<Job, 'mode' | 'status' | 'listenerStatus' | 'jobExecutions'>,
|
|
133
|
+
): JobDisplayStatus {
|
|
134
|
+
if (isTerminalJobStatus(job.status)) return job.status;
|
|
135
|
+
if (job.mode === 'listening' && job.listenerStatus === 'listening') return 'listening';
|
|
136
|
+
|
|
137
|
+
const execution = defaultJobExecution(job);
|
|
138
|
+
return execution ? deriveJobExecutionDisplayStatus(execution) : 'pending';
|
|
139
|
+
}
|
|
140
|
+
|
|
126
141
|
export function resolveJobExecution(
|
|
127
142
|
job: Job,
|
|
128
143
|
jobExecutionId: string | undefined,
|
|
@@ -135,7 +150,7 @@ export function resolveJobExecution(
|
|
|
135
150
|
return defaultJobExecution(job);
|
|
136
151
|
}
|
|
137
152
|
|
|
138
|
-
export function defaultJobExecution(job: Job): JobExecution | undefined {
|
|
153
|
+
export function defaultJobExecution(job: Pick<Job, 'jobExecutions'>): JobExecution | undefined {
|
|
139
154
|
const runningExecution = job.jobExecutions.find(
|
|
140
155
|
(jobExecution) => jobExecution.status === 'running',
|
|
141
156
|
);
|
|
@@ -4,6 +4,8 @@ export type StepErrorReason =
|
|
|
4
4
|
| 'checkout_failed'
|
|
5
5
|
| 'checkout_auth_failed'
|
|
6
6
|
| 'checkout_unavailable'
|
|
7
|
+
| 'checkout_path_invalid'
|
|
8
|
+
| 'checkout_destination_occupied'
|
|
7
9
|
| 'git_unavailable'
|
|
8
10
|
| 'workspace_prep_failed'
|
|
9
11
|
| 'setup_aborted'
|
|
@@ -23,6 +25,8 @@ export const STEP_ERROR_REASONS = new Set<StepErrorReason>([
|
|
|
23
25
|
'checkout_failed',
|
|
24
26
|
'checkout_auth_failed',
|
|
25
27
|
'checkout_unavailable',
|
|
28
|
+
'checkout_path_invalid',
|
|
29
|
+
'checkout_destination_occupied',
|
|
26
30
|
'git_unavailable',
|
|
27
31
|
'workspace_prep_failed',
|
|
28
32
|
'setup_aborted',
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {type Job, WORKFLOW_JOB_STATUSES} from './job.js';
|
|
1
|
+
import {type Job, type JobStatus, WORKFLOW_JOB_STATUSES} from './job.js';
|
|
2
2
|
import type {WorkflowRunAttempt, WorkflowRunAttemptSummary} from './workflow-run-attempt.js';
|
|
3
3
|
|
|
4
4
|
export type WorkflowRunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
5
5
|
export type WorkflowRunRerunMode = 'all' | 'failed';
|
|
6
6
|
export type WorkflowStatus = WorkflowRunStatus | (typeof WORKFLOW_JOB_STATUSES)[number];
|
|
7
|
+
export type WorkflowDisplayStatus = WorkflowStatus | 'listening';
|
|
7
8
|
|
|
8
9
|
export const WORKFLOW_RUN_STATUSES = [
|
|
9
10
|
'pending',
|
|
@@ -30,11 +31,51 @@ export interface WorkflowSourceSnapshot {
|
|
|
30
31
|
format: 'yaml';
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Provider-neutral trigger facts. Every field is nullable: only source-control triggers
|
|
36
|
+
* resolve a reference at all, and a payload can name a ref without naming an actor.
|
|
37
|
+
*/
|
|
38
|
+
export interface WorkflowRunTriggerReference {
|
|
39
|
+
repository: string | null;
|
|
40
|
+
ref: string | null;
|
|
41
|
+
commit: string | null;
|
|
42
|
+
actor: string | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** One glyph in a run row's job status strip: enough to draw and label it, nothing more. */
|
|
46
|
+
export interface WorkflowRunJobSummary {
|
|
47
|
+
id: string;
|
|
48
|
+
key: string;
|
|
49
|
+
name: string | null;
|
|
50
|
+
status: JobStatus;
|
|
51
|
+
position: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface WorkflowRunJobStatusCount {
|
|
55
|
+
status: JobStatus;
|
|
56
|
+
count: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A run's jobs as the list receives them: a bounded slice to draw, plus totals covering all
|
|
61
|
+
* of them.
|
|
62
|
+
*
|
|
63
|
+
* `preview` is capped by the API, so `preview.length` is not the job count and the strip
|
|
64
|
+
* reads `total` and `statusCounts` for anything it says rather than anything it draws.
|
|
65
|
+
*/
|
|
66
|
+
export interface WorkflowRunJobs {
|
|
67
|
+
preview: WorkflowRunJobSummary[];
|
|
68
|
+
statusCounts: WorkflowRunJobStatusCount[];
|
|
69
|
+
total: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
33
72
|
export interface WorkflowRun {
|
|
34
73
|
id: string;
|
|
35
74
|
projectId: string;
|
|
36
75
|
definitionId: string;
|
|
76
|
+
number: number | null;
|
|
37
77
|
name: string;
|
|
78
|
+
workflowName: string;
|
|
38
79
|
currentAttempt: number;
|
|
39
80
|
triggerProvider: string | null;
|
|
40
81
|
triggerSource: string;
|
|
@@ -42,20 +83,25 @@ export interface WorkflowRun {
|
|
|
42
83
|
triggerDisplayLabel: string;
|
|
43
84
|
triggerLabel: string;
|
|
44
85
|
triggerPayload: Record<string, unknown>;
|
|
86
|
+
triggerReference: WorkflowRunTriggerReference | null;
|
|
45
87
|
inputs: Record<string, unknown> | null;
|
|
46
88
|
sourceSnapshot: WorkflowSourceSnapshot | null;
|
|
47
89
|
createdAt: string;
|
|
48
90
|
updatedAt: string;
|
|
49
|
-
shortId: string;
|
|
50
91
|
isTemporary: boolean;
|
|
51
92
|
}
|
|
52
93
|
|
|
53
|
-
|
|
94
|
+
/** A run as the API returns it outside the list: no job strip, because none was fetched. */
|
|
95
|
+
export interface WorkflowRunRecord extends WorkflowRun {
|
|
54
96
|
status: WorkflowRunStatus;
|
|
55
97
|
latestAttempt: number;
|
|
56
98
|
runAttempt: WorkflowRunAttemptSummary;
|
|
57
99
|
}
|
|
58
100
|
|
|
101
|
+
export interface WorkflowRunListItem extends WorkflowRunRecord {
|
|
102
|
+
jobs: WorkflowRunJobs;
|
|
103
|
+
}
|
|
104
|
+
|
|
59
105
|
export interface WorkflowRunDetail extends WorkflowRun {
|
|
60
106
|
latestAttempt: number;
|
|
61
107
|
runAttempt: WorkflowRunAttempt;
|
|
@@ -72,10 +118,6 @@ export interface ManualWorkflowLaunch {
|
|
|
72
118
|
workflowRunId: string;
|
|
73
119
|
}
|
|
74
120
|
|
|
75
|
-
export function workflowRunShortId(id: string): string {
|
|
76
|
-
return id.length <= 8 ? id : id.slice(0, 8);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
121
|
export function workflowRunTriggerLabel({
|
|
80
122
|
triggerSource,
|
|
81
123
|
triggerEvent,
|
|
@@ -96,6 +138,33 @@ export function workflowRunTriggerDisplayLabel({
|
|
|
96
138
|
return triggerEvent || triggerSource;
|
|
97
139
|
}
|
|
98
140
|
|
|
141
|
+
const SHORT_COMMIT_LENGTH = 7;
|
|
142
|
+
const PULL_REQUEST_REF_PATTERN = /^refs\/pull\/(\d+)\/head$/u;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The ref as a person names it: `main` for a branch, `#42` for a pull request, the tag for a
|
|
146
|
+
* tag. An unrecognized ref is shown verbatim rather than hidden, since a ref nobody can read
|
|
147
|
+
* is still better evidence than a blank cell.
|
|
148
|
+
*/
|
|
149
|
+
export function workflowRunBranchLabel(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
|
|
150
|
+
const ref = run.triggerReference?.ref;
|
|
151
|
+
if (!ref) return null;
|
|
152
|
+
const pullRequest = PULL_REQUEST_REF_PATTERN.exec(ref);
|
|
153
|
+
if (pullRequest) return `#${pullRequest[1]}`;
|
|
154
|
+
if (ref.startsWith('refs/heads/')) return ref.slice('refs/heads/'.length);
|
|
155
|
+
if (ref.startsWith('refs/tags/')) return ref.slice('refs/tags/'.length);
|
|
156
|
+
return ref;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function workflowRunCommitLabel(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
|
|
160
|
+
const commit = run.triggerReference?.commit;
|
|
161
|
+
return commit ? commit.slice(0, SHORT_COMMIT_LENGTH) : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function workflowRunActor(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
|
|
165
|
+
return run.triggerReference?.actor ?? null;
|
|
166
|
+
}
|
|
167
|
+
|
|
99
168
|
export function isWorkflowRunTerminal(status: WorkflowRunStatus): boolean {
|
|
100
169
|
return TERMINAL_WORKFLOW_RUN_STATUS_SET.has(status);
|
|
101
170
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
toWorkflowRunListPage,
|
|
7
7
|
} from '#hooks/api/workflow-run-mapper.js';
|
|
8
8
|
import {
|
|
9
|
+
workflowJob,
|
|
9
10
|
workflowJobDto,
|
|
10
11
|
workflowJobExecutionDto,
|
|
11
12
|
workflowRunAttemptDto,
|
|
@@ -18,7 +19,6 @@ import {
|
|
|
18
19
|
import {
|
|
19
20
|
isWorkflowRunTerminal,
|
|
20
21
|
isWorkflowStatus,
|
|
21
|
-
workflowRunShortId,
|
|
22
22
|
workflowRunTriggerDisplayLabel,
|
|
23
23
|
workflowRunTriggerLabel,
|
|
24
24
|
} from './workflow-run.js';
|
|
@@ -51,7 +51,9 @@ describe('workflow run model mapping', () => {
|
|
|
51
51
|
id: '66666666-6666-4666-8666-666666666666',
|
|
52
52
|
projectId: '44444444-4444-4444-8444-444444444444',
|
|
53
53
|
definitionId: '55555555-5555-4555-8555-555555555555',
|
|
54
|
+
number: 1,
|
|
54
55
|
name: 'deploy-web',
|
|
56
|
+
workflowName: 'deploy-web',
|
|
55
57
|
currentAttempt: 3,
|
|
56
58
|
triggerProvider: 'github',
|
|
57
59
|
triggerSource: 'github_acme',
|
|
@@ -63,7 +65,6 @@ describe('workflow run model mapping', () => {
|
|
|
63
65
|
sourceSnapshot: {format: 'yaml', content: 'jobs: {}'},
|
|
64
66
|
createdAt: '2026-05-07T01:01:00.000Z',
|
|
65
67
|
updatedAt: '2026-05-07T01:02:00.000Z',
|
|
66
|
-
shortId: '66666666',
|
|
67
68
|
isTemporary: false,
|
|
68
69
|
});
|
|
69
70
|
expect(run).not.toHaveProperty('status');
|
|
@@ -91,7 +92,6 @@ describe('workflow run model mapping', () => {
|
|
|
91
92
|
triggerLabel: '',
|
|
92
93
|
inputs: null,
|
|
93
94
|
sourceSnapshot: null,
|
|
94
|
-
shortId: 'temp-123',
|
|
95
95
|
isTemporary: true,
|
|
96
96
|
});
|
|
97
97
|
});
|
|
@@ -299,6 +299,10 @@ describe('workflow run model mapping', () => {
|
|
|
299
299
|
event: 'deployment_status',
|
|
300
300
|
delivery_id: 'delivery-1',
|
|
301
301
|
received_at: '2026-05-07T01:00:00.000Z',
|
|
302
|
+
project: {id: '44444444-4444-4444-8444-444444444444'},
|
|
303
|
+
repository: 'acme/api',
|
|
304
|
+
ref: 'refs/heads/main',
|
|
305
|
+
commit: 'a'.repeat(40),
|
|
302
306
|
data: {state: 'success'},
|
|
303
307
|
},
|
|
304
308
|
],
|
|
@@ -332,6 +336,10 @@ describe('workflow run model mapping', () => {
|
|
|
332
336
|
event: 'deployment_status',
|
|
333
337
|
deliveryId: 'delivery-1',
|
|
334
338
|
receivedAt: '2026-05-07T01:00:00.000Z',
|
|
339
|
+
project: {id: '44444444-4444-4444-8444-444444444444'},
|
|
340
|
+
repository: 'acme/api',
|
|
341
|
+
ref: 'refs/heads/main',
|
|
342
|
+
commit: 'a'.repeat(40),
|
|
335
343
|
data: {state: 'success'},
|
|
336
344
|
},
|
|
337
345
|
],
|
|
@@ -376,6 +384,18 @@ describe('workflow run model mapping', () => {
|
|
|
376
384
|
});
|
|
377
385
|
});
|
|
378
386
|
|
|
387
|
+
test('exposes display names for jobs and job executions', () => {
|
|
388
|
+
const job = workflowJob({
|
|
389
|
+
name: 'Deploy',
|
|
390
|
+
key: 'deploy',
|
|
391
|
+
job_executions: [workflowJobExecutionDto({name: 'Deploy production'})],
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
expect(job.displayName).toBe('Deploy');
|
|
395
|
+
expect(job.jobExecutions[0]?.displayName).toBe('Deploy production');
|
|
396
|
+
expect(workflowJob({name: null, key: 'deploy-prod'}).displayName).toBe('deploy-prod');
|
|
397
|
+
});
|
|
398
|
+
|
|
379
399
|
test('returns no job display duration when a job has multiple executions', () => {
|
|
380
400
|
const job = workflowJobDto({
|
|
381
401
|
job_executions: [
|
|
@@ -628,12 +648,7 @@ describe('workflow run helpers', () => {
|
|
|
628
648
|
expect(neither).toBe('');
|
|
629
649
|
});
|
|
630
650
|
|
|
631
|
-
test('
|
|
632
|
-
const short = workflowRunShortId('abc123');
|
|
633
|
-
const long = workflowRunShortId('66666666-6666-4666-8666-666666666666');
|
|
634
|
-
|
|
635
|
-
expect(short).toBe('abc123');
|
|
636
|
-
expect(long).toBe('66666666');
|
|
651
|
+
test('classifies workflow statuses', () => {
|
|
637
652
|
expect(isWorkflowRunTerminal('succeeded')).toBe(true);
|
|
638
653
|
expect(isWorkflowRunTerminal('running')).toBe(false);
|
|
639
654
|
expect(isWorkflowStatus('pending')).toBe(true);
|
package/src/core/workflow-run.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type {
|
|
2
2
|
JobDisplayDuration,
|
|
3
|
+
JobDisplayStatus,
|
|
3
4
|
JobListening,
|
|
4
5
|
JobMode,
|
|
5
6
|
JobStatus,
|
|
@@ -9,6 +10,7 @@ export type {
|
|
|
9
10
|
} from './entities/job.js';
|
|
10
11
|
export {
|
|
11
12
|
defaultJobExecution,
|
|
13
|
+
deriveJobDisplayStatus,
|
|
12
14
|
isTerminalJobStatus,
|
|
13
15
|
Job,
|
|
14
16
|
resolveJobExecution,
|
|
@@ -17,11 +19,16 @@ export {
|
|
|
17
19
|
} from './entities/job.js';
|
|
18
20
|
export type {
|
|
19
21
|
JobExecutionDisplayDuration,
|
|
22
|
+
JobExecutionDisplayStatus,
|
|
20
23
|
JobExecutionStatus,
|
|
21
24
|
JobExecutionTime,
|
|
22
25
|
WorkflowExecutionEvent,
|
|
23
26
|
} from './entities/job-execution.js';
|
|
24
|
-
export {
|
|
27
|
+
export {
|
|
28
|
+
deriveJobExecutionDisplayStatus,
|
|
29
|
+
isTerminalJobExecutionStatus,
|
|
30
|
+
JobExecution,
|
|
31
|
+
} from './entities/job-execution.js';
|
|
25
32
|
export type {
|
|
26
33
|
AgentConfigIssue,
|
|
27
34
|
AgentStepConfig,
|
|
@@ -39,12 +46,18 @@ export type {
|
|
|
39
46
|
export {StepAttempt} from './entities/step-attempt.js';
|
|
40
47
|
export type {
|
|
41
48
|
ManualWorkflowLaunch,
|
|
49
|
+
WorkflowDisplayStatus,
|
|
42
50
|
WorkflowRun,
|
|
43
51
|
WorkflowRunDetail,
|
|
52
|
+
WorkflowRunJobStatusCount,
|
|
53
|
+
WorkflowRunJobSummary,
|
|
54
|
+
WorkflowRunJobs,
|
|
44
55
|
WorkflowRunListItem,
|
|
45
56
|
WorkflowRunListPage,
|
|
57
|
+
WorkflowRunRecord,
|
|
46
58
|
WorkflowRunRerunMode,
|
|
47
59
|
WorkflowRunStatus,
|
|
60
|
+
WorkflowRunTriggerReference,
|
|
48
61
|
WorkflowSourceSnapshot,
|
|
49
62
|
WorkflowStatus,
|
|
50
63
|
} from './entities/workflow-run.js';
|
|
@@ -53,7 +66,9 @@ export {
|
|
|
53
66
|
isWorkflowStatus,
|
|
54
67
|
TERMINAL_WORKFLOW_RUN_STATUSES,
|
|
55
68
|
WORKFLOW_RUN_STATUSES,
|
|
56
|
-
|
|
69
|
+
workflowRunActor,
|
|
70
|
+
workflowRunBranchLabel,
|
|
71
|
+
workflowRunCommitLabel,
|
|
57
72
|
workflowRunTriggerDisplayLabel,
|
|
58
73
|
workflowRunTriggerLabel,
|
|
59
74
|
} from './entities/workflow-run.js';
|