@shipfox/client-workflows 18.0.0 → 20.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.
Files changed (62) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +25 -0
  3. package/dist/components/workflow-run-duration-label.d.ts +8 -7
  4. package/dist/components/workflow-run-duration-label.d.ts.map +1 -1
  5. package/dist/components/workflow-run-duration-label.js +15 -31
  6. package/dist/components/workflow-run-duration-label.js.map +1 -1
  7. package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -1
  8. package/dist/components/workflow-run-list/job-status-strip.js +20 -7
  9. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
  10. package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
  11. package/dist/components/workflow-run-list/workflow-run-row.js +9 -6
  12. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  13. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  14. package/dist/components/workflow-run-summary/workflow-run-summary.js +7 -34
  15. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  16. package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
  17. package/dist/components/workflow-status/status-visuals.js +0 -9
  18. package/dist/components/workflow-status/status-visuals.js.map +1 -1
  19. package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
  20. package/dist/components/workflow-status/workflow-status-icon.js +0 -11
  21. package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
  22. package/dist/core/entities/job.d.ts +5 -2
  23. package/dist/core/entities/job.d.ts.map +1 -1
  24. package/dist/core/entities/job.js +8 -1
  25. package/dist/core/entities/job.js.map +1 -1
  26. package/dist/core/entities/workflow-run.d.ts +15 -57
  27. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  28. package/dist/core/entities/workflow-run.js +1 -94
  29. package/dist/core/entities/workflow-run.js.map +1 -1
  30. package/dist/core/workflow-run.d.ts +2 -2
  31. package/dist/core/workflow-run.d.ts.map +1 -1
  32. package/dist/core/workflow-run.js +1 -1
  33. package/dist/core/workflow-run.js.map +1 -1
  34. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  35. package/dist/hooks/api/workflow-run-mapper.js +14 -2
  36. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  37. package/dist/hooks/api/workflow-runs.js +1 -0
  38. package/dist/hooks/api/workflow-runs.js.map +1 -1
  39. package/dist/tsconfig.test.tsbuildinfo +1 -1
  40. package/package.json +2 -2
  41. package/src/components/job-graph/job-node.test.tsx +2 -2
  42. package/src/components/workflow-run-duration-label.tsx +21 -44
  43. package/src/components/workflow-run-list/job-status-strip.tsx +25 -12
  44. package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +121 -0
  45. package/src/components/workflow-run-list/workflow-run-list.stories.tsx +31 -0
  46. package/src/components/workflow-run-list/workflow-run-row.tsx +7 -6
  47. package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +0 -38
  48. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +73 -21
  49. package/src/components/workflow-run-summary/workflow-run-summary.tsx +6 -27
  50. package/src/components/workflow-status/status-visuals.ts +0 -4
  51. package/src/components/workflow-status/workflow-status-icon.stories.tsx +0 -1
  52. package/src/components/workflow-status/workflow-status-icon.tsx +0 -18
  53. package/src/core/entities/job-status.test.ts +47 -1
  54. package/src/core/entities/job.ts +15 -3
  55. package/src/core/entities/workflow-run.ts +21 -134
  56. package/src/core/workflow-run.test.ts +15 -0
  57. package/src/core/workflow-run.ts +0 -8
  58. package/src/hooks/api/workflow-run-mapper.ts +20 -1
  59. package/src/hooks/api/workflow-runs.ts +1 -1
  60. package/test/fixtures/workflow-run.ts +60 -13
  61. package/tsconfig.build.tsbuildinfo +1 -1
  62. package/src/core/entities/workflow-run-display.test.ts +0 -159
@@ -96,7 +96,10 @@ export function toWorkflowRunRecord(dto: WorkflowRunResponseDto): WorkflowRunRec
96
96
  }
97
97
 
98
98
  export function toWorkflowRunListItem(dto: WorkflowRunListItemDto): WorkflowRunListItem {
99
- const statusCounts = dto.job_status_counts.map(({status, count}) => ({status, count}));
99
+ const hasDisplayStatusCounts = dto.job_display_status_counts !== undefined;
100
+ const statusCounts = (dto.job_display_status_counts ?? dto.job_status_counts).map(
101
+ ({status, count}) => ({status, count}),
102
+ );
100
103
  return {
101
104
  ...toWorkflowRunRecord(dto),
102
105
  jobs: {
@@ -105,9 +108,18 @@ export function toWorkflowRunListItem(dto: WorkflowRunListItemDto): WorkflowRunL
105
108
  key: job.key,
106
109
  name: job.name,
107
110
  status: job.status,
111
+ mode: job.mode ?? 'one_shot',
112
+ listenerStatus: job.listener_status ?? 'inactive',
113
+ // The optional display-count field is the rollout capability signal. Pre-display API
114
+ // responses only carry raw verdict counts, so mirror their non-terminal verdict into
115
+ // execution evidence to keep each legacy glyph aligned with those fallback counts.
116
+ executionStatus: hasDisplayStatusCounts
117
+ ? (job.execution_status ?? null)
118
+ : legacyExecutionStatus(job.status),
108
119
  position: job.position,
109
120
  })),
