@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
|
@@ -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>
|
|
@@ -58,7 +58,7 @@ export function RunWorkspaceNav({
|
|
|
58
58
|
<CollapsibleTrigger asChild>
|
|
59
59
|
<button
|
|
60
60
|
type="button"
|
|
61
|
-
className="flex min-h-44 w-full items-center justify-between gap-
|
|
61
|
+
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
62
|
aria-label="Toggle run navigation"
|
|
63
63
|
>
|
|
64
64
|
<span className="min-w-0">
|
|
@@ -82,7 +82,7 @@ export function RunWorkspaceNav({
|
|
|
82
82
|
</CollapsibleTrigger>
|
|
83
83
|
<div
|
|
84
84
|
className={cn(
|
|
85
|
-
'max-h-[50vh] overflow-y-auto p-
|
|
85
|
+
'max-h-[50vh] overflow-y-auto p-tight min-[768px]:block min-[768px]:max-h-none min-[768px]:p-[12px]',
|
|
86
86
|
!mobileOpen && 'hidden',
|
|
87
87
|
)}
|
|
88
88
|
>
|
|
@@ -136,7 +136,7 @@ function RunWorkspaceNavContent({
|
|
|
136
136
|
}, [currentJobId, mobileOpen]);
|
|
137
137
|
|
|
138
138
|
return (
|
|
139
|
-
<nav aria-label="Run workspace" className="flex min-w-0 flex-col gap-
|
|
139
|
+
<nav aria-label="Run workspace" className="flex min-w-0 flex-col gap-group">
|
|
140
140
|
<ul>
|
|
141
141
|
<li>
|
|
142
142
|
<RunSectionLink
|
|
@@ -152,7 +152,7 @@ function RunWorkspaceNavContent({
|
|
|
152
152
|
</ul>
|
|
153
153
|
|
|
154
154
|
<section aria-labelledby="run-workspace-jobs-heading" className="min-w-0">
|
|
155
|
-
<div className="flex items-center justify-between gap-
|
|
155
|
+
<div className="flex items-center justify-between gap-inline px-tight pb-[6px]">
|
|
156
156
|
<Text
|
|
157
157
|
as="h2"
|
|
158
158
|
id="run-workspace-jobs-heading"
|
|
@@ -182,7 +182,7 @@ function RunWorkspaceNavContent({
|
|
|
182
182
|
onClick={onNavigate}
|
|
183
183
|
aria-current={current ? 'page' : undefined}
|
|
184
184
|
className={cn(
|
|
185
|
-
'flex min-h-32 min-w-0 items-center gap-
|
|
185
|
+
'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
186
|
current && 'bg-background-neutral-hover',
|
|
187
187
|
)}
|
|
188
188
|
>
|
|
@@ -210,7 +210,7 @@ function RunWorkspaceNavContent({
|
|
|
210
210
|
id="run-workspace-details-heading"
|
|
211
211
|
size="xs"
|
|
212
212
|
bold
|
|
213
|
-
className="px-
|
|
213
|
+
className="px-tight pb-[6px] text-foreground-neutral-muted"
|
|
214
214
|
>
|
|
215
215
|
Run details
|
|
216
216
|
</Text>
|
|
@@ -285,7 +285,7 @@ function RunSectionLink({
|
|
|
285
285
|
: undefined
|
|
286
286
|
}
|
|
287
287
|
className={cn(
|
|
288
|
-
'flex min-h-32 items-center gap-
|
|
288
|
+
'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
289
|
current && 'bg-background-neutral-hover',
|
|
290
290
|
)}
|
|
291
291
|
>
|
|
@@ -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,14 @@ interface JobExecutionFields {
|
|
|
28
29
|
name: string;
|
|
29
30
|
status: JobExecutionStatus;
|
|
30
31
|
statusReason: string | null;
|
|
32
|
+
runner: string[] | null;
|
|
33
|
+
outputs: Record<string, unknown> | null;
|
|
31
34
|
triggerEvents: WorkflowExecutionEvent[];
|
|
32
35
|
queuedAt: string | null;
|
|
33
36
|
startedAt: string | null;
|
|
34
37
|
finishedAt: string | null;
|
|
35
38
|
timedOutAt: string | null;
|
|
39
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
36
40
|
createdAt: string;
|
|
37
41
|
updatedAt: string;
|
|
38
42
|
steps: Step[];
|
|
@@ -45,11 +49,14 @@ export class JobExecution {
|
|
|
45
49
|
name!: string;
|
|
46
50
|
status!: JobExecutionStatus;
|
|
47
51
|
statusReason!: string | null;
|
|
52
|
+
runner!: string[] | null;
|
|
53
|
+
outputs!: Record<string, unknown> | null;
|
|
48
54
|
triggerEvents!: WorkflowExecutionEvent[];
|
|
49
55
|
queuedAt!: string | null;
|
|
50
56
|
startedAt!: string | null;
|
|
51
57
|
finishedAt!: string | null;
|
|
52
58
|
timedOutAt!: string | null;
|
|
59
|
+
evaluationTrace!: EvaluationTraceEntry[] | null;
|
|
53
60
|
createdAt!: string;
|
|
54
61
|
updatedAt!: string;
|
|
55
62
|
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';
|
|
@@ -75,6 +76,10 @@ interface JobFields {
|
|
|
75
76
|
status: JobStatus;
|
|
76
77
|
statusReason: JobStatusReason | null;
|
|
77
78
|
carriedOver: boolean;
|
|
79
|
+
outputs: Record<string, unknown> | null;
|
|
80
|
+
success: string | null;
|
|
81
|
+
runner: string[] | null;
|
|
82
|
+
evaluationTrace: EvaluationTraceEntry[] | null;
|
|
78
83
|
listening: JobListening | null;
|
|
79
84
|
listenerStatus: ListenerStatus;
|
|
80
85
|
resolutionReason: ResolutionReason | null;
|
|
@@ -94,6 +99,10 @@ export class Job {
|
|
|
94
99
|
status!: JobStatus;
|
|
95
100
|
statusReason!: JobStatusReason | null;
|
|
96
101
|
carriedOver!: boolean;
|
|
102
|
+
outputs!: Record<string, unknown> | null;
|
|
103
|
+
success!: string | null;
|
|
104
|
+
runner!: string[] | null;
|
|
105
|
+
evaluationTrace!: EvaluationTraceEntry[] | null;
|
|
97
106
|
listening!: JobListening | null;
|
|
98
107
|
listenerStatus!: ListenerStatus;
|
|
99
108
|
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;
|
|
@@ -44,6 +44,12 @@ export interface RunAnnotationSummary {
|
|
|
44
44
|
success: number;
|
|
45
45
|
/** True when the read hit its page budget, so every count is a lower bound. */
|
|
46
46
|
truncated: boolean;
|
|
47
|
+
/** Optional per-step counts used by the step inspector without loading annotation bodies. */
|
|
48
|
+
stepCounts?: readonly {
|
|
49
|
+
stepId: string;
|
|
50
|
+
attempt: number;
|
|
51
|
+
total: number;
|
|
52
|
+
}[];
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
/** Everything the annotations list needs to route back to the step that emitted an annotation. */
|
package/src/core/workflow-run.ts
CHANGED
|
@@ -46,6 +46,10 @@ export {
|
|
|
46
46
|
STEP_ERROR_REASONS,
|
|
47
47
|
} from './entities/step.js';
|
|
48
48
|
export type {
|
|
49
|
+
EvaluationTraceEntry,
|
|
50
|
+
EvaluationTraceLimitEntry,
|
|
51
|
+
EvaluationTraceValueEntry,
|
|
52
|
+
StepAttemptDetail,
|
|
49
53
|
StepAttemptDisplayDuration,
|
|
50
54
|
StepGateResult,
|
|
51
55
|
} from './entities/step-attempt.js';
|