@shipfox/client-workflows 16.0.0 → 18.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 +32 -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 +228 -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 +100 -57
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/job-empty-states.d.ts +4 -0
- package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
- package/dist/components/job-detail/job-empty-states.js +60 -11
- 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 +497 -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 +6 -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.d.ts.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +11 -10
- 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 +9 -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 +10 -1
- 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 +48 -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 +241 -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 +105 -59
- package/src/components/job-detail/job-empty-states.test.ts +105 -1
- package/src/components/job-detail/job-empty-states.tsx +77 -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 +541 -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 +6 -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 +18 -11
- 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 +9 -0
- package/src/core/entities/job.ts +12 -1
- 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 +47 -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
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export {RunAnnotationCountChip} from './run-annotation-count-chip.js';
|
|
2
2
|
export {annotationElementId, RunAnnotationItem} from './run-annotation-item.js';
|
|
3
|
-
export {
|
|
3
|
+
export {
|
|
4
|
+
type DerivedRunAnnotation,
|
|
5
|
+
RunAnnotationList,
|
|
6
|
+
type RunAnnotationListQuery,
|
|
7
|
+
} from './run-annotation-list.js';
|
|
4
8
|
export {RunAnnotationSummaryLine} from './run-annotation-summary-line.js';
|
|
5
9
|
export {RunAnnotationsEmpty} from './run-annotations-empty.js';
|
|
@@ -45,10 +45,10 @@ export function RunAnnotationCountChip({
|
|
|
45
45
|
search={workflowRunSearchParams(search, search) as never}
|
|
46
46
|
aria-label={accessibleLabel}
|
|
47
47
|
className={cn(
|
|
48
|
-
'inline-flex h-20 shrink-0 items-center gap-
|
|
48
|
+
'inline-flex h-20 shrink-0 items-center gap-tight rounded-4 border px-tight font-code text-xs leading-16 tabular-nums outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active',
|
|
49
49
|
// The chip stays 20px optically so it sits level with the duration metadata beside it;
|
|
50
50
|
// the hit area grows to the 44px minimum only where the pointer is coarse.
|
|
51
|
-
'[@media(pointer:coarse)]:h-44 [@media(pointer:coarse)]:px-
|
|
51
|
+
'[@media(pointer:coarse)]:h-44 [@media(pointer:coarse)]:px-[10px]',
|
|
52
52
|
severity ? SEVERITY_CHIP_TONE[severity] : 'border-border-neutral-base',
|
|
53
53
|
)}
|
|
54
54
|
>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {QueryLoadError, type QueryLoadErrorQuery} from '@shipfox/client-ui';
|
|
1
|
+
import {AnnotationCard, QueryLoadError, 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
5
|
import {Skeleton} from '@shipfox/react-ui/skeleton';
|
|
6
6
|
import {Text} from '@shipfox/react-ui/typography';
|
|
7
7
|
import {useState} from 'react';
|
|
8
|
-
import type {RunAnnotationEntry} from '#core/run-annotation.js';
|
|
8
|
+
import type {RunAnnotationEntry, RunAnnotationStyle} from '#core/run-annotation.js';
|
|
9
9
|
import {RunAnnotationItem} from './run-annotation-item.js';
|
|
10
10
|
import {RunAnnotationsEmpty} from './run-annotations-empty.js';
|
|
11
11
|
|
|
@@ -19,6 +19,8 @@ export interface RunAnnotationListQuery extends QueryLoadErrorQuery {
|
|
|
19
19
|
export interface RunAnnotationListProps {
|
|
20
20
|
query: RunAnnotationListQuery;
|
|
21
21
|
entries: RunAnnotationEntry[] | undefined;
|
|
22
|
+
/** Synthetic terminal-job diagnostics for jobs that never created an execution record. */
|
|
23
|
+
derivedAnnotations?: readonly DerivedRunAnnotation[] | undefined;
|
|
22
24
|
workflowRunId: string;
|
|
23
25
|
workspaceSlug?: string | undefined;
|
|
24
26
|
projectSlug?: string | undefined;
|
|
@@ -33,6 +35,12 @@ export interface RunAnnotationListProps {
|
|
|
33
35
|
selectedAnnotationId?: string | undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
export interface DerivedRunAnnotation {
|
|
39
|
+
id: string;
|
|
40
|
+
style: RunAnnotationStyle;
|
|
41
|
+
body: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
/**
|
|
37
45
|
* How many annotations render at once.
|
|
38
46
|
*
|
|
@@ -51,6 +59,7 @@ const RENDER_WINDOW = 25;
|
|
|
51
59
|
export function RunAnnotationList({
|
|
52
60
|
query,
|
|
53
61
|
entries,
|
|
62
|
+
derivedAnnotations = [],
|
|
54
63
|
workflowRunId,
|
|
55
64
|
workspaceSlug,
|
|
56
65
|
projectSlug,
|
|
@@ -80,12 +89,13 @@ export function RunAnnotationList({
|
|
|
80
89
|
|
|
81
90
|
const visible = entries.slice(0, renderCount);
|
|
82
91
|
const hiddenCount = entries.length - visible.length;
|
|
92
|
+
const hasContent = entries.length > 0 || derivedAnnotations.length > 0;
|
|
83
93
|
|
|
84
94
|
return (
|
|
85
|
-
<div className="flex min-w-0 flex-col gap-
|
|
95
|
+
<div className="flex min-w-0 flex-col gap-cluster">
|
|
86
96
|
{query.isError ? <RunAnnotationStaleError query={query} /> : null}
|
|
87
97
|
|
|
88
|
-
{
|
|
98
|
+
{!hasContent ? (
|
|
89
99
|
filtered ? (
|
|
90
100
|
<RunAnnotationsFilteredEmpty
|
|
91
101
|
jobName={filteredJobName}
|
|
@@ -97,7 +107,7 @@ export function RunAnnotationList({
|
|
|
97
107
|
<RunAnnotationsEmpty />
|
|
98
108
|
)
|
|
99
109
|
) : (
|
|
100
|
-
<ol className="flex min-w-0 flex-col gap-
|
|
110
|
+
<ol className="flex min-w-0 flex-col gap-cluster">
|
|
101
111
|
{visible.map((entry) => (
|
|
102
112
|
<RunAnnotationItem
|
|
103
113
|
key={entry.annotation.id}
|
|
@@ -109,6 +119,11 @@ export function RunAnnotationList({
|
|
|
109
119
|
selected={entry.annotation.id === selectedAnnotationId}
|
|
110
120
|
/>
|
|
111
121
|
))}
|
|
122
|
+
{derivedAnnotations.map((annotation) => (
|
|
123
|
+
<li key={annotation.id}>
|
|
124
|
+
<AnnotationCard style={annotation.style} body={annotation.body} />
|
|
125
|
+
</li>
|
|
126
|
+
))}
|
|
112
127
|
</ol>
|
|
113
128
|
)}
|
|
114
129
|
|
|
@@ -187,7 +202,7 @@ function RunAnnotationsFilteredEmpty({
|
|
|
187
202
|
onClearFilters: (() => void) | undefined;
|
|
188
203
|
}) {
|
|
189
204
|
return (
|
|
190
|
-
<div className="flex flex-col items-center gap-
|
|
205
|
+
<div className="flex flex-col items-center gap-cluster">
|
|
191
206
|
<EmptyState
|
|
192
207
|
icon="fileDamageLine"
|
|
193
208
|
title={incomplete ? 'No matches in loaded annotations' : 'No matching annotations'}
|
|
@@ -216,7 +231,7 @@ function RunAnnotationsFilteredEmpty({
|
|
|
216
231
|
function RunAnnotationStaleError({query}: {query: QueryLoadErrorQuery}) {
|
|
217
232
|
return (
|
|
218
233
|
<Callout role="status" aria-live="polite" type="error">
|
|
219
|
-
<div className="flex w-full items-center justify-between gap-
|
|
234
|
+
<div className="flex w-full items-center justify-between gap-inline">
|
|
220
235
|
<Text size="xs">Could not refresh annotations.</Text>
|
|
221
236
|
<Button
|
|
222
237
|
type="button"
|
|
@@ -239,14 +254,14 @@ const ANNOTATION_SKELETON_ROWS = ['first', 'second', 'third'];
|
|
|
239
254
|
|
|
240
255
|
function RunAnnotationListSkeleton() {
|
|
241
256
|
return (
|
|
242
|
-
<section aria-label="Loading annotations" className="flex flex-col gap-
|
|
257
|
+
<section aria-label="Loading annotations" className="flex flex-col gap-cluster">
|
|
243
258
|
{ANNOTATION_SKELETON_ROWS.map((row) => (
|
|
244
259
|
<div
|
|
245
260
|
key={row}
|
|
246
|
-
className="flex gap-
|
|
261
|
+
className="flex gap-cluster rounded-8 border border-border-neutral-base bg-background-components-base px-[12px] py-[8px]"
|
|
247
262
|
>
|
|
248
263
|
<Skeleton className="h-40 w-4 rounded-full" />
|
|
249
|
-
<div className="flex min-w-0 flex-1 flex-col gap-
|
|
264
|
+
<div className="flex min-w-0 flex-1 flex-col gap-inline">
|
|
250
265
|
<Skeleton className="h-20 w-160 rounded-4" />
|
|
251
266
|
<Skeleton className="h-16 w-240 rounded-4" />
|
|
252
267
|
<Skeleton className="h-40 w-full rounded-4" />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {MetadataSeparator} from '@shipfox/client-ui';
|
|
1
2
|
import {Icon} from '@shipfox/react-ui/icon';
|
|
2
3
|
import {Text} from '@shipfox/react-ui/typography';
|
|
3
4
|
import {cn} from '@shipfox/react-ui/utils';
|
|
@@ -8,7 +9,6 @@ import {
|
|
|
8
9
|
type WorkflowRunsSearch,
|
|
9
10
|
workflowRunSearchParams,
|
|
10
11
|
} from '#routes/inputs.js';
|
|
11
|
-
import {MetadataSeparator} from '../workflow-run-summary/workflow-run-summary.js';
|
|
12
12
|
import {SEVERITY_ICON, SEVERITY_ICON_TONE} from './severity-visuals.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -48,7 +48,7 @@ export function RunAnnotationSummaryLine({
|
|
|
48
48
|
const totalLabel = countLabel(summary.total, 'annotation', summary.truncated);
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
|
-
<div className="flex flex-wrap items-center gap-x-
|
|
51
|
+
<div className="flex flex-wrap items-center gap-x-inline gap-y-tight text-foreground-neutral-subtle">
|
|
52
52
|
{search.severity && workspaceSlug && projectSlug && workflowRunId ? (
|
|
53
53
|
// The severity filter has no control of its own, so while one is active the total is
|
|
54
54
|
// the way back out. Unfiltered it stays plain text: a link to where you already are
|
|
@@ -77,7 +77,7 @@ export function RunAnnotationSummaryLine({
|
|
|
77
77
|
</Text>
|
|
78
78
|
)}
|
|
79
79
|
{visibleSeverities.map((severity) => (
|
|
80
|
-
<span key={severity} className="inline-flex shrink-0 items-center gap-
|
|
80
|
+
<span key={severity} className="inline-flex shrink-0 items-center gap-inline">
|
|
81
81
|
<MetadataSeparator />
|
|
82
82
|
<SeverityLink
|
|
83
83
|
count={summary[severity]}
|
|
@@ -127,7 +127,7 @@ function SeverityLink({
|
|
|
127
127
|
);
|
|
128
128
|
|
|
129
129
|
if (!workspaceSlug || !projectSlug || !workflowRunId) {
|
|
130
|
-
return <span className="inline-flex items-center gap-
|
|
130
|
+
return <span className="inline-flex items-center gap-tight">{content}</span>;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
const searchWithoutAnnotation = withoutAnnotation(search);
|
|
@@ -142,7 +142,7 @@ function SeverityLink({
|
|
|
142
142
|
search,
|
|
143
143
|
) as never
|
|
144
144
|
}
|
|
145
|
-
className="inline-flex items-center gap-
|
|
145
|
+
className="inline-flex items-center gap-tight rounded-4 outline-none hover:underline focus-visible:shadow-border-interactive-with-active"
|
|
146
146
|
>
|
|
147
147
|
{content}
|
|
148
148
|
</Link>
|
|
@@ -53,12 +53,16 @@ export function RunWorkspaceNav({
|
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
55
|
<TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>
|
|
56
|
-
<aside className="w-full shrink-0 border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r">
|
|
57
|
-
<Collapsible
|
|
56
|
+
<aside className="flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r">
|
|
57
|
+
<Collapsible
|
|
58
|
+
open={mobileOpen}
|
|
59
|
+
onOpenChange={setMobileOpen}
|
|
60
|
+
className="flex min-h-0 flex-col min-[768px]:flex-1"
|
|
61
|
+
>
|
|
58
62
|
<CollapsibleTrigger asChild>
|
|
59
63
|
<button
|
|
60
64
|
type="button"
|
|
61
|
-
className="flex min-h-44 w-full items-center justify-between gap-
|
|
65
|
+
className="flex min-h-44 w-full items-center justify-between gap-cluster px-row text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden"
|
|
62
66
|
aria-label="Toggle run navigation"
|
|
63
67
|
>
|
|
64
68
|
<span className="min-w-0">
|
|
@@ -82,7 +86,7 @@ export function RunWorkspaceNav({
|
|
|
82
86
|
</CollapsibleTrigger>
|
|
83
87
|
<div
|
|
84
88
|
className={cn(
|
|
85
|
-
'max-h-[50vh] overflow-y-auto p-
|
|
89
|
+
'flex min-h-0 max-h-[50vh] flex-col overflow-y-auto p-tight scrollbar min-[768px]:min-h-0 min-[768px]:max-h-none min-[768px]:flex-1 min-[768px]:flex min-[768px]:overflow-hidden min-[768px]:p-[12px]',
|
|
86
90
|
!mobileOpen && 'hidden',
|
|
87
91
|
)}
|
|
88
92
|
>
|
|
@@ -136,7 +140,7 @@ function RunWorkspaceNavContent({
|
|
|
136
140
|
}, [currentJobId, mobileOpen]);
|
|
137
141
|
|
|
138
142
|
return (
|
|
139
|
-
<nav aria-label="Run workspace" className="flex min-w-0 flex-col gap-
|
|
143
|
+
<nav aria-label="Run workspace" className="flex min-h-0 min-w-0 flex-1 flex-col gap-group">
|
|
140
144
|
<ul>
|
|
141
145
|
<li>
|
|
142
146
|
<RunSectionLink
|
|
@@ -151,8 +155,11 @@ function RunWorkspaceNavContent({
|
|
|
151
155
|
</li>
|
|
152
156
|
</ul>
|
|
153
157
|
|
|
154
|
-
<section
|
|
155
|
-
|
|
158
|
+
<section
|
|
159
|
+
aria-labelledby="run-workspace-jobs-heading"
|
|
160
|
+
className="flex min-h-0 min-w-0 flex-1 flex-col"
|
|
161
|
+
>
|
|
162
|
+
<div className="flex items-center justify-between gap-inline px-tight pb-[6px]">
|
|
156
163
|
<Text
|
|
157
164
|
as="h2"
|
|
158
165
|
id="run-workspace-jobs-heading"
|
|
@@ -166,7 +173,7 @@ function RunWorkspaceNavContent({
|
|
|
166
173
|
{jobs.length}
|
|
167
174
|
</Text>
|
|
168
175
|
</div>
|
|
169
|
-
<ol className="
|
|
176
|
+
<ol className="min-h-0 flex-1 overflow-y-auto scrollbar">
|
|
170
177
|
{jobs.map((job) => {
|
|
171
178
|
const current = job.id === currentJobId;
|
|
172
179
|
const execution = defaultJobExecution(job);
|
|
@@ -182,7 +189,7 @@ function RunWorkspaceNavContent({
|
|
|
182
189
|
onClick={onNavigate}
|
|
183
190
|
aria-current={current ? 'page' : undefined}
|
|
184
191
|
className={cn(
|
|
185
|
-
'flex min-h-32 min-w-0 items-center gap-
|
|
192
|
+
'flex min-h-32 min-w-0 items-center gap-inline rounded-4 px-tight text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',
|
|
186
193
|
current && 'bg-background-neutral-hover',
|
|
187
194
|
)}
|
|
188
195
|
>
|
|
@@ -210,7 +217,7 @@ function RunWorkspaceNavContent({
|
|
|
210
217
|
id="run-workspace-details-heading"
|
|
211
218
|
size="xs"
|
|
212
219
|
bold
|
|
213
|
-
className="px-
|
|
220
|
+
className="px-tight pb-[6px] text-foreground-neutral-muted"
|
|
214
221
|
>
|
|
215
222
|
Run details
|
|
216
223
|
</Text>
|
|
@@ -285,7 +292,7 @@ function RunSectionLink({
|
|
|
285
292
|
: undefined
|
|
286
293
|
}
|
|
287
294
|
className={cn(
|
|
288
|
-
'flex min-h-32 items-center gap-
|
|
295
|
+
'flex min-h-32 items-center gap-inline rounded-4 px-tight text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',
|
|
289
296
|
current && 'bg-background-neutral-hover',
|
|
290
297
|
)}
|
|
291
298
|
>
|
|
@@ -9,10 +9,10 @@ export function WorkflowRunSkeleton() {
|
|
|
9
9
|
return (
|
|
10
10
|
<section
|
|
11
11
|
aria-label="Loading workflow run"
|
|
12
|
-
className="bg-background-neutral-background px-
|
|
12
|
+
className="bg-background-neutral-background px-row py-row"
|
|
13
13
|
>
|
|
14
|
-
<div className="flex min-w-0 flex-wrap items-center gap-x-
|
|
15
|
-
<div className="flex min-w-0 items-center gap-
|
|
14
|
+
<div className="flex min-w-0 flex-wrap items-center gap-x-cluster gap-y-inline">
|
|
15
|
+
<div className="flex min-w-0 items-center gap-inline">
|
|
16
16
|
<Skeleton className="size-8 rounded-full" />
|
|
17
17
|
<Skeleton className="h-24 w-180 rounded-6" />
|
|
18
18
|
</div>
|
|
@@ -35,7 +35,7 @@ export function WorkflowRunContentSkeleton() {
|
|
|
35
35
|
return (
|
|
36
36
|
<section
|
|
37
37
|
aria-label="Loading workflow run content"
|
|
38
|
-
className="min-h-160 rounded-8 border border-border-neutral-base bg-background-components-base p-
|
|
38
|
+
className="min-h-160 rounded-8 border border-border-neutral-base bg-background-components-base p-panel-compact"
|
|
39
39
|
>
|
|
40
40
|
<Skeleton className="h-160 w-full rounded-6" />
|
|
41
41
|
</section>
|
|
@@ -59,9 +59,9 @@ export function WorkflowRunNotFound() {
|
|
|
59
59
|
*/
|
|
60
60
|
export function WorkflowRunStaleError({query}: {query: QueryLoadErrorQuery}) {
|
|
61
61
|
return (
|
|
62
|
-
<div className="border-b border-border-neutral-base p-
|
|
62
|
+
<div className="border-b border-border-neutral-base p-tight">
|
|
63
63
|
<Callout role="alert" type="error">
|
|
64
|
-
<div className="flex items-center justify-between gap-
|
|
64
|
+
<div className="flex items-center justify-between gap-inline">
|
|
65
65
|
<Text size="xs">Could not refresh this run.</Text>
|
|
66
66
|
<Button
|
|
67
67
|
type="button"
|
|
@@ -14,7 +14,12 @@ import {Text} from '@shipfox/react-ui/typography';
|
|
|
14
14
|
import {useNavigate} from '@tanstack/react-router';
|
|
15
15
|
import {type ReactNode, useEffect, useMemo} from 'react';
|
|
16
16
|
import {buildRunAnnotationList, type RunAnnotationSummary} from '#core/run-annotation.js';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
type EvaluationTraceEntry,
|
|
19
|
+
isWorkflowRunTerminal,
|
|
20
|
+
type Job,
|
|
21
|
+
type WorkflowRunRerunMode,
|
|
22
|
+
} from '#core/workflow-run.js';
|
|
18
23
|
import {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';
|
|
19
24
|
import {useRunAnnotationsQuery} from '#hooks/api/run-annotations.js';
|
|
20
25
|
import {
|
|
@@ -32,7 +37,11 @@ import {
|
|
|
32
37
|
import {JobGraph} from '../job-graph/index.js';
|
|
33
38
|
import type {JobGraphSelectionSource} from '../job-graph/types.js';
|
|
34
39
|
import {WorkflowRunSummary} from '../workflow-run-summary/index.js';
|
|
35
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
type DerivedRunAnnotation,
|
|
42
|
+
RunAnnotationList,
|
|
43
|
+
RunAnnotationSummaryLine,
|
|
44
|
+
} from '../workflow-run-tabs/index.js';
|
|
36
45
|
import {WorkflowSourceContent} from '../workflow-source-panel/index.js';
|
|
37
46
|
import {RunWorkspaceNav} from './run-workspace-nav.js';
|
|
38
47
|
import {resolveWorkflowRunSelection} from './workflow-run-selection.js';
|
|
@@ -339,7 +348,7 @@ function RunViewContent({
|
|
|
339
348
|
highlightedLineRange={highlightedLineRange}
|
|
340
349
|
/>
|
|
341
350
|
) : (
|
|
342
|
-
<div className="min-h-0 flex-1 overflow-auto p-
|
|
351
|
+
<div className="min-h-0 flex-1 overflow-auto p-panel">{loadingOrError}</div>
|
|
343
352
|
)}
|
|
344
353
|
</div>
|
|
345
354
|
</div>
|
|
@@ -382,8 +391,11 @@ function RunSectionContent({
|
|
|
382
391
|
}) {
|
|
383
392
|
if (section === 'summary') {
|
|
384
393
|
return (
|
|
385
|
-
<section
|
|
386
|
-
|
|
394
|
+
<section
|
|
395
|
+
aria-label="All jobs summary"
|
|
396
|
+
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
397
|
+
>
|
|
398
|
+
<div className="mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame">
|
|
387
399
|
<Text as="h2" className="sr-only">
|
|
388
400
|
All jobs summary
|
|
389
401
|
</Text>
|
|
@@ -415,8 +427,11 @@ function RunSectionContent({
|
|
|
415
427
|
}
|
|
416
428
|
|
|
417
429
|
return (
|
|
418
|
-
<section
|
|
419
|
-
|
|
430
|
+
<section
|
|
431
|
+
aria-label="Workflow source"
|
|
432
|
+
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
433
|
+
>
|
|
434
|
+
<div className="mx-auto flex min-h-full w-full max-w-[1120px] flex-col px-frame">
|
|
420
435
|
<Text as="h2" className="sr-only">
|
|
421
436
|
Workflow source
|
|
422
437
|
</Text>
|
|
@@ -480,14 +495,42 @@ function RunAnnotationsSection({
|
|
|
480
495
|
: undefined,
|
|
481
496
|
[records, run.jobs, selectedJob?.id, severity],
|
|
482
497
|
);
|
|
498
|
+
const derivedAnnotations = useMemo<readonly DerivedRunAnnotation[] | undefined>(() => {
|
|
499
|
+
if (!records) return undefined;
|
|
500
|
+
const jobsWithAnnotations = new Set(records.map((annotation) => annotation.jobId));
|
|
501
|
+
|
|
502
|
+
return run.jobs
|
|
503
|
+
.filter((job) => {
|
|
504
|
+
const style = job.status === 'failed' ? 'error' : 'warning';
|
|
505
|
+
return (
|
|
506
|
+
(!selectedJob || selectedJob.id === job.id) &&
|
|
507
|
+
!jobsWithAnnotations.has(job.id) &&
|
|
508
|
+
(job.status === 'failed' || job.status === 'skipped') &&
|
|
509
|
+
job.jobExecutions.length === 0 &&
|
|
510
|
+
matchesDerivedAnnotationFilters(style, selection)
|
|
511
|
+
);
|
|
512
|
+
})
|
|
513
|
+
.map((job) => ({
|
|
514
|
+
id: `derived-${job.id}`,
|
|
515
|
+
style: job.status === 'failed' ? 'error' : 'warning',
|
|
516
|
+
body: derivedJobAnnotation(job),
|
|
517
|
+
}));
|
|
518
|
+
}, [records, run.jobs, selectedJob, selection]);
|
|
519
|
+
const hasSynthesizedJobAnnotations = run.jobs.some(
|
|
520
|
+
(job) =>
|
|
521
|
+
(job.status === 'failed' || job.status === 'skipped') && job.jobExecutions.length === 0,
|
|
522
|
+
);
|
|
483
523
|
|
|
484
524
|
return (
|
|
485
|
-
<section
|
|
486
|
-
|
|
525
|
+
<section
|
|
526
|
+
aria-label="Run annotations"
|
|
527
|
+
className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
|
|
528
|
+
>
|
|
529
|
+
<div className="mx-auto flex w-full max-w-[1120px] flex-col gap-group px-frame">
|
|
487
530
|
<Text as="h2" className="sr-only">
|
|
488
531
|
Annotations
|
|
489
532
|
</Text>
|
|
490
|
-
<div className="flex flex-wrap items-center justify-between gap-
|
|
533
|
+
<div className="flex flex-wrap items-center justify-between gap-inline">
|
|
491
534
|
<RunAnnotationSummaryLine
|
|
492
535
|
summary={annotationSummary}
|
|
493
536
|
workspaceSlug={workspaceSlug}
|
|
@@ -507,12 +550,16 @@ function RunAnnotationsSection({
|
|
|
507
550
|
key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}
|
|
508
551
|
query={annotations.query}
|
|
509
552
|
entries={entries}
|
|
553
|
+
derivedAnnotations={derivedAnnotations}
|
|
510
554
|
workspaceSlug={workspaceSlug}
|
|
511
555
|
projectSlug={projectSlug}
|
|
512
556
|
workflowRunId={run.id}
|
|
513
557
|
runAttempt={run.runAttempt.attempt}
|
|
514
558
|
// A run with no annotations at all offers no filter to clear, whatever the URL says.
|
|
515
|
-
filtered={Boolean(
|
|
559
|
+
filtered={Boolean(
|
|
560
|
+
(severity || selectedJob || selection?.annotation) &&
|
|
561
|
+
((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations),
|
|
562
|
+
)}
|
|
516
563
|
filteredJobName={selectedJob?.displayName}
|
|
517
564
|
filteredSeverity={severity}
|
|
518
565
|
onClearFilters={onClearAnnotationFilters}
|
|
@@ -523,6 +570,59 @@ function RunAnnotationsSection({
|
|
|
523
570
|
);
|
|
524
571
|
}
|
|
525
572
|
|
|
573
|
+
function matchesDerivedAnnotationFilters(
|
|
574
|
+
style: 'warning' | 'error',
|
|
575
|
+
selection: WorkflowRunsSearch | undefined,
|
|
576
|
+
): boolean {
|
|
577
|
+
if (selection?.severity && style !== selection.severity) return false;
|
|
578
|
+
// A selected annotation is a deep-link to a real annotation record. Synthetic diagnostics
|
|
579
|
+
// have no id or context, so they must not remain visible behind that selection.
|
|
580
|
+
return !selection?.annotation;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function derivedJobAnnotation(job: Job): string {
|
|
584
|
+
const reason = job.statusReason ? `Reason: \`${job.statusReason}\`` : null;
|
|
585
|
+
const traceSummary = formatConditionEvaluation(job.evaluationTrace);
|
|
586
|
+
const details = [reason, traceSummary].filter(Boolean).join('\n');
|
|
587
|
+
|
|
588
|
+
if (job.status === 'skipped') {
|
|
589
|
+
return [
|
|
590
|
+
`**${job.displayName}** was skipped before an execution was created.`,
|
|
591
|
+
'',
|
|
592
|
+
'Review its dependencies or condition before re-running.',
|
|
593
|
+
details,
|
|
594
|
+
]
|
|
595
|
+
.filter(Boolean)
|
|
596
|
+
.join('\n');
|
|
597
|
+
}
|
|
598
|
+
return [
|
|
599
|
+
`**${job.displayName}** failed before an execution was created.`,
|
|
600
|
+
'',
|
|
601
|
+
'Check runner availability and workflow configuration before re-running.',
|
|
602
|
+
details,
|
|
603
|
+
]
|
|
604
|
+
.filter(Boolean)
|
|
605
|
+
.join('\n');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function formatConditionEvaluation(
|
|
609
|
+
trace: readonly EvaluationTraceEntry[] | null | undefined,
|
|
610
|
+
): string | null {
|
|
611
|
+
if (!trace?.length) return null;
|
|
612
|
+
|
|
613
|
+
return [
|
|
614
|
+
'Condition evaluation:',
|
|
615
|
+
...trace.map((entry) => {
|
|
616
|
+
if ('dropped' in entry) {
|
|
617
|
+
return `- ${entry.dropped} additional evaluation${entry.dropped === 1 ? '' : 's'} not recorded`;
|
|
618
|
+
}
|
|
619
|
+
const value =
|
|
620
|
+
entry.value === undefined || entry.value === '' ? '(empty)' : `\`${entry.value}\``;
|
|
621
|
+
return `- \`${entry.field}\` evaluated \`${entry.expression}\` to ${value}${entry.degraded ? ' (degraded)' : ''}`;
|
|
622
|
+
}),
|
|
623
|
+
].join('\n');
|
|
624
|
+
}
|
|
625
|
+
|
|
526
626
|
const ALL_ANNOTATION_JOBS = 'all-jobs';
|
|
527
627
|
|
|
528
628
|
function AnnotationJobFilter({
|
|
@@ -566,11 +666,11 @@ function RunWorkspaceNavSkeleton() {
|
|
|
566
666
|
return (
|
|
567
667
|
<aside
|
|
568
668
|
aria-label="Loading run navigation"
|
|
569
|
-
className="hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-
|
|
669
|
+
className="hidden w-240 shrink-0 border-r border-border-neutral-base bg-background-neutral-background p-panel-compact min-[768px]:block"
|
|
570
670
|
>
|
|
571
|
-
<div className="flex flex-col gap-
|
|
671
|
+
<div className="flex flex-col gap-group">
|
|
572
672
|
<div className="h-32 rounded-4 bg-background-components-subtle" />
|
|
573
|
-
<div className="flex flex-col gap-
|
|
673
|
+
<div className="flex flex-col gap-inline">
|
|
574
674
|
<div className="h-16 w-64 rounded-4 bg-background-components-subtle" />
|
|
575
675
|
<div className="h-32 rounded-4 bg-background-components-subtle" />
|
|
576
676
|
<div className="h-32 rounded-4 bg-background-components-subtle" />
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {type Duration, intervalToDuration} from 'date-fns';
|
|
2
2
|
import type {Step} from './step.js';
|
|
3
|
+
import type {EvaluationTraceEntry} from './step-attempt.js';
|
|
3
4
|
|
|
4
5
|
export type JobExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
5
6
|
export type JobExecutionDisplayStatus = JobExecutionStatus;
|
|
@@ -28,11 +29,15 @@ interface JobExecutionFields {
|
|
|
28
29
|
name: string;
|
|
29
30
|
status: JobExecutionStatus;
|
|
30
31
|
statusReason: string | null;
|
|
32
|
+
statusReasonMessage: string | null;
|
|
33
|
+
runner: string[] | null;
|
|
34
|
+
outputs: Record<string, unknown> | null;
|
|
31
35
|
triggerEvents: WorkflowExecutionEvent[];
|
|
32
36
|
queuedAt: string | null;
|
|
33
37
|
startedAt: string | null;
|
|
34
38
|
finishedAt: string | null;
|
|
35
39
|
timedOutAt: string | null;
|
|
40
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
36
41
|
createdAt: string;
|
|
37
42
|
updatedAt: string;
|
|
38
43
|
steps: Step[];
|
|
@@ -45,11 +50,15 @@ export class JobExecution {
|
|
|
45
50
|
name!: string;
|
|
46
51
|
status!: JobExecutionStatus;
|
|
47
52
|
statusReason!: string | null;
|
|
53
|
+
statusReasonMessage!: string | null;
|
|
54
|
+
runner!: string[] | null;
|
|
55
|
+
outputs!: Record<string, unknown> | null;
|
|
48
56
|
triggerEvents!: WorkflowExecutionEvent[];
|
|
49
57
|
queuedAt!: string | null;
|
|
50
58
|
startedAt!: string | null;
|
|
51
59
|
finishedAt!: string | null;
|
|
52
60
|
timedOutAt!: string | null;
|
|
61
|
+
evaluationTrace!: EvaluationTraceEntry[] | null;
|
|
53
62
|
createdAt!: string;
|
|
54
63
|
updatedAt!: string;
|
|
55
64
|
steps!: Step[];
|
package/src/core/entities/job.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type JobExecution,
|
|
4
4
|
type JobExecutionDisplayDuration,
|
|
5
5
|
} from './job-execution.js';
|
|
6
|
+
import type {EvaluationTraceEntry} from './step-attempt.js';
|
|
6
7
|
|
|
7
8
|
export type JobStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';
|
|
8
9
|
export type JobDisplayStatus = JobStatus | 'listening';
|
|
@@ -19,8 +20,10 @@ export type JobStatusReason =
|
|
|
19
20
|
| 'run_cancelled'
|
|
20
21
|
| 'timed_out'
|
|
21
22
|
| 'runner_lost'
|
|
23
|
+
| 'output_too_large'
|
|
22
24
|
| 'step_failed'
|
|
23
|
-
| 'unknown'
|
|
25
|
+
| 'unknown'
|
|
26
|
+
| 'output_invalid';
|
|
24
27
|
export interface JobListening {
|
|
25
28
|
on: Array<{
|
|
26
29
|
source: string;
|
|
@@ -75,6 +78,10 @@ interface JobFields {
|
|
|
75
78
|
status: JobStatus;
|
|
76
79
|
statusReason: JobStatusReason | null;
|
|
77
80
|
carriedOver: boolean;
|
|
81
|
+
outputs: Record<string, unknown> | null;
|
|
82
|
+
success: string | null;
|
|
83
|
+
runner: string[] | null;
|
|
84
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
78
85
|
listening: JobListening | null;
|
|
79
86
|
listenerStatus: ListenerStatus;
|
|
80
87
|
resolutionReason: ResolutionReason | null;
|
|
@@ -94,6 +101,10 @@ export class Job {
|
|
|
94
101
|
status!: JobStatus;
|
|
95
102
|
statusReason!: JobStatusReason | null;
|
|
96
103
|
carriedOver!: boolean;
|
|
104
|
+
outputs!: Record<string, unknown> | null;
|
|
105
|
+
success!: string | null;
|
|
106
|
+
runner!: string[] | null;
|
|
107
|
+
evaluationTrace!: EvaluationTraceEntry[] | null;
|
|
97
108
|
listening!: JobListening | null;
|
|
98
109
|
listenerStatus!: ListenerStatus;
|
|
99
110
|
resolutionReason!: ResolutionReason | null;
|
|
@@ -13,6 +13,27 @@ export type StepAttemptDisplayDuration =
|
|
|
13
13
|
| {state: 'fixed'; elapsed: Duration}
|
|
14
14
|
| {state: 'live'; fromIso: string};
|
|
15
15
|
|
|
16
|
+
export interface EvaluationTraceValueEntry {
|
|
17
|
+
expression: string;
|
|
18
|
+
roots: string[];
|
|
19
|
+
fillTarget: string;
|
|
20
|
+
evaluatedAt: string;
|
|
21
|
+
field: string;
|
|
22
|
+
value?: string;
|
|
23
|
+
truncated?: boolean;
|
|
24
|
+
exprTruncated?: boolean;
|
|
25
|
+
reference?: boolean;
|
|
26
|
+
degraded?: boolean;
|
|
27
|
+
envKey?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface EvaluationTraceLimitEntry {
|
|
31
|
+
truncated: true;
|
|
32
|
+
dropped: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type EvaluationTraceEntry = EvaluationTraceValueEntry | EvaluationTraceLimitEntry;
|
|
36
|
+
|
|
16
37
|
interface StepAttemptFields {
|
|
17
38
|
id: string;
|
|
18
39
|
stepId: string;
|
|
@@ -22,6 +43,8 @@ interface StepAttemptFields {
|
|
|
22
43
|
status: string;
|
|
23
44
|
exitCode: number | null;
|
|
24
45
|
output: Record<string, unknown> | null;
|
|
46
|
+
outputs: Record<string, unknown> | null;
|
|
47
|
+
response: string | null;
|
|
25
48
|
error: Record<string, unknown> | null;
|
|
26
49
|
gateResult: StepGateResult;
|
|
27
50
|
restartFeedback: string | null;
|
|
@@ -38,6 +61,8 @@ export class StepAttempt {
|
|
|
38
61
|
status!: string;
|
|
39
62
|
exitCode!: number | null;
|
|
40
63
|
output!: Record<string, unknown> | null;
|
|
64
|
+
outputs!: Record<string, unknown> | null;
|
|
65
|
+
response!: string | null;
|
|
41
66
|
error!: Record<string, unknown> | null;
|
|
42
67
|
gateResult!: StepGateResult;
|
|
43
68
|
restartFeedback!: string | null;
|
|
@@ -53,6 +78,14 @@ export class StepAttempt {
|
|
|
53
78
|
}
|
|
54
79
|
}
|
|
55
80
|
|
|
81
|
+
export interface StepAttemptDetail {
|
|
82
|
+
stepId: string;
|
|
83
|
+
attempt: number;
|
|
84
|
+
authoredConfig: Record<string, unknown> | null;
|
|
85
|
+
config: Record<string, unknown> | null;
|
|
86
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
87
|
+
}
|
|
88
|
+
|
|
56
89
|
export function stepAttemptDisplayDurationFromTimestamps({
|
|
57
90
|
startedAt,
|
|
58
91
|
finishedAt,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {StepAttempt} from './step-attempt.js';
|
|
1
|
+
import type {EvaluationTraceEntry, StepAttempt} from './step-attempt.js';
|
|
2
2
|
|
|
3
3
|
export type StepErrorReason =
|
|
4
4
|
| 'checkout_failed'
|
|
@@ -71,8 +71,10 @@ export interface Step {
|
|
|
71
71
|
name: string;
|
|
72
72
|
sourceLocation: StepSourceLocation | null;
|
|
73
73
|
status: string;
|
|
74
|
+
statusReason: string | null;
|
|
74
75
|
type: string;
|
|
75
76
|
config: Record<string, unknown>;
|
|
77
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
76
78
|
agentConfig: AgentStepConfig | null;
|
|
77
79
|
error: StepError | null;
|
|
78
80
|
position: number;
|