@shipfox/client-workflows 16.0.0 → 17.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +20 -0
- package/dist/components/identifier/identifier.js +2 -2
- package/dist/components/identifier/identifier.js.map +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.js +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -1
- package/dist/components/job-detail/job-context-panel.d.ts +6 -0
- package/dist/components/job-detail/job-context-panel.d.ts.map +1 -0
- package/dist/components/job-detail/job-context-panel.js +224 -0
- package/dist/components/job-detail/job-context-panel.js.map +1 -0
- package/dist/components/job-detail/job-detail-header.d.ts +3 -1
- package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-header.js +54 -48
- package/dist/components/job-detail/job-detail-header.js.map +1 -1
- package/dist/components/job-detail/job-detail-view.d.ts +1 -1
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-view.js +80 -44
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
- package/dist/components/job-detail/job-empty-states.js +19 -10
- package/dist/components/job-detail/job-empty-states.js.map +1 -1
- package/dist/components/job-detail/job-execution-switcher.js +4 -4
- package/dist/components/job-detail/job-execution-switcher.js.map +1 -1
- package/dist/components/job-detail/json-code.d.ts +14 -0
- package/dist/components/job-detail/json-code.d.ts.map +1 -0
- package/dist/components/job-detail/json-code.js +93 -0
- package/dist/components/job-detail/json-code.js.map +1 -0
- package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.js +9 -6
- package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
- package/dist/components/job-detail/step-troubleshooting.d.ts +18 -0
- package/dist/components/job-detail/step-troubleshooting.d.ts.map +1 -0
- package/dist/components/job-detail/step-troubleshooting.js +493 -0
- package/dist/components/job-detail/step-troubleshooting.js.map +1 -0
- package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +5 -4
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/job-graph/job-node.js +3 -3
- package/dist/components/job-graph/job-node.js.map +1 -1
- package/dist/components/step-list/index.d.ts +1 -0
- package/dist/components/step-list/index.d.ts.map +1 -1
- package/dist/components/step-list/index.js.map +1 -1
- package/dist/components/step-list/step-list-model.d.ts.map +1 -1
- package/dist/components/step-list/step-list-model.js +5 -0
- package/dist/components/step-list/step-list-model.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +5 -1
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js +117 -82
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-duration-label.js +1 -1
- package/dist/components/workflow-run-duration-label.js.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.js +6 -6
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js +4 -4
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +6 -6
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +7 -7
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +0 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +8 -13
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/index.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js +2 -2
- package/dist/components/workflow-run-tabs/run-annotation-count-chip.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts +9 -2
- package/dist/components/workflow-run-tabs/run-annotation-list.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-list.js +28 -19
- package/dist/components/workflow-run-tabs/run-annotation-list.js.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -1
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +5 -5
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +7 -7
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +6 -6
- package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +72 -12
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +7 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job.d.ts +9 -0
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/job.js.map +1 -1
- package/dist/core/entities/step-attempt.d.ts +29 -0
- package/dist/core/entities/step-attempt.d.ts.map +1 -1
- package/dist/core/entities/step-attempt.js.map +1 -1
- package/dist/core/entities/step.d.ts +3 -1
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/run-annotation.d.ts +6 -0
- package/dist/core/run-annotation.d.ts.map +1 -1
- package/dist/core/run-annotation.js.map +1 -1
- package/dist/core/workflow-run.d.ts +1 -1
- package/dist/core/workflow-run.d.ts.map +1 -1
- package/dist/core/workflow-run.js.map +1 -1
- package/dist/hooks/api/annotations.d.ts +63 -0
- package/dist/hooks/api/annotations.d.ts.map +1 -0
- package/dist/hooks/api/annotations.js +145 -0
- package/dist/hooks/api/annotations.js.map +1 -0
- package/dist/hooks/api/step-attempt-detail.d.ts +14 -0
- package/dist/hooks/api/step-attempt-detail.d.ts.map +1 -0
- package/dist/hooks/api/step-attempt-detail.js +43 -0
- package/dist/hooks/api/step-attempt-detail.js.map +1 -0
- package/dist/hooks/api/workflow-run-mapper.d.ts +9 -2
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +47 -0
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/pages/project-workflows-page.js +19 -19
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-run-list-page.js +1 -1
- package/dist/pages/workflow-run-list-page.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/components/identifier/identifier.tsx +2 -2
- package/src/components/job-detail/agent-config-failure-callout.tsx +5 -1
- package/src/components/job-detail/job-context-panel.test.tsx +72 -0
- package/src/components/job-detail/job-context-panel.tsx +237 -0
- package/src/components/job-detail/job-detail-header.tsx +52 -46
- package/src/components/job-detail/job-detail-view.stories.tsx +555 -53
- package/src/components/job-detail/job-detail-view.tsx +87 -45
- package/src/components/job-detail/job-empty-states.tsx +23 -10
- package/src/components/job-detail/job-execution-switcher.tsx +5 -5
- package/src/components/job-detail/json-code.tsx +120 -0
- package/src/components/job-detail/step-attempt-log-panel.test.tsx +1 -0
- package/src/components/job-detail/step-attempt-log-panel.tsx +17 -6
- package/src/components/job-detail/step-troubleshooting.stories.tsx +120 -0
- package/src/components/job-detail/step-troubleshooting.test.tsx +337 -0
- package/src/components/job-detail/step-troubleshooting.tsx +537 -0
- package/src/components/job-graph/job-graph-content.tsx +4 -3
- package/src/components/job-graph/job-node.tsx +3 -3
- package/src/components/step-list/index.ts +1 -0
- package/src/components/step-list/step-list-model.ts +5 -0
- package/src/components/step-list/step-list.test.tsx +75 -2
- package/src/components/step-list/step-list.tsx +73 -20
- package/src/components/workflow-run-duration-label.tsx +1 -1
- package/src/components/workflow-run-list/job-status-strip.tsx +6 -6
- package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-filters.tsx +4 -4
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +6 -6
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-row.tsx +7 -7
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +1 -1
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +1 -1
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +11 -11
- package/src/components/workflow-run-tabs/index.ts +5 -1
- package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +2 -2
- package/src/components/workflow-run-tabs/run-annotation-list.tsx +25 -10
- package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +5 -5
- package/src/components/workflow-run-view/run-workspace-nav.tsx +7 -7
- package/src/components/workflow-run-view/workflow-run-states.tsx +6 -6
- package/src/components/workflow-run-view/workflow-run-view.tsx +114 -14
- package/src/core/entities/job-execution.ts +7 -0
- package/src/core/entities/job.ts +9 -0
- package/src/core/entities/step-attempt.ts +33 -0
- package/src/core/entities/step.ts +3 -1
- package/src/core/run-annotation.ts +6 -0
- package/src/core/workflow-run.ts +4 -0
- package/src/hooks/api/annotations.test.ts +84 -0
- package/src/hooks/api/annotations.ts +240 -0
- package/src/hooks/api/step-attempt-detail.ts +67 -0
- package/src/hooks/api/workflow-run-mapper.ts +46 -0
- package/src/hooks/api/workflow-runs.test.tsx +61 -1
- package/src/pages/project-workflows-page.tsx +19 -19
- package/src/pages/workflow-job-detail-page.test.tsx +52 -1
- package/src/pages/workflow-run-list-page.tsx +1 -1
- package/test/fixtures/workflow-run.ts +7 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -92,6 +92,35 @@ describe('StepList', () => {
|
|
|
92
92
|
).toBeInTheDocument();
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
test('opens the inspector without expanding the step log', async () => {
|
|
96
|
+
const user = userEvent.setup();
|
|
97
|
+
const attempt = makeAttempt({status: 'succeeded'});
|
|
98
|
+
const step = makeStep({name: 'deploy', attempts: [attempt]});
|
|
99
|
+
|
|
100
|
+
function InspectableStepList() {
|
|
101
|
+
const [inspectorOpenAttemptId, setInspectorOpenAttemptId] = useState<string | null>(null);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<StepList
|
|
105
|
+
job={makeJob({steps: [step]})}
|
|
106
|
+
inspectorOpenAttemptId={inspectorOpenAttemptId}
|
|
107
|
+
onInspectorOpenChange={setInspectorOpenAttemptId}
|
|
108
|
+
renderExpandedStep={({attemptId}) => <Text size="sm">logs for {attemptId}</Text>}
|
|
109
|
+
renderInspector={(entry) => <Text size="sm">inspector for {entry.id}</Text>}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
render(<InspectableStepList />);
|
|
115
|
+
|
|
116
|
+
const deploy = screen.getByRole('button', {name: 'deploy, Succeeded, attempt 1'});
|
|
117
|
+
await user.click(screen.getByRole('button', {name: 'Inspect deploy, attempt 1'}));
|
|
118
|
+
|
|
119
|
+
expect(deploy).toHaveAttribute('aria-expanded', 'false');
|
|
120
|
+
expect(screen.queryByText(`logs for ${attempt.id}`)).not.toBeInTheDocument();
|
|
121
|
+
expect(screen.getByText(`inspector for ${attempt.id}`)).toBeInTheDocument();
|
|
122
|
+
});
|
|
123
|
+
|
|
95
124
|
test('keeps multiple expanded rows open', async () => {
|
|
96
125
|
const user = userEvent.setup();
|
|
97
126
|
const buildAttempt = makeAttempt({status: 'succeeded'});
|
|
@@ -180,8 +209,8 @@ describe('StepList', () => {
|
|
|
180
209
|
await user.click(buildRow);
|
|
181
210
|
await user.click(deployRow);
|
|
182
211
|
|
|
183
|
-
expect(buildRow).not.toHaveClass('bg-background-components-hover');
|
|
184
|
-
expect(deployRow).toHaveClass('bg-background-components-hover');
|
|
212
|
+
expect(buildRow.parentElement?.parentElement).not.toHaveClass('bg-background-components-hover');
|
|
213
|
+
expect(deployRow.parentElement?.parentElement).toHaveClass('bg-background-components-hover');
|
|
185
214
|
});
|
|
186
215
|
|
|
187
216
|
test('opens a default selected attempt', () => {
|
|
@@ -280,6 +309,50 @@ describe('StepList', () => {
|
|
|
280
309
|
expect(screen.getByText(`logs for ${deployAttempt.id}`)).toBeInTheDocument();
|
|
281
310
|
});
|
|
282
311
|
|
|
312
|
+
test('does not auto-open inspectors for failed landing attempts', async () => {
|
|
313
|
+
const user = userEvent.setup();
|
|
314
|
+
const firstAttempt = makeAttempt({id: 'failed-attempt-first', status: 'failed'});
|
|
315
|
+
const secondAttempt = makeAttempt({id: 'failed-attempt-second', status: 'failed'});
|
|
316
|
+
const firstJob = makeJob({
|
|
317
|
+
id: 'job-first',
|
|
318
|
+
steps: [makeStep({name: 'build', status: 'failed', attempts: [firstAttempt]})],
|
|
319
|
+
});
|
|
320
|
+
const secondJob = makeJob({
|
|
321
|
+
id: 'job-second',
|
|
322
|
+
steps: [makeStep({name: 'deploy', status: 'failed', attempts: [secondAttempt]})],
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
function InspectableStepList({job, defaultAttemptId}: {job: Job; defaultAttemptId: string}) {
|
|
326
|
+
const [inspectorOpenAttemptId, setInspectorOpenAttemptId] = useState<string | null>(null);
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<StepList
|
|
330
|
+
job={job}
|
|
331
|
+
defaultSelectedAttemptId={defaultAttemptId}
|
|
332
|
+
inspectorOpenAttemptId={inspectorOpenAttemptId}
|
|
333
|
+
onInspectorOpenChange={setInspectorOpenAttemptId}
|
|
334
|
+
renderExpandedStep={({attemptId}) => <Text size="sm">logs for {attemptId}</Text>}
|
|
335
|
+
renderInspector={(entry) => <Text size="sm">inspector open {entry.id}</Text>}
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const {rerender} = render(
|
|
341
|
+
<InspectableStepList job={firstJob} defaultAttemptId={firstAttempt.id} />,
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
expect(screen.queryByText(`inspector open ${firstAttempt.id}`)).not.toBeInTheDocument();
|
|
345
|
+
|
|
346
|
+
await user.click(
|
|
347
|
+
screen.getByRole('button', {name: `Inspect build, attempt ${firstAttempt.attempt}`}),
|
|
348
|
+
);
|
|
349
|
+
expect(screen.getByText(`inspector open ${firstAttempt.id}`)).toBeInTheDocument();
|
|
350
|
+
|
|
351
|
+
rerender(<InspectableStepList job={secondJob} defaultAttemptId={secondAttempt.id} />);
|
|
352
|
+
|
|
353
|
+
expect(screen.queryByText(`inspector open ${secondAttempt.id}`)).not.toBeInTheDocument();
|
|
354
|
+
});
|
|
355
|
+
|
|
283
356
|
test('does not replace the landing selection when a live job reports a new candidate', () => {
|
|
284
357
|
const firstAttempt = makeAttempt({status: 'running'});
|
|
285
358
|
const secondAttempt = makeAttempt({status: 'running'});
|
|
@@ -58,9 +58,12 @@ export interface StepListProps {
|
|
|
58
58
|
selectedAttemptId?: string | null | undefined;
|
|
59
59
|
defaultSelectedAttemptId?: string | undefined;
|
|
60
60
|
onSelectedAttemptChange?: ((attemptId: string | undefined) => void) | undefined;
|
|
61
|
+
inspectorOpenAttemptId?: string | null | undefined;
|
|
62
|
+
onInspectorOpenChange?: ((attemptId: string | null) => void) | undefined;
|
|
61
63
|
autoSelectActiveAttempt?: boolean | undefined;
|
|
62
64
|
emptyState?: StepListEmptyState | undefined;
|
|
63
65
|
renderExpandedStep?: ((context: StepExpandedContext) => ReactNode) | undefined;
|
|
66
|
+
renderInspector?: ((entry: StepListEntryModel) => ReactNode) | undefined;
|
|
64
67
|
showHeader?: boolean | undefined;
|
|
65
68
|
className?: string | undefined;
|
|
66
69
|
}
|
|
@@ -71,9 +74,12 @@ export function StepList({
|
|
|
71
74
|
selectedAttemptId,
|
|
72
75
|
defaultSelectedAttemptId,
|
|
73
76
|
onSelectedAttemptChange,
|
|
77
|
+
inspectorOpenAttemptId = null,
|
|
78
|
+
onInspectorOpenChange,
|
|
74
79
|
autoSelectActiveAttempt = false,
|
|
75
80
|
emptyState,
|
|
76
81
|
renderExpandedStep,
|
|
82
|
+
renderInspector,
|
|
77
83
|
showHeader = true,
|
|
78
84
|
className,
|
|
79
85
|
}: StepListProps) {
|
|
@@ -90,9 +96,12 @@ export function StepList({
|
|
|
90
96
|
selectedAttemptId={selectedAttemptId}
|
|
91
97
|
defaultSelectedAttemptId={defaultSelectedAttemptId}
|
|
92
98
|
onSelectedAttemptChange={onSelectedAttemptChange}
|
|
99
|
+
inspectorOpenAttemptId={inspectorOpenAttemptId}
|
|
100
|
+
onInspectorOpenChange={onInspectorOpenChange}
|
|
93
101
|
autoSelectActiveAttempt={autoSelectActiveAttempt}
|
|
94
102
|
emptyState={emptyState}
|
|
95
103
|
renderExpandedStep={renderExpandedStep}
|
|
104
|
+
renderInspector={renderInspector}
|
|
96
105
|
showHeader={showHeader}
|
|
97
106
|
className={className}
|
|
98
107
|
/>
|
|
@@ -104,9 +113,12 @@ function StepListContent({
|
|
|
104
113
|
selectedAttemptId,
|
|
105
114
|
defaultSelectedAttemptId,
|
|
106
115
|
onSelectedAttemptChange,
|
|
116
|
+
inspectorOpenAttemptId = null,
|
|
117
|
+
onInspectorOpenChange,
|
|
107
118
|
autoSelectActiveAttempt,
|
|
108
119
|
emptyState,
|
|
109
120
|
renderExpandedStep,
|
|
121
|
+
renderInspector,
|
|
110
122
|
showHeader,
|
|
111
123
|
className,
|
|
112
124
|
}: Omit<StepListProps, 'job' | 'jobExecution'> & {model: StepListModel}) {
|
|
@@ -185,6 +197,15 @@ function StepListContent({
|
|
|
185
197
|
setUserSelectedAttempt(true);
|
|
186
198
|
}, [selectedAttemptId]);
|
|
187
199
|
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (
|
|
202
|
+
inspectorOpenAttemptId !== null &&
|
|
203
|
+
!model.entries.some((entry) => entry.id === inspectorOpenAttemptId && !entry.carriedOver)
|
|
204
|
+
) {
|
|
205
|
+
onInspectorOpenChange?.(null);
|
|
206
|
+
}
|
|
207
|
+
}, [inspectorOpenAttemptId, model.entries, onInspectorOpenChange]);
|
|
208
|
+
|
|
188
209
|
function selectAttempt(nextAttemptIds: string[]) {
|
|
189
210
|
const nextAttemptId = nextSelectedAttemptId(selectedAttemptIds, nextAttemptIds);
|
|
190
211
|
setUserSelectedAttempt(true);
|
|
@@ -193,6 +214,10 @@ function StepListContent({
|
|
|
193
214
|
onSelectedAttemptChange?.(nextAttemptId);
|
|
194
215
|
}
|
|
195
216
|
|
|
217
|
+
const inspectorEntry = model.entries.find(
|
|
218
|
+
(entry) => entry.id === inspectorOpenAttemptId && !entry.carriedOver,
|
|
219
|
+
);
|
|
220
|
+
|
|
196
221
|
return (
|
|
197
222
|
<TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>
|
|
198
223
|
<section
|
|
@@ -203,7 +228,7 @@ function StepListContent({
|
|
|
203
228
|
)}
|
|
204
229
|
>
|
|
205
230
|
{showHeader ? (
|
|
206
|
-
<div className="flex min-h-40 items-center border-b border-border-neutral-base px-
|
|
231
|
+
<div className="flex min-h-40 items-center border-b border-border-neutral-base px-row py-row">
|
|
207
232
|
<Text as="h2" id={titleId} size="sm" bold className="text-foreground-neutral-base">
|
|
208
233
|
{model.jobName}
|
|
209
234
|
</Text>
|
|
@@ -220,7 +245,7 @@ function StepListContent({
|
|
|
220
245
|
asChild
|
|
221
246
|
>
|
|
222
247
|
<ol>
|
|
223
|
-
{model.entries.map((entry) => {
|
|
248
|
+
{model.entries.map((entry, index) => {
|
|
224
249
|
const selected = selectedAttemptIds.includes(entry.id);
|
|
225
250
|
return (
|
|
226
251
|
<StepRow
|
|
@@ -228,6 +253,7 @@ function StepListContent({
|
|
|
228
253
|
entry={entry}
|
|
229
254
|
selected={selected}
|
|
230
255
|
hasExpandedContent={hasExpandedContent}
|
|
256
|
+
isLast={index === model.entries.length - 1}
|
|
231
257
|
onSelect={() => {
|
|
232
258
|
selectAttempt(
|
|
233
259
|
hasExpandedContent
|
|
@@ -237,6 +263,11 @@ function StepListContent({
|
|
|
237
263
|
: [entry.id],
|
|
238
264
|
);
|
|
239
265
|
}}
|
|
266
|
+
onInspect={
|
|
267
|
+
onInspectorOpenChange && !entry.carriedOver
|
|
268
|
+
? () => onInspectorOpenChange(entry.id)
|
|
269
|
+
: undefined
|
|
270
|
+
}
|
|
240
271
|
expandedContent={
|
|
241
272
|
selected
|
|
242
273
|
? renderExpandedStep?.({
|
|
@@ -260,6 +291,7 @@ function StepListContent({
|
|
|
260
291
|
</Accordion>
|
|
261
292
|
)}
|
|
262
293
|
</section>
|
|
294
|
+
{inspectorEntry ? renderInspector?.(inspectorEntry) : null}
|
|
263
295
|
</TimeTickerProvider>
|
|
264
296
|
);
|
|
265
297
|
}
|
|
@@ -275,7 +307,7 @@ function StepListEmptyStateView({
|
|
|
275
307
|
if (!emptyState.status) {
|
|
276
308
|
return (
|
|
277
309
|
<EmptyState
|
|
278
|
-
className="min-h-120
|
|
310
|
+
className="min-h-120 p-panel"
|
|
279
311
|
icon="componentLine"
|
|
280
312
|
title={emptyState.title}
|
|
281
313
|
description={emptyState.description}
|
|
@@ -285,7 +317,7 @@ function StepListEmptyStateView({
|
|
|
285
317
|
}
|
|
286
318
|
|
|
287
319
|
return (
|
|
288
|
-
<div className="flex min-h-120 flex-col items-center justify-center gap-
|
|
320
|
+
<div className="flex min-h-120 flex-col items-center justify-center gap-inline p-panel">
|
|
289
321
|
<StepListEmptyStateIcon status={emptyState.status} />
|
|
290
322
|
<div className="text-center">
|
|
291
323
|
<Text size="sm" className="text-foreground-neutral-subtle">
|
|
@@ -302,14 +334,14 @@ function StepListEmptyStateView({
|
|
|
302
334
|
function StepListEmptyStateIcon({status}: {status: JobDisplayStatus}) {
|
|
303
335
|
if (status !== 'running') {
|
|
304
336
|
return (
|
|
305
|
-
<div className="flex size-32 items-center justify-center rounded-6 border border-border-neutral-strong bg-background-neutral-base p-
|
|
337
|
+
<div className="flex size-32 items-center justify-center rounded-6 border border-border-neutral-strong bg-background-neutral-base p-tight">
|
|
306
338
|
<WorkflowStatusIcon status={status} size={20} tooltip={false} />
|
|
307
339
|
</div>
|
|
308
340
|
);
|
|
309
341
|
}
|
|
310
342
|
|
|
311
343
|
return (
|
|
312
|
-
<div className="flex size-32 items-center justify-center rounded-6 border border-border-neutral-strong bg-background-neutral-base p-
|
|
344
|
+
<div className="flex size-32 items-center justify-center rounded-6 border border-border-neutral-strong bg-background-neutral-base p-tight text-foreground-neutral-muted">
|
|
313
345
|
<Icon name="timerLine" size={18} aria-hidden="true" />
|
|
314
346
|
</div>
|
|
315
347
|
);
|
|
@@ -319,13 +351,17 @@ function StepRow({
|
|
|
319
351
|
entry,
|
|
320
352
|
selected,
|
|
321
353
|
hasExpandedContent,
|
|
354
|
+
isLast,
|
|
322
355
|
onSelect,
|
|
356
|
+
onInspect,
|
|
323
357
|
expandedContent,
|
|
324
358
|
}: {
|
|
325
359
|
entry: StepListEntryModel;
|
|
326
360
|
selected: boolean;
|
|
327
361
|
hasExpandedContent: boolean;
|
|
362
|
+
isLast: boolean;
|
|
328
363
|
onSelect: () => void;
|
|
364
|
+
onInspect?: (() => void) | undefined;
|
|
329
365
|
expandedContent: ReactNode;
|
|
330
366
|
}) {
|
|
331
367
|
const shouldShowLabelTooltip = entry.step.label.length > 32;
|
|
@@ -341,7 +377,7 @@ function StepRow({
|
|
|
341
377
|
/>
|
|
342
378
|
<StepStatusIcon entry={entry} />
|
|
343
379
|
<div className="min-w-0 flex-1">
|
|
344
|
-
<div className="flex min-w-0 items-center gap-
|
|
380
|
+
<div className="flex min-w-0 items-center gap-inline">
|
|
345
381
|
<Text size="sm" bold className="truncate text-foreground-neutral-base">
|
|
346
382
|
{entry.step.label}
|
|
347
383
|
</Text>
|
|
@@ -353,8 +389,7 @@ function StepRow({
|
|
|
353
389
|
</>
|
|
354
390
|
);
|
|
355
391
|
const rowClasses = cn(
|
|
356
|
-
'group
|
|
357
|
-
selected && 'bg-background-components-hover',
|
|
392
|
+
'group flex min-h-44 min-w-0 flex-1 items-center gap-x-inline bg-transparent px-row py-row text-left transition-colors hover:bg-transparent active:bg-transparent focus-visible:shadow-border-interactive-with-active focus-visible:outline-none',
|
|
358
393
|
entry.carriedOver && 'opacity-[0.55]',
|
|
359
394
|
);
|
|
360
395
|
const button = hasExpandedContent ? (
|
|
@@ -388,15 +423,33 @@ function StepRow({
|
|
|
388
423
|
);
|
|
389
424
|
const row = (
|
|
390
425
|
<>
|
|
391
|
-
|
|
426
|
+
<div
|
|
427
|
+
className={cn(
|
|
428
|
+
'group flex min-w-0 items-center gap-inline pr-[8px] transition-colors hover:bg-background-components-hover active:bg-background-components-pressed',
|
|
429
|
+
selected && 'bg-background-components-hover',
|
|
430
|
+
!hasExpandedContent && ['border-b border-border-neutral-base', isLast && 'border-b-0'],
|
|
431
|
+
)}
|
|
432
|
+
>
|
|
433
|
+
<div className="min-w-0 flex-1">{triggerNode}</div>
|
|
434
|
+
{onInspect ? (
|
|
435
|
+
<Tooltip>
|
|
436
|
+
<TooltipTrigger asChild>
|
|
437
|
+
<button
|
|
438
|
+
type="button"
|
|
439
|
+
aria-label={`Inspect ${entry.step.label}, attempt ${entry.attempt}`}
|
|
440
|
+
onClick={onInspect}
|
|
441
|
+
className="flex size-28 shrink-0 items-center justify-center rounded-4 bg-transparent text-foreground-neutral-muted outline-none transition-colors hover:bg-transparent hover:text-foreground-neutral-base active:bg-transparent focus-visible:shadow-button-neutral-focus"
|
|
442
|
+
>
|
|
443
|
+
<Icon name="informationLine" size={14} aria-hidden="true" />
|
|
444
|
+
</button>
|
|
445
|
+
</TooltipTrigger>
|
|
446
|
+
<TooltipContent>Inspect step details</TooltipContent>
|
|
447
|
+
</Tooltip>
|
|
448
|
+
) : null}
|
|
449
|
+
</div>
|
|
392
450
|
{selected && expandedContent ? (
|
|
393
|
-
<AccordionContent className="border-t border-border-neutral-base bg-
|
|
394
|
-
<div className="
|
|
395
|
-
<span aria-hidden="true" />
|
|
396
|
-
<span aria-hidden="true" />
|
|
397
|
-
<div className="min-w-0">{expandedContent}</div>
|
|
398
|
-
<span aria-hidden="true" />
|
|
399
|
-
</div>
|
|
451
|
+
<AccordionContent className="border-t border-border-neutral-base bg-transparent px-0 py-0">
|
|
452
|
+
<div className="min-w-0">{expandedContent}</div>
|
|
400
453
|
</AccordionContent>
|
|
401
454
|
) : null}
|
|
402
455
|
</>
|
|
@@ -410,7 +463,7 @@ function StepRow({
|
|
|
410
463
|
);
|
|
411
464
|
}
|
|
412
465
|
|
|
413
|
-
return <li
|
|
466
|
+
return <li>{row}</li>;
|
|
414
467
|
}
|
|
415
468
|
|
|
416
469
|
function CarriedOverBadge() {
|
|
@@ -482,10 +535,10 @@ const attemptChipClasses: Record<NonNullable<BadgeVariant>, string> = {
|
|
|
482
535
|
|
|
483
536
|
function StepAttemptChip({attempt}: {attempt: StepAttemptModel}) {
|
|
484
537
|
return (
|
|
485
|
-
<div className="flex shrink-0 items-center gap-
|
|
538
|
+
<div className="flex shrink-0 items-center gap-tight" aria-hidden="true">
|
|
486
539
|
<span
|
|
487
540
|
className={cn(
|
|
488
|
-
'inline-flex h-18 min-w-24 items-center justify-center rounded-4 border px-
|
|
541
|
+
'inline-flex h-18 min-w-24 items-center justify-center rounded-4 border px-tight font-code text-xs leading-16 text-foreground-neutral-base',
|
|
489
542
|
attemptChipClasses[attempt.statusVisual.badge ?? 'neutral'],
|
|
490
543
|
)}
|
|
491
544
|
>
|
|
@@ -121,7 +121,7 @@ function DurationText({
|
|
|
121
121
|
variant="label"
|
|
122
122
|
aria-label={ariaLabel}
|
|
123
123
|
className={cn(
|
|
124
|
-
'inline-flex shrink-0 items-center gap-
|
|
124
|
+
'inline-flex shrink-0 items-center gap-tight tabular-nums text-foreground-neutral-subtle',
|
|
125
125
|
className,
|
|
126
126
|
)}
|
|
127
127
|
>
|
|
@@ -74,9 +74,9 @@ export function JobStatusStrip({jobs, className}: JobStatusStripProps) {
|
|
|
74
74
|
<span
|
|
75
75
|
role="img"
|
|
76
76
|
aria-label={summary}
|
|
77
|
-
className={cn('inline-flex items-center gap-
|
|
77
|
+
className={cn('inline-flex items-center gap-[3px]', className)}
|
|
78
78
|
>
|
|
79
|
-
<span aria-hidden="true" className="inline-flex items-center gap-
|
|
79
|
+
<span aria-hidden="true" className="inline-flex items-center gap-[3px]">
|
|
80
80
|
{visible.map((job) => (
|
|
81
81
|
<WorkflowStatusIcon
|
|
82
82
|
key={job.id}
|
|
@@ -89,7 +89,7 @@ export function JobStatusStrip({jobs, className}: JobStatusStripProps) {
|
|
|
89
89
|
/>
|
|
90
90
|
))}
|
|
91
91
|
{hiddenCount > 0 && overflowStatus ? (
|
|
92
|
-
<span className="inline-flex items-center gap-
|
|
92
|
+
<span className="inline-flex items-center gap-[2px]">
|
|
93
93
|
<WorkflowStatusIcon
|
|
94
94
|
status={overflowStatus}
|
|
95
95
|
size={GLYPH_SIZE}
|
|
@@ -127,17 +127,17 @@ function JobStatusStripTooltip({jobs, summary}: {jobs: WorkflowRunJobs; summary:
|
|
|
127
127
|
const remaining = notableTotal - named.length;
|
|
128
128
|
|
|
129
129
|
return (
|
|
130
|
-
<span className="
|
|
130
|
+
<span className="flex max-w-[280px] flex-col gap-tight">
|
|
131
131
|
<Text as="span" size="xs" className="block">
|
|
132
132
|
{summary}
|
|
133
133
|
</Text>
|
|
134
134
|
{named.map((job) => (
|
|
135
|
-
<Code as="span" variant="label" key={job.id} className="
|
|
135
|
+
<Code as="span" variant="label" key={job.id} className="block truncate">
|
|
136
136
|
{getWorkflowStatusVisual(job.status).label.toLowerCase()} · {job.name ?? job.key}
|
|
137
137
|
</Code>
|
|
138
138
|
))}
|
|
139
139
|
{remaining > 0 ? (
|
|
140
|
-
<Text as="span" size="xs" className="
|
|
140
|
+
<Text as="span" size="xs" className="block text-foreground-neutral-muted">
|
|
141
141
|
and {remaining} more
|
|
142
142
|
</Text>
|
|
143
143
|
) : null}
|
|
@@ -65,7 +65,7 @@ export function WorkflowRunFilterMenu({
|
|
|
65
65
|
</DropdownMenuTrigger>
|
|
66
66
|
<DropdownMenuContent align="start" className="max-h-[320px] w-[240px] overflow-y-auto">
|
|
67
67
|
{options.length === 0 ? (
|
|
68
|
-
<Text as="p" size="xs" className="px-
|
|
68
|
+
<Text as="p" size="xs" className="px-tight py-[6px] text-foreground-neutral-muted">
|
|
69
69
|
{emptyMessage}
|
|
70
70
|
</Text>
|
|
71
71
|
) : (
|
|
@@ -53,7 +53,7 @@ export function WorkflowRunFilters({
|
|
|
53
53
|
const [sheetOpen, setSheetOpen] = useState(false);
|
|
54
54
|
|
|
55
55
|
return (
|
|
56
|
-
<div className="flex flex-wrap items-center gap-
|
|
56
|
+
<div className="flex flex-wrap items-center gap-inline">
|
|
57
57
|
<Input
|
|
58
58
|
value={search.search ?? ''}
|
|
59
59
|
onChange={(event) => onChange({search: event.target.value})}
|
|
@@ -64,7 +64,7 @@ export function WorkflowRunFilters({
|
|
|
64
64
|
iconLeft={<Icon name="searchLine" className="size-14 text-foreground-neutral-muted" />}
|
|
65
65
|
/>
|
|
66
66
|
|
|
67
|
-
<div className="hidden flex-wrap items-center gap-
|
|
67
|
+
<div className="hidden flex-wrap items-center gap-inline md:flex">
|
|
68
68
|
<WorkflowRunFilterControls search={search} facets={facets} onChange={onChange} />
|
|
69
69
|
{hasActiveFilters ? <ClearFiltersButton onClear={onClear} /> : null}
|
|
70
70
|
</div>
|
|
@@ -85,7 +85,7 @@ export function WorkflowRunFilters({
|
|
|
85
85
|
<SheetHeader>
|
|
86
86
|
<SheetTitle>Filter runs</SheetTitle>
|
|
87
87
|
</SheetHeader>
|
|
88
|
-
<SheetBody className="flex flex-col gap-
|
|
88
|
+
<SheetBody className="flex flex-col gap-cluster">
|
|
89
89
|
<WorkflowRunFilterControls
|
|
90
90
|
search={search}
|
|
91
91
|
facets={facets}
|
|
@@ -161,7 +161,7 @@ function WorkflowRunFilterControls({
|
|
|
161
161
|
className={controlClassName}
|
|
162
162
|
/>
|
|
163
163
|
{stacked ? (
|
|
164
|
-
<div className="flex flex-col gap-
|
|
164
|
+
<div className="flex flex-col gap-inline">
|
|
165
165
|
<Label>Created between</Label>
|
|
166
166
|
<RunDateRangeFilter search={search} onChange={onChange} />
|
|
167
167
|
</div>
|
|
@@ -24,7 +24,7 @@ export function WorkflowRunListSkeleton() {
|
|
|
24
24
|
<div
|
|
25
25
|
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton row, stable position
|
|
26
26
|
key={index}
|
|
27
|
-
className="flex items-center gap-
|
|
27
|
+
className="flex items-center gap-inline px-row py-row @min-[976px]:h-44 @min-[976px]:py-0"
|
|
28
28
|
>
|
|
29
29
|
<Skeleton className="size-14 shrink-0 rounded-full" />
|
|
30
30
|
<Skeleton className="h-12 w-[220px] max-w-[40%]" />
|
|
@@ -44,9 +44,9 @@ export function WorkflowRunListSkeleton() {
|
|
|
44
44
|
*/
|
|
45
45
|
export function WorkflowRunListStaleError({query}: {query: QueryLoadErrorQuery}) {
|
|
46
46
|
return (
|
|
47
|
-
<div className="pb-
|
|
47
|
+
<div className="pb-[8px]">
|
|
48
48
|
<Callout role="alert" type="error">
|
|
49
|
-
<div className="flex items-center justify-between gap-
|
|
49
|
+
<div className="flex items-center justify-between gap-inline">
|
|
50
50
|
<Text size="xs">Could not refresh workflow runs.</Text>
|
|
51
51
|
<Button
|
|
52
52
|
type="button"
|
|
@@ -116,7 +116,7 @@ export function WorkflowRunListNoMatches({
|
|
|
116
116
|
onLoadMore?: () => void;
|
|
117
117
|
}) {
|
|
118
118
|
return (
|
|
119
|
-
<div className="flex flex-col gap-
|
|
119
|
+
<div className="flex flex-col gap-inline">
|
|
120
120
|
{isFetchNextPageError ? (
|
|
121
121
|
<Callout role="alert" type="error">
|
|
122
122
|
Could not load more workflow runs. Try again to continue searching older runs.
|
|
@@ -131,7 +131,7 @@ export function WorkflowRunListNoMatches({
|
|
|
131
131
|
: 'No run matches these filters.'
|
|
132
132
|
}
|
|
133
133
|
action={
|
|
134
|
-
<div className="flex flex-wrap justify-center gap-
|
|
134
|
+
<div className="flex flex-wrap justify-center gap-inline">
|
|
135
135
|
{hasNextPage && onLoadMore ? (
|
|
136
136
|
<Button
|
|
137
137
|
type="button"
|
|
@@ -167,7 +167,7 @@ export function WorkflowRunListLoadMore({
|
|
|
167
167
|
if (!hasNextPage || !onLoadMore) return null;
|
|
168
168
|
|
|
169
169
|
return (
|
|
170
|
-
<div className="flex flex-col items-center gap-
|
|
170
|
+
<div className="flex flex-col items-center gap-inline border-t border-border-neutral-base py-row">
|
|
171
171
|
{isFetchNextPageError ? (
|
|
172
172
|
<Callout role="alert" type="error">
|
|
173
173
|
Could not load more workflow runs. Try again.
|
|
@@ -58,7 +58,7 @@ export function WorkflowRunListView({
|
|
|
58
58
|
<TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>
|
|
59
59
|
<section
|
|
60
60
|
aria-labelledby={headingId}
|
|
61
|
-
className={cn('flex min-h-0 min-w-0 flex-1 flex-col gap-
|
|
61
|
+
className={cn('flex min-h-0 min-w-0 flex-1 flex-col gap-cluster', className)}
|
|
62
62
|
>
|
|
63
63
|
{/* The tab strip above already reads "Runs", so the page heading is for structure and
|
|
64
64
|
assistive tech rather than a second visible title competing with it. */}
|
|
@@ -81,15 +81,15 @@ export function WorkflowRunRow({
|
|
|
81
81
|
<>
|
|
82
82
|
<WorkflowStatusIcon status={display.status} size={14} className="shrink-0" />
|
|
83
83
|
|
|
84
|
-
<div className="flex min-w-0 flex-1 flex-col gap-
|
|
85
|
-
<span className="flex min-w-0 items-center gap-
|
|
84
|
+
<div className="flex min-w-0 flex-1 flex-col gap-tight @min-[976px]:flex-row @min-[976px]:items-center @min-[976px]:gap-cluster">
|
|
85
|
+
<span className="flex min-w-0 items-center gap-inline @min-[976px]:flex-1">
|
|
86
86
|
<Code variant="label" bold className="truncate text-foreground-neutral-base">
|
|
87
87
|
{run.name}
|
|
88
88
|
</Code>
|
|
89
89
|
{run.number !== null ? <WorkflowRunNumberLabel run={run} /> : null}
|
|
90
90
|
</span>
|
|
91
91
|
|
|
92
|
-
<span className="flex min-w-0 flex-wrap items-center gap-
|
|
92
|
+
<span className="flex min-w-0 flex-wrap items-center gap-inline text-foreground-neutral-subtle @min-[976px]:flex-nowrap @min-[976px]:shrink-0">
|
|
93
93
|
{run.triggerDisplayLabel ? <TriggerLabel run={run} /> : null}
|
|
94
94
|
{branch ? <BranchLabel branch={branch} isPullRequest={branch.startsWith('#')} /> : null}
|
|
95
95
|
{commit ? <CommitLabel commit={commit} /> : null}
|
|
@@ -97,7 +97,7 @@ export function WorkflowRunRow({
|
|
|
97
97
|
</span>
|
|
98
98
|
</div>
|
|
99
99
|
|
|
100
|
-
<span className="flex shrink-0 items-center gap-
|
|
100
|
+
<span className="flex shrink-0 items-center gap-cluster">
|
|
101
101
|
{/* Fixed at the strip's worst case (see MAX_VISIBLE_JOBS) so the overflow count cannot
|
|
102
102
|
paint over the duration, and kept even when a run has no jobs planned yet, so the
|
|
103
103
|
numerics stay in line down the list instead of stepping in and out. */}
|
|
@@ -120,7 +120,7 @@ export function WorkflowRunRow({
|
|
|
120
120
|
// Rows run edge to edge inside the list's scroll container, which would clip the standard
|
|
121
121
|
// outset focus ring, so this one is inset per the design system's focus-ring rule.
|
|
122
122
|
const rowClassName =
|
|
123
|
-
'flex w-full min-w-0 items-center gap-
|
|
123
|
+
'flex w-full min-w-0 items-center gap-inline px-row py-row text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';
|
|
124
124
|
|
|
125
125
|
// Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row
|
|
126
126
|
// replaces them on the next poll, so they render non-interactively instead of as a link
|
|
@@ -164,7 +164,7 @@ function TriggerLabel({run}: {run: WorkflowRunListItem}) {
|
|
|
164
164
|
return (
|
|
165
165
|
<Tooltip>
|
|
166
166
|
<TooltipTrigger asChild>
|
|
167
|
-
<span className="flex min-w-0 max-w-[140px] items-center gap-
|
|
167
|
+
<span className="flex min-w-0 max-w-[140px] items-center gap-tight outline-none">
|
|
168
168
|
<TriggerSourceIcon
|
|
169
169
|
provider={run.triggerProvider}
|
|
170
170
|
source={run.triggerSource}
|
|
@@ -235,7 +235,7 @@ function MetadataChip({
|
|
|
235
235
|
children: string;
|
|
236
236
|
}) {
|
|
237
237
|
return (
|
|
238
|
-
<span className={cn('flex min-w-0 shrink-0 items-center gap-
|
|
238
|
+
<span className={cn('flex min-w-0 shrink-0 items-center gap-tight', className)} title={title}>
|
|
239
239
|
<Icon name={icon} className="size-12 shrink-0 text-foreground-neutral-muted" aria-hidden />
|
|
240
240
|
<Code as="span" variant="label" className="min-w-0 truncate">
|
|
241
241
|
{children}
|
|
@@ -52,7 +52,7 @@ export function WorkflowRunAttemptSwitcher({
|
|
|
52
52
|
size="2xs"
|
|
53
53
|
iconRight="arrowDownSLine"
|
|
54
54
|
aria-label={`Switch attempt, currently ${run.runAttempt.attempt} of ${maxAttempt}`}
|
|
55
|
-
className="h-20 px-
|
|
55
|
+
className="h-20 px-[4px] text-foreground-neutral-subtle hover:text-foreground-neutral-base"
|
|
56
56
|
>
|
|
57
57
|
<Text as="span" size="xs" className="text-inherit">
|
|
58
58
|
Attempt {run.runAttempt.attempt} of {maxAttempt}
|
|
@@ -38,7 +38,7 @@ describe('WorkflowRunSummary', () => {
|
|
|
38
38
|
|
|
39
39
|
const summary = await screen.findByRole('region', {name: 'deploy-web'});
|
|
40
40
|
|
|
41
|
-
expect(summary).toHaveClass('bg-background-neutral-background', 'px-
|
|
41
|
+
expect(summary).toHaveClass('bg-background-neutral-background', 'px-row', 'py-row');
|
|
42
42
|
expect(summary.firstElementChild).not.toHaveClass('max-w-[1120px]');
|
|
43
43
|
expect(within(summary).getByRole('heading', {name: 'deploy-web'})).toBeInTheDocument();
|
|
44
44
|
expect(within(summary).getAllByText('Running')).not.toHaveLength(0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {TriggerSourceIcon} from '@shipfox/client-triggers';
|
|
2
|
+
import {MetadataSeparator} from '@shipfox/client-ui';
|
|
2
3
|
import {Badge} from '@shipfox/react-ui/badge';
|
|
3
4
|
import {Button} from '@shipfox/react-ui/button';
|
|
4
5
|
import {
|
|
@@ -77,10 +78,13 @@ export function WorkflowRunSummary({
|
|
|
77
78
|
|
|
78
79
|
return (
|
|
79
80
|
<TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>
|
|
80
|
-
<section
|
|
81
|
-
|
|
81
|
+
<section
|
|
82
|
+
aria-labelledby={headingId}
|
|
83
|
+
className="bg-background-neutral-background px-row py-row"
|
|
84
|
+
>
|
|
85
|
+
<div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1">
|
|
82
86
|
<div className="col-start-1 row-start-1 min-w-0 max-[480px]:col-start-auto max-[480px]:row-start-auto">
|
|
83
|
-
<div className="flex min-w-0 items-center gap-
|
|
87
|
+
<div className="flex min-w-0 items-center gap-inline">
|
|
84
88
|
<Badge variant={status.badge} size="xs">
|
|
85
89
|
<span className="text-center" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>
|
|
86
90
|
{status.label}
|
|
@@ -107,7 +111,7 @@ export function WorkflowRunSummary({
|
|
|
107
111
|
</div>
|
|
108
112
|
|
|
109
113
|
{hasAction ? (
|
|
110
|
-
<div className="col-start-2 row-start-1 flex min-w-max items-center gap-
|
|
114
|
+
<div className="col-start-2 row-start-1 flex min-w-max items-center gap-inline justify-self-end max-[480px]:col-start-auto max-[480px]:row-start-auto max-[480px]:justify-self-start">
|
|
111
115
|
<WorkflowRunActionSlot
|
|
112
116
|
action={action}
|
|
113
117
|
cancelling={cancelling}
|
|
@@ -118,7 +122,7 @@ export function WorkflowRunSummary({
|
|
|
118
122
|
</div>
|
|
119
123
|
) : null}
|
|
120
124
|
|
|
121
|
-
<div className="col-span-2 row-start-2 flex min-w-0 items-center gap-
|
|
125
|
+
<div className="col-span-2 row-start-2 flex min-w-0 items-center gap-cluster overflow-hidden text-foreground-neutral-subtle max-[480px]:col-span-1 max-[480px]:row-start-auto">
|
|
122
126
|
{run.number !== null ? (
|
|
123
127
|
<>
|
|
124
128
|
<WorkflowRunNumberLabel run={run} />
|
|
@@ -144,7 +148,7 @@ export function WorkflowRunSummary({
|
|
|
144
148
|
<button
|
|
145
149
|
type="button"
|
|
146
150
|
aria-label={run.triggerLabel}
|
|
147
|
-
className="inline-flex max-w-full min-w-0 cursor-help items-center gap-
|
|
151
|
+
className="inline-flex max-w-full min-w-0 cursor-help items-center gap-tight rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-subtle outline-none focus-visible:shadow-button-neutral-focus"
|
|
148
152
|
>
|
|
149
153
|
<TriggerSourceIcon
|
|
150
154
|
provider={run.triggerProvider}
|
|
@@ -188,7 +192,7 @@ export function WorkflowRunSummary({
|
|
|
188
192
|
{blockingJob ? (
|
|
189
193
|
<>
|
|
190
194
|
<MetadataSeparator />
|
|
191
|
-
<span className="flex min-w-0 items-center gap-
|
|
195
|
+
<span className="flex min-w-0 items-center gap-tight">
|
|
192
196
|
<Text as="span" size="xs" className="shrink-0">
|
|
193
197
|
waiting on
|
|
194
198
|
</Text>
|
|
@@ -310,7 +314,3 @@ function hasFailedOrCancelledJobs(run: WorkflowRunDetail): boolean {
|
|
|
310
314
|
function workflowRunHasJobs(run: WorkflowRunDetail): run is WorkflowRunDetail & {jobs: Job[]} {
|
|
311
315
|
return 'jobs' in run && Array.isArray(run.jobs);
|
|
312
316
|
}
|
|
313
|
-
|
|
314
|
-
export function MetadataSeparator() {
|
|
315
|
-
return <span aria-hidden="true" className="h-12 w-px shrink-0 bg-border-neutral-base" />;
|
|
316
|
-
}
|