@shipfox/client-workflows 20.0.0 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +51 -0
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-view.js +232 -44
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/job-empty-states.js +2 -2
- package/dist/components/job-detail/job-empty-states.js.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.d.ts +7 -1
- package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.js +37 -10
- package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +2 -2
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/step-list/step-list-model.d.ts +1 -0
- package/dist/components/step-list/step-list-model.d.ts.map +1 -1
- package/dist/components/step-list/step-list-model.js +1 -1
- package/dist/components/step-list/step-list-model.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +2 -1
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js +25 -9
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.d.ts +9 -1
- package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.js +22 -11
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
- 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 +13 -7
- 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.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +43 -38
- 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.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +34 -22
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts +3 -3
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +25 -18
- 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 +4 -4
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +20 -7
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +1 -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.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +103 -78
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.js +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -1
- package/dist/pages/project-workflows-page.d.ts.map +1 -1
- package/dist/pages/project-workflows-page.js +171 -158
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-job-detail-page.d.ts.map +1 -1
- package/dist/pages/workflow-job-detail-page.js +3 -2
- package/dist/pages/workflow-job-detail-page.js.map +1 -1
- package/dist/pages/workflow-run-detail-page.js +2 -1
- package/dist/pages/workflow-run-detail-page.js.map +1 -1
- package/dist/pages/workflow-run-list-page.d.ts.map +1 -1
- package/dist/pages/workflow-run-list-page.js +9 -11
- package/dist/pages/workflow-run-list-page.js.map +1 -1
- package/dist/routes/job-detail.d.ts +1 -1
- package/dist/routes/job-detail.js +1 -1
- package/dist/routes/job-detail.js.map +1 -1
- package/dist/routes/run-detail.d.ts +1 -1
- package/dist/routes/run-detail.js +1 -1
- package/dist/routes/run-detail.js.map +1 -1
- package/dist/routes/runs.d.ts +1 -1
- package/dist/routes/runs.js +1 -1
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/workflows.d.ts +3 -0
- package/dist/routes/workflows.js +3 -0
- package/dist/routes/workflows.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/job-detail/job-detail-view.tsx +264 -49
- package/src/components/job-detail/job-empty-states.tsx +2 -2
- package/src/components/job-detail/step-attempt-log-panel.test.tsx +30 -12
- package/src/components/job-detail/step-attempt-log-panel.tsx +68 -10
- package/src/components/job-graph/job-graph-content.tsx +2 -2
- package/src/components/job-graph/job-graph.stories.tsx +1 -1
- package/src/components/job-graph/job-node.stories.tsx +1 -1
- package/src/components/step-list/step-list-model.ts +1 -1
- package/src/components/step-list/step-list.test.tsx +29 -1
- package/src/components/step-list/step-list.tsx +29 -11
- package/src/components/workflow-run-list/job-status-strip.tsx +25 -12
- package/src/components/workflow-run-list/workflow-run-filters.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-list-content.tsx +7 -2
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +42 -41
- package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +53 -4
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +28 -22
- package/src/components/workflow-run-list/workflow-run-list.stories.tsx +9 -20
- package/src/components/workflow-run-list/workflow-run-row.tsx +26 -19
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +3 -3
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +11 -2
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +4 -7
- package/src/components/workflow-run-view/run-workspace-nav.test.tsx +40 -2
- package/src/components/workflow-run-view/run-workspace-nav.tsx +28 -9
- package/src/components/workflow-run-view/workflow-run-states.tsx +1 -4
- package/src/components/workflow-run-view/workflow-run-view.stories.tsx +142 -0
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +42 -8
- package/src/components/workflow-run-view/workflow-run-view.tsx +112 -96
- package/src/components/workflow-source-panel/workflow-source-content.tsx +2 -2
- package/src/pages/project-workflows-page.tsx +135 -125
- package/src/pages/workflow-job-detail-page.test.tsx +32 -0
- package/src/pages/workflow-job-detail-page.tsx +5 -1
- package/src/pages/workflow-run-detail-page.tsx +1 -1
- package/src/pages/workflow-run-list-page.tsx +9 -11
- package/src/pages/workflow-run-pages.test.tsx +26 -0
- package/src/routes/job-detail.tsx +1 -1
- package/src/routes/run-detail.tsx +1 -1
- package/src/routes/runs.tsx +1 -1
- package/src/routes/workflows.tsx +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type {WorkflowRunDetailResponseDto} from '@shipfox/api-workflows-dto';
|
|
2
|
+
import {configureApiClient} from '@shipfox/client-api';
|
|
3
|
+
import type {Decorator, Meta, StoryObj} from '@storybook/react';
|
|
4
|
+
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
|
5
|
+
import {type ReactNode, useEffect, useState} from 'react';
|
|
6
|
+
import {
|
|
7
|
+
runAttemptsResponseDto,
|
|
8
|
+
workflowJobDto,
|
|
9
|
+
workflowRunDetailDto,
|
|
10
|
+
} from '#test/fixtures/workflow-run.js';
|
|
11
|
+
import {WorkflowRunView} from './workflow-run-view.js';
|
|
12
|
+
|
|
13
|
+
const PROJECT_ID = '22222222-2222-4222-8222-222222222222';
|
|
14
|
+
const RUN_ID = '11111111-1111-4111-8111-111111111111';
|
|
15
|
+
const RUN_STARTED_AT = '2026-06-26T11:57:00.000Z';
|
|
16
|
+
const RUN_FINISHED_AT = '2026-06-26T11:59:00.000Z';
|
|
17
|
+
|
|
18
|
+
const RUN_RESPONSE: WorkflowRunDetailResponseDto = workflowRunDetailDto({
|
|
19
|
+
id: RUN_ID,
|
|
20
|
+
project_id: PROJECT_ID,
|
|
21
|
+
name: 'deploy-web',
|
|
22
|
+
status: 'succeeded',
|
|
23
|
+
started_at: RUN_STARTED_AT,
|
|
24
|
+
finished_at: RUN_FINISHED_AT,
|
|
25
|
+
has_started_job_execution: true,
|
|
26
|
+
jobs: [
|
|
27
|
+
workflowJobDto({
|
|
28
|
+
key: 'build',
|
|
29
|
+
name: 'build',
|
|
30
|
+
status: 'succeeded',
|
|
31
|
+
position: 0,
|
|
32
|
+
}),
|
|
33
|
+
workflowJobDto({
|
|
34
|
+
key: 'deploy',
|
|
35
|
+
name: 'deploy',
|
|
36
|
+
status: 'succeeded',
|
|
37
|
+
position: 1,
|
|
38
|
+
dependencies: ['build'],
|
|
39
|
+
}),
|
|
40
|
+
workflowJobDto({
|
|
41
|
+
key: 'notify',
|
|
42
|
+
name: 'notify',
|
|
43
|
+
status: 'succeeded',
|
|
44
|
+
position: 2,
|
|
45
|
+
dependencies: ['deploy'],
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
const RUN_ATTEMPTS_RESPONSE = runAttemptsResponseDto({attempts: []});
|
|
50
|
+
|
|
51
|
+
const withRunApi: Decorator = (Story) => (
|
|
52
|
+
<RunWorkspaceStoryProviders>
|
|
53
|
+
<Story />
|
|
54
|
+
</RunWorkspaceStoryProviders>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const meta = {
|
|
58
|
+
title: 'Workflows/WorkflowRunView',
|
|
59
|
+
component: WorkflowRunView,
|
|
60
|
+
parameters: {
|
|
61
|
+
layout: 'fullscreen',
|
|
62
|
+
viewport: {
|
|
63
|
+
defaultViewport: 'wide',
|
|
64
|
+
options: {
|
|
65
|
+
wide: {
|
|
66
|
+
name: 'Wide',
|
|
67
|
+
styles: {width: '1440px', height: '720px'},
|
|
68
|
+
type: 'desktop',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
globals: {
|
|
73
|
+
viewport: {value: 'wide'},
|
|
74
|
+
},
|
|
75
|
+
argos: {
|
|
76
|
+
modes: {dark: {theme: 'dark'}},
|
|
77
|
+
fitToContent: false,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
decorators: [withRunApi],
|
|
81
|
+
args: {
|
|
82
|
+
projectId: PROJECT_ID,
|
|
83
|
+
workspaceSlug: 'acme',
|
|
84
|
+
projectSlug: 'platform',
|
|
85
|
+
workflowRunId: RUN_ID,
|
|
86
|
+
},
|
|
87
|
+
} satisfies Meta<typeof WorkflowRunView>;
|
|
88
|
+
|
|
89
|
+
export default meta;
|
|
90
|
+
type Story = StoryObj<typeof meta>;
|
|
91
|
+
|
|
92
|
+
export const WideViewport: Story = {};
|
|
93
|
+
|
|
94
|
+
function RunWorkspaceStoryProviders({children}: {children: ReactNode}) {
|
|
95
|
+
const [queryClient] = useState(
|
|
96
|
+
() => new QueryClient({defaultOptions: {queries: {retry: false}}}),
|
|
97
|
+
);
|
|
98
|
+
const [configured, setConfigured] = useState(false);
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
configureApiClient({
|
|
102
|
+
baseUrl: 'https://api.example.test',
|
|
103
|
+
fetchImpl: (input) => {
|
|
104
|
+
const url =
|
|
105
|
+
input instanceof Request ? input.url : input instanceof URL ? input.href : String(input);
|
|
106
|
+
const path = new URL(url, 'https://api.example.test').pathname;
|
|
107
|
+
const response =
|
|
108
|
+
path === '/annotations'
|
|
109
|
+
? {
|
|
110
|
+
body: {annotations: [], has_more: false, next_cursor: null},
|
|
111
|
+
status: 200,
|
|
112
|
+
}
|
|
113
|
+
: path === `/workflows/runs/${RUN_ID}/attempts`
|
|
114
|
+
? {body: RUN_ATTEMPTS_RESPONSE, status: 200}
|
|
115
|
+
: path === `/workflows/runs/${RUN_ID}`
|
|
116
|
+
? {body: RUN_RESPONSE, status: 200}
|
|
117
|
+
: {body: {code: 'not-found'}, status: 404};
|
|
118
|
+
return new Response(JSON.stringify(response.body), {
|
|
119
|
+
status: response.status,
|
|
120
|
+
headers: {'content-type': 'application/json'},
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
setConfigured(true);
|
|
125
|
+
|
|
126
|
+
return () => {
|
|
127
|
+
configureApiClient({baseUrl: '', fetchImpl: undefined});
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
if (!configured) return null;
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<QueryClientProvider client={queryClient}>
|
|
135
|
+
<div className="flex h-[720px] min-w-[1440px] w-[1440px] bg-background-subtle-base">
|
|
136
|
+
<div className="flex min-h-0 min-w-0 w-full flex-1 flex-col px-frame py-frame">
|
|
137
|
+
{children}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</QueryClientProvider>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
@@ -49,23 +49,57 @@ describe('WorkflowRunView', () => {
|
|
|
49
49
|
const summary = await screen.findByRole('region', {name: 'deploy-web'});
|
|
50
50
|
expect(within(summary).getByRole('heading', {name: 'deploy-web'})).toBeInTheDocument();
|
|
51
51
|
expect(screen.getByRole('navigation', {name: 'Run workspace'})).toBeInTheDocument();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
).toHaveClass('
|
|
52
|
+
const workspaceLayout = screen
|
|
53
|
+
.getByRole('navigation', {name: 'Run workspace'})
|
|
54
|
+
.closest('[data-run-workspace-layout]');
|
|
55
|
+
expect(workspaceLayout).toHaveClass('border-t', 'border-border-neutral-base');
|
|
56
|
+
expect(workspaceLayout).not.toHaveClass('max-w-[1360px]');
|
|
57
|
+
const workspaceFrame = workspaceLayout?.querySelector('[data-run-workspace-frame]');
|
|
58
|
+
expect(workspaceFrame).toHaveClass('w-full', 'min-[768px]:flex-row');
|
|
59
|
+
expect(workspaceFrame).not.toHaveClass('mx-auto', 'max-w-[calc(240px_+_1120px)]');
|
|
57
60
|
expect(screen.getByRole('link', {name: 'Summary'})).toHaveAttribute('aria-current', 'page');
|
|
58
61
|
expect(screen.getByRole('heading', {name: 'Jobs'})).toBeInTheDocument();
|
|
59
62
|
expect(screen.getByRole('heading', {name: 'Run details'})).toBeInTheDocument();
|
|
60
|
-
|
|
63
|
+
const allJobsSummary = screen.getByRole('region', {name: 'All jobs summary'});
|
|
64
|
+
expect(allJobsSummary).toBeInTheDocument();
|
|
65
|
+
expect(allJobsSummary.querySelector('[data-slot="panel"]')).not.toBeNull();
|
|
66
|
+
expect(allJobsSummary.querySelector('[data-slot="panel-body"]')).toHaveClass(
|
|
67
|
+
'bg-background-components-base',
|
|
68
|
+
);
|
|
61
69
|
expect(screen.getByRole('region', {name: 'Workflow jobs'})).toBeInTheDocument();
|
|
62
|
-
expect(container.querySelector('[data-run-workspace-content]')).toHaveClass(
|
|
70
|
+
expect(container.querySelector('[data-run-workspace-content]')).toHaveClass('flex-1');
|
|
71
|
+
expect(container.querySelector('[data-run-workspace-content]')).not.toHaveClass(
|
|
63
72
|
'bg-background-neutral-base',
|
|
64
|
-
'flex-1',
|
|
65
73
|
);
|
|
66
74
|
expect(screen.queryByRole('tab', {name: 'Jobs'})).not.toBeInTheDocument();
|
|
67
75
|
});
|
|
68
76
|
|
|
77
|
+
test.each([
|
|
78
|
+
{tab: undefined, region: 'All jobs summary'},
|
|
79
|
+
{tab: 'source', region: 'Workflow source'},
|
|
80
|
+
{tab: 'annotations', region: 'Run annotations'},
|
|
81
|
+
] as const)('does not cap the $region section at 1120px', async ({tab, region}) => {
|
|
82
|
+
configureRunFetch();
|
|
83
|
+
|
|
84
|
+
renderView({tab});
|
|
85
|
+
|
|
86
|
+
const section = await screen.findByRole('region', {name: region});
|
|
87
|
+
expect(section.firstElementChild).not.toHaveClass('mx-auto', 'px-frame', 'max-w-[1120px]');
|
|
88
|
+
expect(section.querySelector('[data-slot="panel"]')).not.toBeNull();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('keeps dedicated job content on the full-width data surface', async () => {
|
|
92
|
+
configureRunFetch();
|
|
93
|
+
|
|
94
|
+
renderView({jobContent: <div>Job logs</div>});
|
|
95
|
+
|
|
96
|
+
const jobContent = await screen.findByText('Job logs');
|
|
97
|
+
const workspaceFrame = jobContent.closest('[data-run-workspace-frame]');
|
|
98
|
+
|
|
99
|
+
expect(workspaceFrame).toHaveClass('w-full', 'min-[768px]:flex-row');
|
|
100
|
+
expect(workspaceFrame).not.toHaveClass('max-w-[calc(240px_+_1120px)]');
|
|
101
|
+
});
|
|
102
|
+
|
|
69
103
|
test('treats the removed Jobs tab URL as the graph Summary', async () => {
|
|
70
104
|
configureRunFetch();
|
|
71
105
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {ApiError} from '@shipfox/client-api';
|
|
2
2
|
import {QueryLoadError} from '@shipfox/client-ui';
|
|
3
3
|
import {EmptyState} from '@shipfox/react-ui/empty-state';
|
|
4
|
+
import {Panel, PanelBody, PanelHeader} from '@shipfox/react-ui/panel';
|
|
4
5
|
import {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';
|
|
5
6
|
import {
|
|
6
7
|
Select,
|
|
@@ -309,47 +310,49 @@ function RunViewContent({
|
|
|
309
310
|
|
|
310
311
|
<div
|
|
311
312
|
data-run-workspace-layout
|
|
312
|
-
className="flex min-h-0 min-w-0 flex-1 flex-col border-t border-border-neutral-base
|
|
313
|
+
className="flex min-h-0 min-w-0 flex-1 flex-col border-t border-border-neutral-base"
|
|
313
314
|
>
|
|
314
|
-
{runData && workspaceSlug && projectSlug ? (
|
|
315
|
-
<RunWorkspaceNav
|
|
316
|
-
workspaceSlug={workspaceSlug}
|
|
317
|
-
projectSlug={projectSlug}
|
|
318
|
-
run={runData}
|
|
319
|
-
activeSection={activeSection}
|
|
320
|
-
currentJobId={activeJobId}
|
|
321
|
-
jobSearch={jobSearch}
|
|
322
|
-
annotationSummary={annotationSummary}
|
|
323
|
-
/>
|
|
324
|
-
) : (
|
|
325
|
-
<RunWorkspaceNavSkeleton />
|
|
326
|
-
)}
|
|
327
|
-
|
|
328
315
|
<div
|
|
329
|
-
data-run-workspace-
|
|
330
|
-
className="flex min-h-0 min-w-0 flex-1 flex-col
|
|
316
|
+
data-run-workspace-frame
|
|
317
|
+
className="flex min-h-0 min-w-0 w-full flex-1 flex-col min-[768px]:flex-row"
|
|
331
318
|
>
|
|
332
|
-
{runData &&
|
|
333
|
-
|
|
334
|
-
) : runData ? (
|
|
335
|
-
<RunSectionContent
|
|
336
|
-
section={activeSection}
|
|
337
|
-
run={runData}
|
|
338
|
-
annotations={annotations}
|
|
339
|
-
annotationSummary={annotationSummary}
|
|
319
|
+
{runData && workspaceSlug && projectSlug ? (
|
|
320
|
+
<RunWorkspaceNav
|
|
340
321
|
workspaceSlug={workspaceSlug}
|
|
341
322
|
projectSlug={projectSlug}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
sourceSnapshot={sourceSnapshot}
|
|
348
|
-
highlightedLineRange={highlightedLineRange}
|
|
323
|
+
run={runData}
|
|
324
|
+
activeSection={activeSection}
|
|
325
|
+
currentJobId={activeJobId}
|
|
326
|
+
jobSearch={jobSearch}
|
|
327
|
+
annotationSummary={annotationSummary}
|
|
349
328
|
/>
|
|
350
329
|
) : (
|
|
351
|
-
<
|
|
330
|
+
<RunWorkspaceNavSkeleton />
|
|
352
331
|
)}
|
|
332
|
+
|
|
333
|
+
<div data-run-workspace-content className="flex min-h-0 min-w-0 flex-1 flex-col">
|
|
334
|
+
{runData && jobContent ? (
|
|
335
|
+
jobContent
|
|
336
|
+
) : runData ? (
|
|
337
|
+
<RunSectionContent
|
|
338
|
+
section={activeSection}
|
|
339
|
+
run={runData}
|
|
340
|
+
annotations={annotations}
|
|
341
|
+
annotationSummary={annotationSummary}
|
|
342
|
+
workspaceSlug={workspaceSlug}
|
|
343
|
+
projectSlug={projectSlug}
|
|
344
|
+
selection={selection}
|
|
345
|
+
selectedJobId={selection?.jobId}
|
|
346
|
+
onSelectGraphJob={selectGraphJob}
|
|
347
|
+
onSelectAnnotationJob={selectAnnotationJob}
|
|
348
|
+
onClearAnnotationFilters={clearAnnotationFilters}
|
|
349
|
+
sourceSnapshot={sourceSnapshot}
|
|
350
|
+
highlightedLineRange={highlightedLineRange}
|
|
351
|
+
/>
|
|
352
|
+
) : (
|
|
353
|
+
<div className="min-h-0 flex-1 overflow-auto p-panel">{loadingOrError}</div>
|
|
354
|
+
)}
|
|
355
|
+
</div>
|
|
353
356
|
</div>
|
|
354
357
|
</div>
|
|
355
358
|
</div>
|
|
@@ -395,16 +398,20 @@ function RunSectionContent({
|
|
|
395
398
|
aria-label="All jobs summary"
|
|
396
399
|
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
397
400
|
>
|
|
398
|
-
<div className="
|
|
401
|
+
<div className="flex w-full flex-col gap-group">
|
|
399
402
|
<Text as="h2" className="sr-only">
|
|
400
403
|
All jobs summary
|
|
401
404
|
</Text>
|
|
402
|
-
<
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
405
|
+
<Panel className="min-h-160">
|
|
406
|
+
<PanelBody className="min-h-160 bg-background-components-base p-0">
|
|
407
|
+
<JobGraph
|
|
408
|
+
run={run}
|
|
409
|
+
selectedJobId={selectedJobId}
|
|
410
|
+
onSelectedJobChange={onSelectGraphJob}
|
|
411
|
+
className="min-h-160 overflow-hidden"
|
|
412
|
+
/>
|
|
413
|
+
</PanelBody>
|
|
414
|
+
</Panel>
|
|
408
415
|
</div>
|
|
409
416
|
</section>
|
|
410
417
|
);
|
|
@@ -431,28 +438,33 @@ function RunSectionContent({
|
|
|
431
438
|
aria-label="Workflow source"
|
|
432
439
|
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
433
440
|
>
|
|
434
|
-
<div className="
|
|
441
|
+
<div className="flex min-h-full w-full flex-col">
|
|
435
442
|
<Text as="h2" className="sr-only">
|
|
436
443
|
Workflow source
|
|
437
444
|
</Text>
|
|
438
|
-
|
|
439
|
-
<
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
445
|
+
<Panel className="min-h-160 flex-1">
|
|
446
|
+
<PanelBody className="min-h-160 flex-1 p-0">
|
|
447
|
+
{sourceSnapshot ? (
|
|
448
|
+
<WorkflowSourceContent
|
|
449
|
+
source={sourceSnapshot}
|
|
450
|
+
highlightedLineRange={highlightedLineRange}
|
|
451
|
+
scrollHighlightedIntoView
|
|
452
|
+
/>
|
|
453
|
+
) : (
|
|
454
|
+
<EmptyState
|
|
455
|
+
variant="panel"
|
|
456
|
+
className="min-h-160"
|
|
457
|
+
icon="fileDamageLine"
|
|
458
|
+
title="Source snapshot unavailable"
|
|
459
|
+
description={
|
|
460
|
+
run.isTemporary
|
|
461
|
+
? 'Temporary runs do not capture workflow source.'
|
|
462
|
+
: 'This run was created before workflow source snapshots were captured.'
|
|
463
|
+
}
|
|
464
|
+
/>
|
|
465
|
+
)}
|
|
466
|
+
</PanelBody>
|
|
467
|
+
</Panel>
|
|
456
468
|
</div>
|
|
457
469
|
</section>
|
|
458
470
|
);
|
|
@@ -526,45 +538,49 @@ function RunAnnotationsSection({
|
|
|
526
538
|
aria-label="Run annotations"
|
|
527
539
|
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
528
540
|
>
|
|
529
|
-
<div className="
|
|
541
|
+
<div className="flex w-full flex-col">
|
|
530
542
|
<Text as="h2" className="sr-only">
|
|
531
543
|
Annotations
|
|
532
544
|
</Text>
|
|
533
|
-
<
|
|
534
|
-
<
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
(
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
545
|
+
<Panel>
|
|
546
|
+
<PanelHeader className="flex-wrap">
|
|
547
|
+
<RunAnnotationSummaryLine
|
|
548
|
+
summary={annotationSummary}
|
|
549
|
+
workspaceSlug={workspaceSlug}
|
|
550
|
+
projectSlug={projectSlug}
|
|
551
|
+
workflowRunId={run.id}
|
|
552
|
+
search={selection}
|
|
553
|
+
/>
|
|
554
|
+
<AnnotationJobFilter
|
|
555
|
+
jobs={run.jobs}
|
|
556
|
+
selectedJobId={selectedJob?.id}
|
|
557
|
+
onSelect={onSelectAnnotationJob}
|
|
558
|
+
/>
|
|
559
|
+
</PanelHeader>
|
|
560
|
+
<PanelBody className="gap-group p-panel">
|
|
561
|
+
<RunAnnotationList
|
|
562
|
+
// Remounting on a filter or run-attempt change resets the render window, so the next
|
|
563
|
+
// list never inherits a "show more" position from different data.
|
|
564
|
+
key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}
|
|
565
|
+
query={annotations.query}
|
|
566
|
+
entries={entries}
|
|
567
|
+
derivedAnnotations={derivedAnnotations}
|
|
568
|
+
workspaceSlug={workspaceSlug}
|
|
569
|
+
projectSlug={projectSlug}
|
|
570
|
+
workflowRunId={run.id}
|
|
571
|
+
runAttempt={run.runAttempt.attempt}
|
|
572
|
+
// A run with no annotations at all offers no filter to clear, whatever the URL says.
|
|
573
|
+
filtered={Boolean(
|
|
574
|
+
(severity || selectedJob || selection?.annotation) &&
|
|
575
|
+
((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations),
|
|
576
|
+
)}
|
|
577
|
+
filteredJobName={selectedJob?.displayName}
|
|
578
|
+
filteredSeverity={severity}
|
|
579
|
+
onClearFilters={onClearAnnotationFilters}
|
|
580
|
+
selectedAnnotationId={selection?.annotation}
|
|
581
|
+
/>
|
|
582
|
+
</PanelBody>
|
|
583
|
+
</Panel>
|
|
568
584
|
</div>
|
|
569
585
|
</section>
|
|
570
586
|
);
|
|
@@ -666,7 +682,7 @@ function RunWorkspaceNavSkeleton() {
|
|
|
666
682
|
return (
|
|
667
683
|
<aside
|
|
668
684
|
aria-label="Loading run navigation"
|
|
669
|
-
className="hidden w-240 shrink-0
|
|
685
|
+
className="hidden w-240 shrink-0 p-panel-compact min-[768px]:block"
|
|
670
686
|
>
|
|
671
687
|
<div className="flex flex-col gap-group">
|
|
672
688
|
<div className="h-32 rounded-4 bg-background-components-subtle" />
|
|
@@ -63,8 +63,8 @@ export function WorkflowSourceContent({
|
|
|
63
63
|
value={item.filename}
|
|
64
64
|
className={cn(
|
|
65
65
|
'min-h-full px-0 pb-0',
|
|
66
|
-
'[&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base
|
|
67
|
-
'[&_code]:!text-sm [&_code]:!text-foreground-
|
|
66
|
+
'[&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base',
|
|
67
|
+
'[&_code]:!text-sm [&_code]:!text-foreground-contrast-primary [&_.line]:!text-sm [&_.line]:before:!text-sm [&_.line]:before:!text-foreground-contrast-secondary',
|
|
68
68
|
)}
|
|
69
69
|
>
|
|
70
70
|
<CodeBlockContent
|