@shipfox/client-workflows 14.0.1 → 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/.storybook/preview.tsx +7 -2
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +42 -0
- package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -0
- package/dist/components/{workflow-run-view → job-detail}/agent-config-failure-callout.js +2 -2
- package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -0
- package/dist/components/job-detail/job-detail-header.d.ts +15 -0
- package/dist/components/job-detail/job-detail-header.d.ts.map +1 -0
- package/dist/components/job-detail/job-detail-header.js +124 -0
- package/dist/components/job-detail/job-detail-header.js.map +1 -0
- package/dist/components/job-detail/job-detail-view.d.ts +16 -0
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -0
- package/dist/components/job-detail/job-detail-view.js +420 -0
- package/dist/components/job-detail/job-detail-view.js.map +1 -0
- package/dist/components/job-detail/job-empty-states.d.ts +10 -0
- package/dist/components/job-detail/job-empty-states.d.ts.map +1 -0
- package/dist/components/job-detail/job-empty-states.js +195 -0
- package/dist/components/job-detail/job-empty-states.js.map +1 -0
- package/dist/components/job-detail/job-execution-switcher.d.ts.map +1 -0
- package/dist/components/job-detail/job-execution-switcher.js.map +1 -0
- package/dist/components/job-detail/job-execution-time-text.d.ts.map +1 -0
- package/dist/components/job-detail/job-execution-time-text.js.map +1 -0
- package/dist/components/job-detail/job-selection.d.ts +24 -0
- package/dist/components/job-detail/job-selection.d.ts.map +1 -0
- package/dist/components/job-detail/job-selection.js +66 -0
- package/dist/components/job-detail/job-selection.js.map +1 -0
- package/dist/components/job-detail/step-attempt-log-panel.d.ts +15 -0
- package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -0
- package/dist/components/{workflow-run-view → job-detail}/step-attempt-log-panel.js +61 -16
- package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -0
- package/dist/components/job-graph/job-graph-content.js +1 -1
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/step-list/step-list-model.js +2 -2
- package/dist/components/step-list/step-list-model.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +1 -0
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js +29 -4
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-duration-label.d.ts +9 -4
- package/dist/components/workflow-run-duration-label.d.ts.map +1 -1
- package/dist/components/workflow-run-duration-label.js +27 -7
- package/dist/components/workflow-run-duration-label.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +6 -5
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +69 -64
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +3 -3
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/index.js +3 -3
- 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/run-annotations-empty.d.ts +3 -1
- package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotations-empty.js +2 -2
- package/dist/components/workflow-run-tabs/run-annotations-empty.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/index.d.ts +0 -1
- package/dist/components/workflow-run-view/index.d.ts.map +1 -1
- package/dist/components/workflow-run-view/index.js +0 -1
- package/dist/components/workflow-run-view/index.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts +20 -0
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -0
- package/dist/components/workflow-run-view/run-workspace-nav.js +277 -0
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -0
- package/dist/components/workflow-run-view/workflow-run-selection.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-selection.js +1 -14
- package/dist/components/workflow-run-view/workflow-run-selection.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts +10 -10
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +351 -239
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
- package/dist/components/workflow-status/status-visuals.js +10 -2
- package/dist/components/workflow-status/status-visuals.js.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.d.ts +3 -1
- package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.js +13 -2
- package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +9 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js +13 -3
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/step-attempt.d.ts.map +1 -1
- package/dist/core/entities/step.d.ts +2 -0
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js +13 -0
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +56 -1
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js +98 -0
- package/dist/core/entities/workflow-run.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/core/workflow-run.d.ts +4 -4
- 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 +20 -16
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +5 -0
- package/dist/feature.js.map +1 -1
- 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/hooks/api/workflow-runs.d.ts +5 -3
- package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
- package/dist/hooks/api/workflow-runs.js +5 -4
- package/dist/hooks/api/workflow-runs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pages/workflow-job-detail-page.d.ts +11 -0
- package/dist/pages/workflow-job-detail-page.d.ts.map +1 -0
- package/dist/pages/workflow-job-detail-page.js +66 -0
- package/dist/pages/workflow-job-detail-page.js.map +1 -0
- package/dist/pages/workflow-run-detail-page.d.ts.map +1 -1
- package/dist/pages/workflow-run-detail-page.js +4 -37
- package/dist/pages/workflow-run-detail-page.js.map +1 -1
- package/dist/routes/inputs.d.ts +52 -34
- package/dist/routes/inputs.d.ts.map +1 -1
- package/dist/routes/inputs.js +74 -43
- package/dist/routes/inputs.js.map +1 -1
- package/dist/routes/job-detail.d.ts +10 -0
- package/dist/routes/job-detail.d.ts.map +1 -0
- package/dist/routes/job-detail.js +27 -0
- package/dist/routes/job-detail.js.map +1 -0
- package/dist/routes/project-route.d.ts +1 -1
- package/dist/routes/run-detail.d.ts.map +1 -1
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -9
- package/src/components/{workflow-run-view → job-detail}/agent-config-failure-callout.stories.tsx +1 -1
- package/src/components/{workflow-run-view → job-detail}/agent-config-failure-callout.tsx +2 -2
- package/src/components/job-detail/job-detail-header.test.tsx +34 -0
- package/src/components/job-detail/job-detail-header.tsx +136 -0
- package/src/components/job-detail/job-detail-view.stories.tsx +531 -0
- package/src/components/job-detail/job-detail-view.tsx +467 -0
- package/src/components/job-detail/job-empty-states.test.ts +27 -0
- package/src/components/job-detail/job-empty-states.tsx +248 -0
- package/src/components/job-detail/job-selection.test.ts +188 -0
- package/src/components/job-detail/job-selection.ts +96 -0
- package/src/components/{workflow-run-view → job-detail}/step-attempt-log-panel.test.tsx +32 -9
- package/src/components/{workflow-run-view → job-detail}/step-attempt-log-panel.tsx +52 -18
- package/src/components/job-graph/job-graph-content.tsx +1 -1
- package/src/components/step-list/step-list-model.test.ts +1 -1
- package/src/components/step-list/step-list-model.ts +2 -2
- package/src/components/step-list/step-list.stories.tsx +1 -1
- package/src/components/step-list/step-list.test.tsx +33 -0
- package/src/components/step-list/step-list.tsx +40 -9
- package/src/components/workflow-run-duration-label.tsx +50 -12
- package/src/components/workflow-run-list/workflow-run-row.tsx +6 -4
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +38 -0
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +79 -5
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +56 -60
- package/src/components/workflow-run-tabs/index.ts +3 -3
- 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-empty.tsx +6 -2
- 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/index.ts +0 -1
- package/src/components/workflow-run-view/run-workspace-nav.test.tsx +286 -0
- package/src/components/workflow-run-view/run-workspace-nav.tsx +314 -0
- package/src/components/workflow-run-view/workflow-run-selection.ts +1 -23
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +237 -1085
- package/src/components/workflow-run-view/workflow-run-view.tsx +450 -323
- package/src/components/workflow-status/status-visuals.ts +5 -2
- package/src/components/workflow-status/workflow-status-icon.stories.tsx +1 -0
- package/src/components/workflow-status/workflow-status-icon.tsx +26 -1
- package/src/core/entities/job-execution.ts +17 -2
- package/src/core/entities/step.ts +26 -0
- package/src/core/entities/workflow-run-display.test.ts +159 -0
- package/src/core/entities/workflow-run.ts +139 -1
- package/src/core/run-annotation.test.ts +315 -0
- package/src/core/run-annotation.ts +238 -0
- package/src/core/workflow-run.ts +16 -1
- package/src/feature.ts +5 -0
- package/src/hooks/api/run-annotation-mapper.ts +30 -0
- package/src/hooks/api/run-annotations.ts +137 -0
- package/src/hooks/api/workflow-runs.ts +6 -2
- package/src/index.ts +1 -0
- package/src/page-harness-budget.test.ts +1 -0
- package/src/pages/workflow-job-detail-page.test.tsx +605 -0
- package/src/pages/workflow-job-detail-page.tsx +84 -0
- package/src/pages/workflow-run-detail-page.tsx +3 -43
- package/src/pages/workflow-run-pages.test.tsx +77 -332
- package/src/routes/inputs.test.ts +56 -6
- package/src/routes/inputs.ts +71 -19
- package/src/routes/job-detail.tsx +29 -0
- package/test/pages.tsx +25 -3
- package/test/render.tsx +6 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts +0 -18
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts.map +0 -1
- package/dist/components/workflow-run-tabs/run-jobs-list.js +0 -107
- package/dist/components/workflow-run-tabs/run-jobs-list.js.map +0 -1
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts +0 -6
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts.map +0 -1
- package/dist/components/workflow-run-tabs/run-tab-count.js +0 -27
- package/dist/components/workflow-run-tabs/run-tab-count.js.map +0 -1
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts +0 -8
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts.map +0 -1
- package/dist/components/workflow-run-tabs/run-tab-strip.js +0 -82
- package/dist/components/workflow-run-tabs/run-tab-strip.js.map +0 -1
- package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts.map +0 -1
- package/dist/components/workflow-run-view/agent-config-failure-callout.js.map +0 -1
- package/dist/components/workflow-run-view/job-card.d.ts +0 -17
- package/dist/components/workflow-run-view/job-card.d.ts.map +0 -1
- package/dist/components/workflow-run-view/job-card.js +0 -496
- package/dist/components/workflow-run-view/job-card.js.map +0 -1
- package/dist/components/workflow-run-view/job-execution-switcher.d.ts.map +0 -1
- package/dist/components/workflow-run-view/job-execution-switcher.js.map +0 -1
- package/dist/components/workflow-run-view/job-execution-time-text.d.ts.map +0 -1
- package/dist/components/workflow-run-view/job-execution-time-text.js.map +0 -1
- package/dist/components/workflow-run-view/step-attempt-log-panel.d.ts +0 -9
- package/dist/components/workflow-run-view/step-attempt-log-panel.d.ts.map +0 -1
- package/dist/components/workflow-run-view/step-attempt-log-panel.js.map +0 -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/components/workflow-run-tabs/run-jobs-list.tsx +0 -151
- package/src/components/workflow-run-tabs/run-tab-count.tsx +0 -28
- package/src/components/workflow-run-tabs/run-tab-strip.stories.tsx +0 -52
- package/src/components/workflow-run-tabs/run-tab-strip.test.tsx +0 -117
- package/src/components/workflow-run-tabs/run-tab-strip.tsx +0 -97
- package/src/components/workflow-run-view/job-card.stories.tsx +0 -789
- package/src/components/workflow-run-view/job-card.test.tsx +0 -115
- package/src/components/workflow-run-view/job-card.tsx +0 -614
- package/src/core/workflow-run-tabs.ts +0 -8
- /package/dist/components/{workflow-run-view → job-detail}/agent-config-failure-callout.d.ts +0 -0
- /package/dist/components/{workflow-run-view → job-detail}/job-execution-switcher.d.ts +0 -0
- /package/dist/components/{workflow-run-view → job-detail}/job-execution-switcher.js +0 -0
- /package/dist/components/{workflow-run-view → job-detail}/job-execution-time-text.d.ts +0 -0
- /package/dist/components/{workflow-run-view → job-detail}/job-execution-time-text.js +0 -0
- /package/src/components/{workflow-run-view → job-detail}/job-execution-switcher.tsx +0 -0
- /package/src/components/{workflow-run-view → job-detail}/job-execution-time-text.tsx +0 -0
|
@@ -3,8 +3,12 @@ import {
|
|
|
3
3
|
applyWorkflowRunFilterPatch,
|
|
4
4
|
clearWorkflowRunFilters,
|
|
5
5
|
hasWorkflowRunFilters,
|
|
6
|
+
validateWorkflowJobSearch,
|
|
6
7
|
validateWorkflowRunsSearch,
|
|
8
|
+
type WorkflowJobSearch,
|
|
7
9
|
type WorkflowRunsSearch,
|
|
10
|
+
workflowJobRouteParams,
|
|
11
|
+
workflowJobSearchParams,
|
|
8
12
|
workflowRouteParams,
|
|
9
13
|
workflowRunListSearchParams,
|
|
10
14
|
workflowRunSearchParams,
|
|
@@ -62,12 +66,58 @@ describe('validateWorkflowRunsSearch', () => {
|
|
|
62
66
|
expect(validateWorkflowRunsSearch({after: '2026-02-28'})).toEqual({after: '2026-02-28'});
|
|
63
67
|
});
|
|
64
68
|
|
|
65
|
-
test('keeps
|
|
69
|
+
test('keeps legacy job selection on the run route', () => {
|
|
66
70
|
expect(validateWorkflowRunsSearch({status: 'failed', runAttempt: '2', job: 'job-1'})).toEqual({
|
|
67
71
|
status: ['failed'],
|
|
72
|
+
jobId: 'job-1',
|
|
68
73
|
runAttempt: 2,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('the job detail URL contract', () => {
|
|
79
|
+
test('reads and writes job-scoped selection parameters', () => {
|
|
80
|
+
const search: WorkflowJobSearch = {
|
|
81
|
+
jobExecutionId: 'execution-1',
|
|
82
|
+
stepId: 'step-1',
|
|
83
|
+
stepAttemptId: 'attempt-2',
|
|
84
|
+
runAttempt: 3,
|
|
85
|
+
};
|
|
86
|
+
const query = stringifyAppSearch(workflowJobSearchParams(search));
|
|
87
|
+
|
|
88
|
+
expect(query).toBe(
|
|
89
|
+
'?jobExecution=execution-1&step=step-1&stepAttempt=attempt-2&runAttempt=%223%22',
|
|
90
|
+
);
|
|
91
|
+
expect(validateWorkflowJobSearch(parseAppSearch(query))).toEqual(search);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('drops malformed job selection values', () => {
|
|
95
|
+
expect(
|
|
96
|
+
validateWorkflowJobSearch({
|
|
97
|
+
tab: 'annotations',
|
|
98
|
+
jobExecution: ['unexpected'],
|
|
99
|
+
step: '',
|
|
100
|
+
stepAttempt: 4,
|
|
101
|
+
runAttempt: '0',
|
|
102
|
+
}),
|
|
103
|
+
).toEqual({});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('requires all job route path parameters', () => {
|
|
107
|
+
expect(
|
|
108
|
+
workflowJobRouteParams({
|
|
109
|
+
workspaceSlug: 'workspace-1',
|
|
110
|
+
projectSlug: 'project-1',
|
|
111
|
+
workflowRunId: 'run-1',
|
|
112
|
+
jobId: 'job-1',
|
|
113
|
+
}),
|
|
114
|
+
).toEqual({
|
|
115
|
+
workspaceSlug: 'workspace-1',
|
|
116
|
+
projectSlug: 'project-1',
|
|
117
|
+
workflowRunId: 'run-1',
|
|
69
118
|
jobId: 'job-1',
|
|
70
119
|
});
|
|
120
|
+
expect(() => workflowJobRouteParams({workspaceSlug: 'workspace-1'})).toThrow();
|
|
71
121
|
});
|
|
72
122
|
|
|
73
123
|
test('accepts known tabs and annotation severities while dropping unknown values', () => {
|
|
@@ -84,8 +134,8 @@ describe('validateWorkflowRunsSearch', () => {
|
|
|
84
134
|
['job execution', {jobExecutionId: 'execution-1'}],
|
|
85
135
|
['step', {stepId: 'step-1'}],
|
|
86
136
|
['step attempt', {stepAttemptId: 'attempt-1'}],
|
|
87
|
-
])('defaults a legacy %s selection URL to
|
|
88
|
-
expect(workflowRunTab(search)).toBe('
|
|
137
|
+
])('defaults a legacy %s selection URL to Summary', (_selection, search) => {
|
|
138
|
+
expect(workflowRunTab(search)).toBe('summary');
|
|
89
139
|
});
|
|
90
140
|
|
|
91
141
|
test('keeps an explicit Summary tab ahead of legacy selection inference', () => {
|
|
@@ -195,9 +245,9 @@ describe('applyWorkflowRunFilterPatch', () => {
|
|
|
195
245
|
});
|
|
196
246
|
|
|
197
247
|
test('leaves the run selection parameters alone', () => {
|
|
198
|
-
const next = applyWorkflowRunFilterPatch({runAttempt: 2
|
|
248
|
+
const next = applyWorkflowRunFilterPatch({runAttempt: 2}, {search: 'deploy'});
|
|
199
249
|
|
|
200
|
-
expect(next).toEqual({runAttempt: 2,
|
|
250
|
+
expect(next).toEqual({runAttempt: 2, search: 'deploy'});
|
|
201
251
|
});
|
|
202
252
|
});
|
|
203
253
|
|
|
@@ -232,7 +282,7 @@ describe('hasWorkflowRunFilters', () => {
|
|
|
232
282
|
});
|
|
233
283
|
|
|
234
284
|
test('does not count a run selection parameter as a filter', () => {
|
|
235
|
-
expect(hasWorkflowRunFilters({runAttempt: 2
|
|
285
|
+
expect(hasWorkflowRunFilters({runAttempt: 2})).toBe(false);
|
|
236
286
|
});
|
|
237
287
|
});
|
|
238
288
|
|
package/src/routes/inputs.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {RUN_ANNOTATION_SEVERITIES, type RunAnnotationSeverity} from '#core/run-annotation.js';
|
|
1
2
|
import type {WorkflowRunSelectionInput} from '#core/workflow-run-url-state.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -12,9 +13,13 @@ export const WORKFLOW_RUN_TABS = ['summary', 'jobs', 'annotations', 'source'] as
|
|
|
12
13
|
|
|
13
14
|
export type WorkflowRunTab = (typeof WORKFLOW_RUN_TABS)[number];
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The `severity` parameter's vocabulary is the display severity set, not a second list: a URL
|
|
18
|
+
* that could name a severity the list cannot rank would be a filter with no matching rows.
|
|
19
|
+
*/
|
|
20
|
+
export const WORKFLOW_RUN_ANNOTATION_SEVERITIES = RUN_ANNOTATION_SEVERITIES;
|
|
16
21
|
|
|
17
|
-
export type WorkflowRunAnnotationSeverity =
|
|
22
|
+
export type WorkflowRunAnnotationSeverity = RunAnnotationSeverity;
|
|
18
23
|
|
|
19
24
|
export interface WorkflowRunsSearch extends WorkflowRunSelectionInput {
|
|
20
25
|
search?: string;
|
|
@@ -31,6 +36,8 @@ export interface WorkflowRunsSearch extends WorkflowRunSelectionInput {
|
|
|
31
36
|
severity?: WorkflowRunAnnotationSeverity;
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
export type WorkflowJobSearch = Omit<WorkflowRunSelectionInput, 'jobId'>;
|
|
40
|
+
|
|
34
41
|
const STATUS_VALUES = new Set<string>(WORKFLOW_RUN_LIST_STATUSES);
|
|
35
42
|
const TAB_VALUES = new Set<string>(WORKFLOW_RUN_TABS);
|
|
36
43
|
const ANNOTATION_SEVERITY_VALUES = new Set<string>(WORKFLOW_RUN_ANNOTATION_SEVERITIES);
|
|
@@ -51,7 +58,6 @@ export function validateWorkflowRunsSearch(input: Record<string, unknown>): Work
|
|
|
51
58
|
const event = repeatable(input.event);
|
|
52
59
|
const after = calendarDate(input.after);
|
|
53
60
|
const before = calendarDate(input.before);
|
|
54
|
-
const runAttempt = positiveInteger(input.runAttempt);
|
|
55
61
|
const tabValue = string(input.tab);
|
|
56
62
|
const tab = tabValue && TAB_VALUES.has(tabValue) ? (tabValue as WorkflowRunTab) : undefined;
|
|
57
63
|
const annotation = string(input.annotation);
|
|
@@ -72,14 +78,16 @@ export function validateWorkflowRunsSearch(input: Record<string, unknown>): Work
|
|
|
72
78
|
...(tab ? {tab} : {}),
|
|
73
79
|
...(annotation ? {annotation} : {}),
|
|
74
80
|
...(severity ? {severity} : {}),
|
|
75
|
-
...(
|
|
76
|
-
...(string(input.jobExecution) ? {jobExecutionId: string(input.jobExecution)} : {}),
|
|
77
|
-
...(string(input.step) ? {stepId: string(input.step)} : {}),
|
|
78
|
-
...(string(input.stepAttempt) ? {stepAttemptId: string(input.stepAttempt)} : {}),
|
|
79
|
-
...(runAttempt ? {runAttempt} : {}),
|
|
81
|
+
...workflowSelectionFromSearch(input, true),
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
/** Reads the job-detail query string without allowing a job id to leak back into URL state. */
|
|
86
|
+
export function validateWorkflowJobSearch(input: Record<string, unknown>): WorkflowJobSearch {
|
|
87
|
+
const {jobId: _jobId, ...selection} = workflowSelectionFromSearch(input, false);
|
|
88
|
+
return selection;
|
|
89
|
+
}
|
|
90
|
+
|
|
83
91
|
/**
|
|
84
92
|
* Writes the query string back.
|
|
85
93
|
*
|
|
@@ -101,23 +109,19 @@ export function workflowRunSearchParams(
|
|
|
101
109
|
...(search.tab && search.tab !== 'summary' ? {tab: search.tab} : {}),
|
|
102
110
|
...(search.annotation ? {annotation: search.annotation} : {}),
|
|
103
111
|
...(search.severity ? {severity: search.severity} : {}),
|
|
104
|
-
...(selection
|
|
105
|
-
...(selection.jobExecutionId ? {jobExecution: selection.jobExecutionId} : {}),
|
|
106
|
-
...(selection.stepId ? {step: selection.stepId} : {}),
|
|
107
|
-
...(selection.stepAttemptId ? {stepAttempt: selection.stepAttemptId} : {}),
|
|
108
|
-
...(selection.runAttempt ? {runAttempt: String(selection.runAttempt)} : {}),
|
|
112
|
+
...workflowSelectionSearchParams(selection, true),
|
|
109
113
|
};
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
export function workflowJobSearchParams(selection: WorkflowJobSearch) {
|
|
117
|
+
return workflowSelectionSearchParams(selection, false);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Resolves the run-level surface. Removed Jobs-tab and selection-only URLs fall back to Summary. */
|
|
116
121
|
export function workflowRunTab(
|
|
117
122
|
search: Pick<WorkflowRunsSearch, 'tab' | 'jobId' | 'jobExecutionId' | 'stepId' | 'stepAttemptId'>,
|
|
118
123
|
): WorkflowRunTab {
|
|
119
|
-
if (search.tab) return search.tab;
|
|
120
|
-
if (search.jobId || search.jobExecutionId || search.stepId || search.stepAttemptId) return 'jobs';
|
|
124
|
+
if (search.tab === 'annotations' || search.tab === 'source') return search.tab;
|
|
121
125
|
return 'summary';
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -203,6 +207,54 @@ export function workflowRouteParams(input: Record<string, unknown>): {
|
|
|
203
207
|
return workflowRunId ? {workspaceSlug, projectSlug, workflowRunId} : {workspaceSlug, projectSlug};
|
|
204
208
|
}
|
|
205
209
|
|
|
210
|
+
export function workflowJobRouteParams(input: Record<string, unknown>): {
|
|
211
|
+
workspaceSlug: string;
|
|
212
|
+
projectSlug: string;
|
|
213
|
+
workflowRunId: string;
|
|
214
|
+
jobId: string;
|
|
215
|
+
} {
|
|
216
|
+
const workspaceSlug = string(input.workspaceSlug);
|
|
217
|
+
const projectSlug = string(input.projectSlug);
|
|
218
|
+
const workflowRunId = string(input.workflowRunId);
|
|
219
|
+
const jobId = string(input.jobId);
|
|
220
|
+
if (!workspaceSlug || !projectSlug || !workflowRunId || !jobId) {
|
|
221
|
+
throw new Error('Workflow job route is missing required path parameters.');
|
|
222
|
+
}
|
|
223
|
+
return {workspaceSlug, projectSlug, workflowRunId, jobId};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function workflowSelectionFromSearch(
|
|
227
|
+
input: Record<string, unknown>,
|
|
228
|
+
includeJobId: boolean,
|
|
229
|
+
): WorkflowRunSelectionInput {
|
|
230
|
+
const jobId = includeJobId ? string(input.job) : undefined;
|
|
231
|
+
const jobExecutionId = string(input.jobExecution);
|
|
232
|
+
const stepId = string(input.step);
|
|
233
|
+
const stepAttemptId = string(input.stepAttempt);
|
|
234
|
+
const runAttempt = positiveInteger(input.runAttempt);
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
...(jobId ? {jobId} : {}),
|
|
238
|
+
...(jobExecutionId ? {jobExecutionId} : {}),
|
|
239
|
+
...(stepId ? {stepId} : {}),
|
|
240
|
+
...(stepAttemptId ? {stepAttemptId} : {}),
|
|
241
|
+
...(runAttempt ? {runAttempt} : {}),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function workflowSelectionSearchParams(
|
|
246
|
+
selection: WorkflowRunSelectionInput,
|
|
247
|
+
includeJobId: boolean,
|
|
248
|
+
) {
|
|
249
|
+
return {
|
|
250
|
+
...(includeJobId && selection.jobId ? {job: selection.jobId} : {}),
|
|
251
|
+
...(selection.jobExecutionId ? {jobExecution: selection.jobExecutionId} : {}),
|
|
252
|
+
...(selection.stepId ? {step: selection.stepId} : {}),
|
|
253
|
+
...(selection.stepAttemptId ? {stepAttempt: selection.stepAttemptId} : {}),
|
|
254
|
+
...(selection.runAttempt ? {runAttempt: String(selection.runAttempt)} : {}),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
206
258
|
function setOrDelete<TKey extends keyof WorkflowRunsSearch>(
|
|
207
259
|
target: WorkflowRunsSearch,
|
|
208
260
|
key: TKey,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {defineRoute, useRouteParams, useRouteSearch} from '@shipfox/client-shell/runtime';
|
|
2
|
+
import {WorkflowJobDetailPage} from '#pages/workflow-job-detail-page.js';
|
|
3
|
+
import {validateWorkflowJobSearch, workflowJobRouteParams} from './inputs.js';
|
|
4
|
+
import {ProjectRoute} from './project-route.js';
|
|
5
|
+
|
|
6
|
+
export default defineRoute({
|
|
7
|
+
staticData: {layout: 'full-bleed'},
|
|
8
|
+
validateSearch: validateWorkflowJobSearch,
|
|
9
|
+
component: () => {
|
|
10
|
+
const {workspaceSlug, projectSlug, workflowRunId, jobId} =
|
|
11
|
+
useRouteParams(workflowJobRouteParams);
|
|
12
|
+
const search = useRouteSearch(validateWorkflowJobSearch);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ProjectRoute>
|
|
16
|
+
{(project) => (
|
|
17
|
+
<WorkflowJobDetailPage
|
|
18
|
+
projectId={project.id}
|
|
19
|
+
workspaceSlug={workspaceSlug}
|
|
20
|
+
projectSlug={projectSlug}
|
|
21
|
+
workflowRunId={workflowRunId}
|
|
22
|
+
jobId={jobId}
|
|
23
|
+
search={search}
|
|
24
|
+
/>
|
|
25
|
+
)}
|
|
26
|
+
</ProjectRoute>
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
});
|
package/test/pages.tsx
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import {type RenderResult, render} from '@testing-library/react';
|
|
21
21
|
import {createStore, Provider as JotaiProvider} from 'jotai';
|
|
22
22
|
import type {ReactElement} from 'react';
|
|
23
|
-
import {validateWorkflowRunsSearch} from '#routes/inputs.js';
|
|
23
|
+
import {validateWorkflowJobSearch, validateWorkflowRunsSearch} from '#routes/inputs.js';
|
|
24
24
|
|
|
25
25
|
// The workflow run page navigates with the router (run rows are links and the page redirects
|
|
26
26
|
// to the first run), so the harness mounts the page under a memory router whose route tree
|
|
@@ -39,6 +39,10 @@ const authState: AuthState = {
|
|
|
39
39
|
workspaces: [{id: PROJECT_TEST_WID, name: 'Acme', slug: PROJECT_TEST_WSLUG, membershipId: 'm-1'}],
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
type TestPageSearch =
|
|
43
|
+
| ReturnType<typeof validateWorkflowRunsSearch>
|
|
44
|
+
| ReturnType<typeof validateWorkflowJobSearch>;
|
|
45
|
+
|
|
42
46
|
export function jsonResponse(body: unknown, init: ResponseInit = {}) {
|
|
43
47
|
return new Response(JSON.stringify(body), {
|
|
44
48
|
status: 200,
|
|
@@ -51,7 +55,8 @@ function createTestRouter(
|
|
|
51
55
|
path: string,
|
|
52
56
|
renderPage: (params: {
|
|
53
57
|
workflowRunId?: string | undefined;
|
|
54
|
-
|
|
58
|
+
jobId?: string | undefined;
|
|
59
|
+
search: TestPageSearch;
|
|
55
60
|
}) => ReactElement,
|
|
56
61
|
) {
|
|
57
62
|
const rootRoute = createRootRoute({component: Outlet});
|
|
@@ -75,6 +80,21 @@ function createTestRouter(
|
|
|
75
80
|
});
|
|
76
81
|
},
|
|
77
82
|
});
|
|
83
|
+
const jobDetailRoute = createRoute({
|
|
84
|
+
getParentRoute: () => rootRoute,
|
|
85
|
+
path: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',
|
|
86
|
+
component: function JobDetailRoute() {
|
|
87
|
+
const {workflowRunId, jobId} = useParams({strict: false}) as {
|
|
88
|
+
workflowRunId?: string;
|
|
89
|
+
jobId?: string;
|
|
90
|
+
};
|
|
91
|
+
return renderPage({
|
|
92
|
+
workflowRunId,
|
|
93
|
+
jobId,
|
|
94
|
+
search: validateWorkflowJobSearch(useSearch({strict: false}) as Record<string, unknown>),
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
});
|
|
78
98
|
const workflowsRoute = createRoute({
|
|
79
99
|
getParentRoute: () => rootRoute,
|
|
80
100
|
path: '/w/$workspaceSlug/p/$projectSlug/workflows',
|
|
@@ -95,6 +115,7 @@ function createTestRouter(
|
|
|
95
115
|
routeTree: rootRoute.addChildren([
|
|
96
116
|
runsRoute,
|
|
97
117
|
runDetailRoute,
|
|
118
|
+
jobDetailRoute,
|
|
98
119
|
workflowsRoute,
|
|
99
120
|
modelProviderSettingsRoute,
|
|
100
121
|
]),
|
|
@@ -105,7 +126,8 @@ export function renderProjectPage(
|
|
|
105
126
|
path: string,
|
|
106
127
|
renderPage: (params: {
|
|
107
128
|
workflowRunId?: string | undefined;
|
|
108
|
-
|
|
129
|
+
jobId?: string | undefined;
|
|
130
|
+
search: TestPageSearch;
|
|
109
131
|
}) => ReactElement,
|
|
110
132
|
): RenderResult & {
|
|
111
133
|
queryClient: QueryClient;
|
package/test/render.tsx
CHANGED
|
@@ -22,6 +22,11 @@ function createComponentRouter(element: ReactElement) {
|
|
|
22
22
|
path: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',
|
|
23
23
|
component: () => null,
|
|
24
24
|
});
|
|
25
|
+
const jobDetailRoute = createRoute({
|
|
26
|
+
getParentRoute: () => rootRoute,
|
|
27
|
+
path: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId',
|
|
28
|
+
component: () => null,
|
|
29
|
+
});
|
|
25
30
|
// The unfiltered empty state links here.
|
|
26
31
|
const workflowsRoute = createRoute({
|
|
27
32
|
getParentRoute: () => rootRoute,
|
|
@@ -31,7 +36,7 @@ function createComponentRouter(element: ReactElement) {
|
|
|
31
36
|
|
|
32
37
|
return createRouter({
|
|
33
38
|
history: createMemoryHistory({initialEntries: ['/']}),
|
|
34
|
-
routeTree: rootRoute.addChildren([indexRoute, runDetailRoute, workflowsRoute]),
|
|
39
|
+
routeTree: rootRoute.addChildren([indexRoute, runDetailRoute, jobDetailRoute, workflowsRoute]),
|
|
35
40
|
});
|
|
36
41
|
}
|
|
37
42
|
|