110
121
  statusCounts,
122
+ hasStartedJobExecution: dto.has_started_job_execution ?? true,
111
123
  // Derived rather than sent: the counts already cover every job, and a separate total
112
124
  // would be a second source of truth that could disagree with them.
113
125
  total: statusCounts.reduce((sum, entry) => sum + entry.count, 0),
@@ -115,6 +127,12 @@ export function toWorkflowRunListItem(dto: WorkflowRunListItemDto): WorkflowRunL
115
127
  };
116
128
  }
117
129
 
130
+ function legacyExecutionStatus(
131
+ status: WorkflowRunListItemDto['jobs'][number]['status'],
132
+ ): 'pending' | 'running' | null {
133
+ return status === 'pending' || status === 'running' ? status : null;
134
+ }
135
+
118
136
  export function toWorkflowRunListPage(dto: WorkflowRunListResponseDto): WorkflowRunListPage {
119
137
  return {
120
138
  runs: dto.runs.map(toWorkflowRunListItem),
@@ -129,6 +147,7 @@ export function toWorkflowRunDetail(dto: WorkflowRunDetailResponseDto): Workflow
129
147
  latestAttempt: dto.latest_attempt,
130
148
  runAttempt: toWorkflowRunAttempt(dto.run_attempt),
131
149
  jobs: dto.jobs.map(toJob),
150
+ hasStartedJobExecution: dto.has_started_job_execution ?? true,
132
151
  };
133
152
  }
134
153
 
