@shipfox/client-workflows 22.0.1 → 22.0.3
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.tsx +2 -2
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +31 -0
- package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
- package/dist/components/job-detail/agent-config-failure-callout.js +15 -0
- package/dist/components/job-detail/agent-config-failure-callout.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 +8 -0
- package/dist/components/job-detail/job-empty-states.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 +9 -15
- 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 +36 -39
- 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.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +9 -13
- package/dist/components/workflow-run-list/workflow-run-row.js.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.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +6 -0
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/job-detail/agent-config-failure-callout.stories.tsx +29 -0
- package/src/components/job-detail/agent-config-failure-callout.tsx +18 -0
- package/src/components/job-detail/job-empty-states.test.ts +21 -0
- package/src/components/job-detail/job-empty-states.tsx +10 -0
- package/src/components/workflow-run-list/workflow-run-list-content.tsx +4 -9
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +36 -39
- package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +5 -0
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-row.tsx +7 -10
- package/src/core/entities/step.ts +2 -0
- package/src/hooks/api/workflow-run-mapper.ts +4 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/client-workflows",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "22.0.
|
|
4
|
+
"version": "22.0.3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"date-fns": "^4.1.0",
|
|
30
30
|
"@shipfox/annotations-dto": "12.3.0",
|
|
31
31
|
"@shipfox/api-definitions-dto": "12.3.0",
|
|
32
|
-
"@shipfox/api-workflows-dto": "13.
|
|
32
|
+
"@shipfox/api-workflows-dto": "13.1.0",
|
|
33
33
|
"@shipfox/client-api": "6.0.1",
|
|
34
|
-
"@shipfox/client-logs": "22.0.
|
|
35
|
-
"@shipfox/client-projects": "22.0.
|
|
36
|
-
"@shipfox/client-shell": "22.0.
|
|
37
|
-
"@shipfox/client-triggers": "22.0.
|
|
38
|
-
"@shipfox/
|
|
39
|
-
"@shipfox/
|
|
34
|
+
"@shipfox/client-logs": "22.0.3",
|
|
35
|
+
"@shipfox/client-projects": "22.0.3",
|
|
36
|
+
"@shipfox/client-shell": "22.0.3",
|
|
37
|
+
"@shipfox/client-triggers": "22.0.3",
|
|
38
|
+
"@shipfox/client-ui": "22.0.3",
|
|
39
|
+
"@shipfox/react-ui": "2.2.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -83,6 +83,19 @@ const errorCases: Array<{
|
|
|
83
83
|
category: 'user',
|
|
84
84
|
},
|
|
85
85
|
},
|
|
86
|
+
{
|
|
87
|
+
label: 'Managed-only policy',
|
|
88
|
+
error: {
|
|
89
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
90
|
+
code: 'workspace-providers-disabled',
|
|
91
|
+
managedProviderId: 'shipfox',
|
|
92
|
+
exitCode: null,
|
|
93
|
+
signal: undefined,
|
|
94
|
+
reason: 'agent_config_invalid',
|
|
95
|
+
agentConfigIssue: 'provider_unsupported',
|
|
96
|
+
category: 'user',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
86
99
|
];
|
|
87
100
|
|
|
88
101
|
export const Playground: Story = {};
|
|
@@ -113,6 +126,22 @@ export const TestProviderUnsupported: Story = {
|
|
|
113
126
|
play: assertCallout('Choose a supported model provider', false),
|
|
114
127
|
};
|
|
115
128
|
|
|
129
|
+
export const TestManagedOnlyPolicy: Story = {
|
|
130
|
+
args: {
|
|
131
|
+
error: {
|
|
132
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
133
|
+
code: 'workspace-providers-disabled',
|
|
134
|
+
managedProviderId: 'shipfox',
|
|
135
|
+
exitCode: null,
|
|
136
|
+
signal: undefined,
|
|
137
|
+
reason: 'agent_config_invalid',
|
|
138
|
+
agentConfigIssue: 'provider_unsupported',
|
|
139
|
+
category: 'user',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
play: assertCallout('Use shipfox for this instance', false),
|
|
143
|
+
};
|
|
144
|
+
|
|
116
145
|
function makeError(agentConfigIssue: AgentConfigIssueValue): StepError {
|
|
117
146
|
return {
|
|
118
147
|
message: 'Agent configuration is invalid',
|
|
@@ -9,6 +9,8 @@ import {Button} from '@shipfox/react-ui/button';
|
|
|
9
9
|
import {Link} from '@tanstack/react-router';
|
|
10
10
|
import type {AgentStepConfig, StepError} from '#core/workflow-run.js';
|
|
11
11
|
|
|
12
|
+
const MANAGED_ONLY_PROVIDER_CODE = 'workspace-providers-disabled';
|
|
13
|
+
|
|
12
14
|
export function AgentConfigFailureCallout({
|
|
13
15
|
workspaceSlug,
|
|
14
16
|
config,
|
|
@@ -47,6 +49,15 @@ function agentConfigFailureCopy(
|
|
|
47
49
|
config: AgentStepConfig | null,
|
|
48
50
|
error: StepError | null,
|
|
49
51
|
): {title: string; description: string; showProviderCta: boolean} {
|
|
52
|
+
const managedOnlyProvider = managedOnlyProviderFromError(error);
|
|
53
|
+
if (managedOnlyProvider) {
|
|
54
|
+
return {
|
|
55
|
+
title: `Use ${managedOnlyProvider} for this instance`,
|
|
56
|
+
description: `This instance only supports provider \`${managedOnlyProvider}\`. Update this step to use \`${managedOnlyProvider}\`, or remove its provider field to use the managed default.`,
|
|
57
|
+
showProviderCta: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
const provider = configValue(config?.provider, 'the selected provider');
|
|
51
62
|
const model = configValue(config?.model, 'the selected model');
|
|
52
63
|
|
|
@@ -92,6 +103,13 @@ function agentConfigFailureCopy(
|
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
|
|
106
|
+
function managedOnlyProviderFromError(error: StepError | null): string | undefined {
|
|
107
|
+
if (error?.code !== MANAGED_ONLY_PROVIDER_CODE && error?.managedProviderId === undefined) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return error.managedProviderId ?? 'the managed provider';
|
|
111
|
+
}
|
|
112
|
+
|
|
95
113
|
function configValue(value: string | null | undefined, fallback: string): string {
|
|
96
114
|
return value ?? fallback;
|
|
97
115
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Step} from '#core/workflow-run.js';
|
|
1
2
|
import {
|
|
2
3
|
workflowJob,
|
|
3
4
|
workflowJobExecutionDto,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
jobSucceededSummary,
|
|
10
11
|
outputFailureDescriptionForExecution,
|
|
11
12
|
skippedJobDescription,
|
|
13
|
+
toSelectedAttemptError,
|
|
12
14
|
} from './job-empty-states.js';
|
|
13
15
|
|
|
14
16
|
describe('jobSucceededSummary', () => {
|
|
@@ -32,6 +34,25 @@ describe('jobSucceededSummary', () => {
|
|
|
32
34
|
});
|
|
33
35
|
});
|
|
34
36
|
|
|
37
|
+
describe('toSelectedAttemptError', () => {
|
|
38
|
+
test('preserves managed-provider metadata from a historical attempt', () => {
|
|
39
|
+
const error = toSelectedAttemptError({type: 'agent'} as Step, {
|
|
40
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
41
|
+
code: 'workspace-providers-disabled',
|
|
42
|
+
managedProviderId: 'shipfox',
|
|
43
|
+
reason: 'agent_config_invalid',
|
|
44
|
+
agentConfigIssue: 'provider_unsupported',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(error).toMatchObject({
|
|
48
|
+
code: 'workspace-providers-disabled',
|
|
49
|
+
managedProviderId: 'shipfox',
|
|
50
|
+
reason: 'agent_config_invalid',
|
|
51
|
+
agentConfigIssue: 'provider_unsupported',
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
35
56
|
describe('skippedJobDescription', () => {
|
|
36
57
|
test('explains when materialized output exceeds the configured size limit', () => {
|
|
37
58
|
expect(skippedJobDescription('output_too_large')).toBe(
|
|
@@ -292,8 +292,18 @@ export function toSelectedAttemptError(
|
|
|
292
292
|
|
|
293
293
|
if (resolvedReason === undefined) return null;
|
|
294
294
|
|
|
295
|
+
const code = typeof error.code === 'string' ? error.code : undefined;
|
|
296
|
+
const managedProviderId =
|
|
297
|
+
typeof error.managedProviderId === 'string'
|
|
298
|
+
? error.managedProviderId
|
|
299
|
+
: typeof error.managed_provider_id === 'string'
|
|
300
|
+
? error.managed_provider_id
|
|
301
|
+
: undefined;
|
|
302
|
+
|
|
295
303
|
return {
|
|
296
304
|
message: typeof error.message === 'string' ? error.message : '',
|
|
305
|
+
...(code === undefined ? {} : {code}),
|
|
306
|
+
...(managedProviderId === undefined ? {} : {managedProviderId}),
|
|
297
307
|
exitCode: exitCode === null || typeof exitCode === 'number' ? exitCode : null,
|
|
298
308
|
signal: typeof error.signal === 'string' ? error.signal : undefined,
|
|
299
309
|
reason: resolvedReason,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {QueryLoadError} from '@shipfox/client-ui';
|
|
2
|
-
import {Panel} from '@shipfox/react-ui/panel';
|
|
3
2
|
import type {WorkflowRunListItem} from '#core/workflow-run.js';
|
|
4
3
|
import type {WorkflowRunListQuery} from './types.js';
|
|
5
4
|
import {
|
|
@@ -53,18 +52,14 @@ export function WorkflowRunListContent({
|
|
|
53
52
|
const showNoMatches = hasLoaded && runs.length === 0 && !showEmptyState;
|
|
54
53
|
|
|
55
54
|
return (
|
|
56
|
-
|
|
55
|
+
<>
|
|
57
56
|
{isPending ? <WorkflowRunListSkeleton /> : null}
|
|
58
57
|
{!isPending ? (
|
|
59
|
-
<
|
|
60
|
-
<QueryLoadError query={query} subject="workflow runs" icon="pulseLine" variant="panel" />
|
|
61
|
-
</Panel>
|
|
58
|
+
<QueryLoadError query={query} subject="workflow runs" icon="pulseLine" variant="panel" />
|
|
62
59
|
) : null}
|
|
63
60
|
{!isPending && refreshFailed ? <WorkflowRunListStaleError query={query} /> : null}
|
|
64
61
|
{showEmptyState ? (
|
|
65
|
-
<
|
|
66
|
-
<WorkflowRunListEmpty workspaceSlug={workspaceSlug} projectSlug={projectSlug} />
|
|
67
|
-
</Panel>
|
|
62
|
+
<WorkflowRunListEmpty workspaceSlug={workspaceSlug} projectSlug={projectSlug} />
|
|
68
63
|
) : null}
|
|
69
64
|
{showNoMatches ? (
|
|
70
65
|
<WorkflowRunListNoMatches
|
|
@@ -86,6 +81,6 @@ export function WorkflowRunListContent({
|
|
|
86
81
|
/>
|
|
87
82
|
</>
|
|
88
83
|
) : null}
|
|
89
|
-
|
|
84
|
+
</>
|
|
90
85
|
);
|
|
91
86
|
}
|
|
@@ -2,7 +2,6 @@ import type {QueryLoadErrorQuery} from '@shipfox/client-ui';
|
|
|
2
2
|
import {Button} from '@shipfox/react-ui/button';
|
|
3
3
|
import {Callout} from '@shipfox/react-ui/callout';
|
|
4
4
|
import {EmptyState} from '@shipfox/react-ui/empty-state';
|
|
5
|
-
import {Panel} from '@shipfox/react-ui/panel';
|
|
6
5
|
import {Skeleton} from '@shipfox/react-ui/skeleton';
|
|
7
6
|
import {Text} from '@shipfox/react-ui/typography';
|
|
8
7
|
import {Link} from '@tanstack/react-router';
|
|
@@ -16,7 +15,7 @@ const SKELETON_ROW_COUNT = 8;
|
|
|
16
15
|
*/
|
|
17
16
|
export function WorkflowRunListSkeleton() {
|
|
18
17
|
return (
|
|
19
|
-
<
|
|
18
|
+
<div role="status" aria-label="Loading runs" className="@container divide-y">
|
|
20
19
|
{Array.from({length: SKELETON_ROW_COUNT}).map((_, index) => (
|
|
21
20
|
<div
|
|
22
21
|
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton row, stable position
|
|
@@ -30,7 +29,7 @@ export function WorkflowRunListSkeleton() {
|
|
|
30
29
|
<Skeleton className="h-12 w-48" />
|
|
31
30
|
</div>
|
|
32
31
|
))}
|
|
33
|
-
</
|
|
32
|
+
</div>
|
|
34
33
|
);
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -114,43 +113,41 @@ export function WorkflowRunListNoMatches({
|
|
|
114
113
|
onLoadMore?: () => void;
|
|
115
114
|
}) {
|
|
116
115
|
return (
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Load more runs
|
|
143
|
-
</Button>
|
|
144
|
-
) : null}
|
|
145
|
-
<Button type="button" size="sm" variant="secondary" onClick={onClear}>
|
|
146
|
-
Show all runs
|
|
116
|
+
<div className="flex flex-col gap-inline">
|
|
117
|
+
{isFetchNextPageError ? (
|
|
118
|
+
<Callout role="alert" type="error">
|
|
119
|
+
Could not load more workflow runs. Try again to continue searching older runs.
|
|
120
|
+
</Callout>
|
|
121
|
+
) : null}
|
|
122
|
+
<EmptyState
|
|
123
|
+
icon="filterOffLine"
|
|
124
|
+
title={hasNextPage ? 'No matches in loaded history' : 'No matching runs'}
|
|
125
|
+
description={
|
|
126
|
+
hasNextPage
|
|
127
|
+
? 'No loaded run matches these filters. Load more to search further back.'
|
|
128
|
+
: 'No run matches these filters.'
|
|
129
|
+
}
|
|
130
|
+
action={
|
|
131
|
+
<div className="flex flex-wrap justify-center gap-inline">
|
|
132
|
+
{hasNextPage && onLoadMore ? (
|
|
133
|
+
<Button
|
|
134
|
+
type="button"
|
|
135
|
+
size="sm"
|
|
136
|
+
variant="primary"
|
|
137
|
+
isLoading={isFetchingNextPage}
|
|
138
|
+
onClick={onLoadMore}
|
|
139
|
+
>
|
|
140
|
+
Load more runs
|
|
147
141
|
</Button>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
142
|
+
) : null}
|
|
143
|
+
<Button type="button" size="sm" variant="secondary" onClick={onClear}>
|
|
144
|
+
Show all runs
|
|
145
|
+
</Button>
|
|
146
|
+
</div>
|
|
147
|
+
}
|
|
148
|
+
variant="panel"
|
|
149
|
+
/>
|
|
150
|
+
</div>
|
|
154
151
|
);
|
|
155
152
|
}
|
|
156
153
|
|
|
@@ -48,6 +48,7 @@ describe('WorkflowRunListView', () => {
|
|
|
48
48
|
const body = panel?.querySelector<HTMLElement>('[data-slot="panel-body"]');
|
|
49
49
|
|
|
50
50
|
expect(panel).not.toBeNull();
|
|
51
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(1);
|
|
51
52
|
expect(header).not.toBeNull();
|
|
52
53
|
expect(body).not.toBeNull();
|
|
53
54
|
expect(within(header as HTMLElement).getByLabelText('Search runs')).toBeInTheDocument();
|
|
@@ -204,6 +205,7 @@ describe('WorkflowRunListView', () => {
|
|
|
204
205
|
renderListView([], {query: loadedQuery({isPending: true, data: undefined})});
|
|
205
206
|
|
|
206
207
|
expect(await screen.findByLabelText('Loading runs')).toBeInTheDocument();
|
|
208
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(1);
|
|
207
209
|
expect(screen.queryByText('No runs yet')).not.toBeInTheDocument();
|
|
208
210
|
});
|
|
209
211
|
|
|
@@ -217,6 +219,7 @@ describe('WorkflowRunListView', () => {
|
|
|
217
219
|
renderListView([]);
|
|
218
220
|
|
|
219
221
|
expect(await screen.findByText('No runs yet')).toBeInTheDocument();
|
|
222
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(1);
|
|
220
223
|
expect(screen.getByRole('link', {name: 'View workflows'})).toBeInTheDocument();
|
|
221
224
|
expect(screen.queryByRole('button', {name: 'Show all runs'})).not.toBeInTheDocument();
|
|
222
225
|
});
|
|
@@ -228,6 +231,7 @@ describe('WorkflowRunListView', () => {
|
|
|
228
231
|
await user.type(await screen.findByLabelText('Search runs'), 'no-such-run');
|
|
229
232
|
|
|
230
233
|
expect(screen.getByText('No matching runs')).toBeInTheDocument();
|
|
234
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(1);
|
|
231
235
|
expect(screen.queryByText('No runs yet')).not.toBeInTheDocument();
|
|
232
236
|
expect(screen.getByRole('button', {name: 'Show all runs'})).toBeInTheDocument();
|
|
233
237
|
});
|
|
@@ -248,6 +252,7 @@ describe('WorkflowRunListView', () => {
|
|
|
248
252
|
});
|
|
249
253
|
|
|
250
254
|
expect(await screen.findByLabelText('Search runs')).toBeInTheDocument();
|
|
255
|
+
expect(document.querySelectorAll('[data-slot="panel"]')).toHaveLength(1);
|
|
251
256
|
expect(screen.queryByText('No runs yet')).not.toBeInTheDocument();
|
|
252
257
|
expect(screen.queryByText('No matching runs')).not.toBeInTheDocument();
|
|
253
258
|
});
|
|
@@ -77,7 +77,7 @@ export function WorkflowRunListView({
|
|
|
77
77
|
hasActiveFilters={hasActiveFilters}
|
|
78
78
|
/>
|
|
79
79
|
</PanelHeader>
|
|
80
|
-
<PanelBody className="min-h-0 flex-1">
|
|
80
|
+
<PanelBody className="min-h-0 flex-1 overflow-y-auto">
|
|
81
81
|
<WorkflowRunListContent
|
|
82
82
|
query={query}
|
|
83
83
|
totalRuns={runs.length}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {TriggerSourceIcon} from '@shipfox/client-triggers';
|
|
2
2
|
import {Icon, type IconName} from '@shipfox/react-ui/icon';
|
|
3
|
-
import {Panel} from '@shipfox/react-ui/panel';
|
|
4
3
|
import {RelativeTime} from '@shipfox/react-ui/relative-time';
|
|
5
4
|
import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';
|
|
6
5
|
import {Code, Text} from '@shipfox/react-ui/typography';
|
|
@@ -38,15 +37,13 @@ export function WorkflowRunRowList({
|
|
|
38
37
|
// A container, not the viewport, drives the row's breakpoints. What a row can afford is its
|
|
39
38
|
// own width; keying off the viewport would keep the job strip hidden on a wide screen or
|
|
40
39
|
// crush it on a narrow one.
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</ul>
|
|
49
|
-
</Panel>
|
|
40
|
+
<ul className="@container divide-y divide-border-neutral-base">
|
|
41
|
+
{runs.map((run) => (
|
|
42
|
+
<li key={run.id}>
|
|
43
|
+
<WorkflowRunRow run={run} workspaceSlug={workspaceSlug} projectSlug={projectSlug} />
|
|
44
|
+
</li>
|
|
45
|
+
))}
|
|
46
|
+
</ul>
|
|
50
47
|
);
|
|
51
48
|
}
|
|
52
49
|
|
|
@@ -51,6 +51,8 @@ export interface StepSourceLocation {
|
|
|
51
51
|
|
|
52
52
|
export interface StepError {
|
|
53
53
|
message: string;
|
|
54
|
+
code?: string | undefined;
|
|
55
|
+
managedProviderId?: string | undefined;
|
|
54
56
|
exitCode: number | null;
|
|
55
57
|
signal: string | undefined;
|
|
56
58
|
reason: StepErrorReason | undefined;
|
|
@@ -217,6 +217,10 @@ export function toStep(dto: WorkflowRunStepDetailDto): Step {
|
|
|
217
217
|
error: dto.error
|
|
218
218
|
? {
|
|
219
219
|
message: dto.error.message,
|
|
220
|
+
...(dto.error.code === undefined ? {} : {code: dto.error.code}),
|
|
221
|
+
...(dto.error.managed_provider_id === undefined
|
|
222
|
+
? {}
|
|
223
|
+
: {managedProviderId: dto.error.managed_provider_id}),
|
|
220
224
|
exitCode: dto.error.exit_code ?? null,
|
|
221
225
|
signal: dto.error.signal,
|
|
222
226
|
reason: dto.error.reason,
|