@@ -358,7 +358,7 @@ function buildTempRun({
358
358
  updatedAt: createdAt,
359
359
  isTemporary: true,
360
360
  // The optimistic row genuinely has no jobs yet: the server has not planned the graph.
361
- jobs: {preview: [], statusCounts: [], total: 0},
361
+ jobs: {preview: [], statusCounts: [], hasStartedJobExecution: false, total: 0},
362
362
  runAttempt: new WorkflowRunAttemptSummary({
363
363
  workflowRunId: id,
364
364
  attempt: 1,
@@ -81,6 +81,8 @@ export function workflowRunDto(
81
81
  finished_at: null,
82
82
  jobs: [],
83
83
  job_status_counts: [],
84
+ job_display_status_counts: [],
85
+ has_started_job_execution: false,
84
86
  ...overrides,
85
87
  };
86
88
  }
@@ -89,11 +91,15 @@ export function workflowRunJobSummaryDto(
89
91
  overrides: Partial<WorkflowRunJobSummaryDto> = {},
90
92
  ): WorkflowRunJobSummaryDto {
91
93
  jobSummarySequence += 1;
94
+ const status = overrides.status ?? 'succeeded';
92
95
  return {
93
96
  id: `${JOB_SUMMARY_ID_PREFIX}${String(jobSummarySequence).padStart(11, '0')}`,
94
97
  key: `job-${jobSummarySequence}`,
95
98
  name: null,
96
- status: 'succeeded',
99
+ status,
100
+ mode: 'one_shot',
101
+ listener_status: 'inactive',
102
+ execution_status: executionStatusForFixtureStatus(status),
97
103
  position: jobSummarySequence - 1,
98
104
  ...overrides,
99
105
  };
@@ -104,13 +110,25 @@ export function workflowRunJobSummaryDtos(
104
110
  count: number,
105
111
  statuses: readonly JobStatusDto[] = [],
106
112
  ): WorkflowRunJobSummaryDto[] {
107
- return Array.from({length: count}, (_, index) =>
108
- workflowRunJobSummaryDto({
113
+ return Array.from({length: count}, (_, index) => {
114
+ const status = statuses[index];
115
+ return workflowRunJobSummaryDto({
109
116
  key: `job-${index + 1}`,
110
117
  position: index,
111
- ...(statuses[index] ? {status: statuses[index]} : {}),
112
- }),
113
- );
118
+ ...(status
119
+ ? {
120
+ status,
121
+ execution_status: executionStatusForFixtureStatus(status),
122
+ }
123
+ : {}),
124
+ });
125
+ });
126
+ }
127
+
128
+ function executionStatusForFixtureStatus(
129
+ status: JobStatusDto,
130
+ ): WorkflowRunJobSummaryDto['execution_status'] {
131
+ return status === 'pending' || status === 'running' ? status : null;
114
132
  }
115
133
 
116
134
  /**
@@ -119,19 +137,33 @@ export function workflowRunJobSummaryDtos(
119
137
  *
120
138
  * Built from one list so the two can never disagree. A fixture whose counts contradicted its
121
139
  * preview would hide exactly the bug the split exists to prevent.
140
+ *
141
+ * `has_started_job_execution` follows the statuses where they settle it: `succeeded` and `failed`
142
+ * cannot be reached without running. `pending`, `skipped`, and `cancelled` leave it open, which is
143
+ * the ambiguity the server flag exists to resolve, so those default to not started and a case that
144
+ * needs the other reading overrides it.
122
145
  */
123
146
  export function workflowRunJobsFixture(
124
147
  statuses: readonly JobStatusDto[],
125
- ): Pick<WorkflowRunListItemDto, 'jobs' | 'job_status_counts'> {
148
+ ): Pick<
149
+ WorkflowRunListItemDto,
150
+ 'jobs' | 'job_status_counts' | 'job_display_status_counts' | 'has_started_job_execution'
151
+ > {
126
152
  const counts = new Map<JobStatusDto, number>();
127
153
  for (const status of statuses) counts.set(status, (counts.get(status) ?? 0) + 1);
128
154
 
155
+ const preview = workflowRunJobSummaryDtos(
156
+ Math.min(statuses.length, WORKFLOW_RUN_JOB_PREVIEW_LIMIT),
157
+ statuses,
158
+ );
159
+
129
160
  return {
130
- jobs: workflowRunJobSummaryDtos(
131
- Math.min(statuses.length, WORKFLOW_RUN_JOB_PREVIEW_LIMIT),
132
- statuses,
133
- ),
161
+ jobs: preview,
134
162
  job_status_counts: [...counts.entries()].map(([status, count]) => ({status, count})),
163
+ job_display_status_counts: [...counts.entries()].map(([status, count]) => ({status, count})),
164
+ has_started_job_execution: statuses.some(
165
+ (status) => status === 'running' || status === 'succeeded' || status === 'failed',
166
+ ),
135
167
  };
136
168
  }
137
169
 
@@ -139,7 +171,10 @@ export function workflowRunJobsFixture(
139
171
  export function workflowRunJobsOfStatus(
140
172
  count: number,
141
173
  status: JobStatusDto = 'succeeded',
142
- ): Pick<WorkflowRunListItemDto, 'jobs' | 'job_status_counts'> {
174
+ ): Pick<
175
+ WorkflowRunListItemDto,
176
+ 'jobs' | 'job_status_counts' | 'job_display_status_counts' | 'has_started_job_execution'
177
+ > {
143
178
  return workflowRunJobsFixture(Array.from({length: count}, () => status));
144
179
  }
145
180
 
@@ -169,7 +204,12 @@ export function workflowRunListPage(
169
204
  export function workflowRunDetailDto(
170
205
  overrides: Partial<WorkflowRunDetailResponseDto> = {},
171
206
  ): WorkflowRunDetailResponseDto {
172
- const {jobs, run_attempt: runAttemptOverride, ...runOverrides} = overrides;
207
+ const {
208
+ jobs,
209
+ run_attempt: runAttemptOverride,
210
+ has_started_job_execution: hasStartedOverride,
211
+ ...runOverrides
212
+ } = overrides;
173
213
  const run = workflowRunDto(runOverrides);
174
214
 
175
215
  return {
@@ -185,6 +225,13 @@ export function workflowRunDetailDto(
185
225
  finished_at: run.finished_at,
186
226
  }),
187
227
  jobs: jobs ?? [],
228
+ // Follows the executions the case actually built, so the fixture cannot claim a run started
229
+ // while carrying no execution that did.
230
+ has_started_job_execution:
231
+ hasStartedOverride ??
232
+ (jobs ?? []).some((job) =>
233
+ job.job_executions.some((execution) => execution.started_at != null),
234
+ ),
188
235
  };
189
236
  }
190
237