@shipfox/client-workflows 20.0.0 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +51 -0
  3. package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
  4. package/dist/components/job-detail/job-detail-view.js +232 -44
  5. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  6. package/dist/components/job-detail/job-empty-states.js +2 -2
  7. package/dist/components/job-detail/job-empty-states.js.map +1 -1
  8. package/dist/components/job-detail/step-attempt-log-panel.d.ts +7 -1
  9. package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
  10. package/dist/components/job-detail/step-attempt-log-panel.js +37 -10
  11. package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
  12. package/dist/components/job-graph/job-graph-content.js +2 -2
  13. package/dist/components/job-graph/job-graph-content.js.map +1 -1
  14. package/dist/components/step-list/step-list-model.d.ts +1 -0
  15. package/dist/components/step-list/step-list-model.d.ts.map +1 -1
  16. package/dist/components/step-list/step-list-model.js +1 -1
  17. package/dist/components/step-list/step-list-model.js.map +1 -1
  18. package/dist/components/step-list/step-list.d.ts +2 -1
  19. package/dist/components/step-list/step-list.d.ts.map +1 -1
  20. package/dist/components/step-list/step-list.js +25 -9
  21. package/dist/components/step-list/step-list.js.map +1 -1
  22. package/dist/components/workflow-run-list/job-status-strip.d.ts +9 -1
  23. package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -1
  24. package/dist/components/workflow-run-list/job-status-strip.js +22 -11
  25. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
  26. package/dist/components/workflow-run-list/workflow-run-filters.js +1 -1
  27. package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
  28. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
  29. package/dist/components/workflow-run-list/workflow-run-list-content.js +13 -7
  30. package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
  31. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
  32. package/dist/components/workflow-run-list/workflow-run-list-states.js +43 -38
  33. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  34. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
  35. package/dist/components/workflow-run-list/workflow-run-list-view.js +34 -22
  36. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  37. package/dist/components/workflow-run-list/workflow-run-row.d.ts +3 -3
  38. package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
  39. package/dist/components/workflow-run-list/workflow-run-row.js +25 -18
  40. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  41. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  42. package/dist/components/workflow-run-summary/workflow-run-summary.js +4 -4
  43. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  44. package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
  45. package/dist/components/workflow-run-view/run-workspace-nav.js +20 -7
  46. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  47. package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
  48. package/dist/components/workflow-run-view/workflow-run-states.js +1 -1
  49. package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
  50. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  51. package/dist/components/workflow-run-view/workflow-run-view.js +103 -78
  52. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  53. package/dist/components/workflow-source-panel/workflow-source-content.js +1 -1
  54. package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -1
  55. package/dist/pages/project-workflows-page.d.ts.map +1 -1
  56. package/dist/pages/project-workflows-page.js +171 -158
  57. package/dist/pages/project-workflows-page.js.map +1 -1
  58. package/dist/pages/workflow-job-detail-page.d.ts.map +1 -1
  59. package/dist/pages/workflow-job-detail-page.js +3 -2
  60. package/dist/pages/workflow-job-detail-page.js.map +1 -1
  61. package/dist/pages/workflow-run-detail-page.js +2 -1
  62. package/dist/pages/workflow-run-detail-page.js.map +1 -1
  63. package/dist/pages/workflow-run-list-page.d.ts.map +1 -1
  64. package/dist/pages/workflow-run-list-page.js +9 -11
  65. package/dist/pages/workflow-run-list-page.js.map +1 -1
  66. package/dist/routes/job-detail.d.ts +1 -1
  67. package/dist/routes/job-detail.js +1 -1
  68. package/dist/routes/job-detail.js.map +1 -1
  69. package/dist/routes/run-detail.d.ts +1 -1
  70. package/dist/routes/run-detail.js +1 -1
  71. package/dist/routes/run-detail.js.map +1 -1
  72. package/dist/routes/runs.d.ts +1 -1
  73. package/dist/routes/runs.js +1 -1
  74. package/dist/routes/runs.js.map +1 -1
  75. package/dist/routes/workflows.d.ts +3 -0
  76. package/dist/routes/workflows.js +3 -0
  77. package/dist/routes/workflows.js.map +1 -1
  78. package/dist/tsconfig.test.tsbuildinfo +1 -1
  79. package/package.json +8 -8
  80. package/src/components/job-detail/job-detail-view.tsx +264 -49
  81. package/src/components/job-detail/job-empty-states.tsx +2 -2
  82. package/src/components/job-detail/step-attempt-log-panel.test.tsx +30 -12
  83. package/src/components/job-detail/step-attempt-log-panel.tsx +68 -10
  84. package/src/components/job-graph/job-graph-content.tsx +2 -2
  85. package/src/components/job-graph/job-graph.stories.tsx +1 -1
  86. package/src/components/job-graph/job-node.stories.tsx +1 -1
  87. package/src/components/step-list/step-list-model.ts +1 -1
  88. package/src/components/step-list/step-list.test.tsx +29 -1
  89. package/src/components/step-list/step-list.tsx +29 -11
  90. package/src/components/workflow-run-list/job-status-strip.tsx +25 -12
  91. package/src/components/workflow-run-list/workflow-run-filters.tsx +1 -1
  92. package/src/components/workflow-run-list/workflow-run-list-content.tsx +7 -2
  93. package/src/components/workflow-run-list/workflow-run-list-states.tsx +42 -41
  94. package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +53 -4
  95. package/src/components/workflow-run-list/workflow-run-list-view.tsx +28 -22
  96. package/src/components/workflow-run-list/workflow-run-list.stories.tsx +9 -20
  97. package/src/components/workflow-run-list/workflow-run-row.tsx +26 -19
  98. package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +3 -3
  99. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +11 -2
  100. package/src/components/workflow-run-summary/workflow-run-summary.tsx +4 -7
  101. package/src/components/workflow-run-view/run-workspace-nav.test.tsx +40 -2
  102. package/src/components/workflow-run-view/run-workspace-nav.tsx +28 -9
  103. package/src/components/workflow-run-view/workflow-run-states.tsx +1 -4
  104. package/src/components/workflow-run-view/workflow-run-view.stories.tsx +142 -0
  105. package/src/components/workflow-run-view/workflow-run-view.test.tsx +42 -8
  106. package/src/components/workflow-run-view/workflow-run-view.tsx +112 -96
  107. package/src/components/workflow-source-panel/workflow-source-content.tsx +2 -2
  108. package/src/pages/project-workflows-page.tsx +135 -125
  109. package/src/pages/workflow-job-detail-page.test.tsx +32 -0
  110. package/src/pages/workflow-job-detail-page.tsx +5 -1
  111. package/src/pages/workflow-run-detail-page.tsx +1 -1
  112. package/src/pages/workflow-run-list-page.tsx +9 -11
  113. package/src/pages/workflow-run-pages.test.tsx +26 -0
  114. package/src/routes/job-detail.tsx +1 -1
  115. package/src/routes/run-detail.tsx +1 -1
  116. package/src/routes/runs.tsx +1 -1
  117. package/src/routes/workflows.tsx +1 -0
  118. package/tsconfig.build.tsbuildinfo +1 -1
@@ -7,6 +7,7 @@ import { Callout } from '@shipfox/react-ui/callout';
7
7
  import { EmptyState } from '@shipfox/react-ui/empty-state';
8
8
  import { Icon } from '@shipfox/react-ui/icon';
9
9
  import { LoadErrorState } from '@shipfox/react-ui/load-error-state';
10
+ import { Panel } from '@shipfox/react-ui/panel';
10
11
  import { RelativeTime, RelativeTimeProvider } from '@shipfox/react-ui/relative-time';
11
12
  import { Sheet, SheetBody, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@shipfox/react-ui/sheet';
12
13
  import { Skeleton } from '@shipfox/react-ui/skeleton';
@@ -128,198 +129,209 @@ function ProjectWorkflowsPageInner({ projectId }) {
128
129
  }
129
130
  function WorkflowDefinitionsList({ definitions, isPending, isError, sync, runError, runningDefinitionId, hasNextPage, isFetchingNextPage, isFetchNextPageError, onRetry, onLoadMore, onOpenDefinition, onRun }) {
130
131
  if (isPending) {
131
- return /*#__PURE__*/ _jsxs("div", {
132
- className: "flex flex-col gap-inline",
132
+ return /*#__PURE__*/ _jsxs(Panel, {
133
+ role: "status",
134
+ "aria-label": "Loading workflows",
135
+ className: "divide-y",
133
136
  children: [
134
137
  /*#__PURE__*/ _jsx(Skeleton, {
135
- className: "h-40 w-full"
138
+ className: "h-44 w-full rounded-none"
136
139
  }),
137
140
  /*#__PURE__*/ _jsx(Skeleton, {
138
- className: "h-40 w-full"
141
+ className: "h-44 w-full rounded-none"
139
142
  }),
140
143
  /*#__PURE__*/ _jsx(Skeleton, {
141
- className: "h-40 w-full"
144
+ className: "h-44 w-full rounded-none"
142
145
  })
143
146
  ]
144
147
  });
145
148
  }
146
149
  if (isError && definitions.length === 0) {
147
- return /*#__PURE__*/ _jsx(LoadErrorState, {
148
- title: "Couldn't load workflows",
149
- description: "Definitions could not be loaded. Source metadata remains visible.",
150
- onRetry: onRetry,
151
- retryLabel: "Retry loading workflows"
150
+ return /*#__PURE__*/ _jsx(Panel, {
151
+ children: /*#__PURE__*/ _jsx(LoadErrorState, {
152
+ title: "Couldn't load workflows",
153
+ description: "Definitions could not be loaded. Source metadata remains visible.",
154
+ onRetry: onRetry,
155
+ retryLabel: "Retry loading workflows",
156
+ variant: "panel"
157
+ })
152
158
  });
153
159
  }
154
160
  if (definitions.length === 0) {
155
- return /*#__PURE__*/ _jsx(WorkflowEmptyState, {
156
- sync: sync
161
+ return /*#__PURE__*/ _jsx(Panel, {
162
+ children: /*#__PURE__*/ _jsx(WorkflowEmptyState, {
163
+ sync: sync
164
+ })
157
165
  });
158
166
  }
159
167
  return /*#__PURE__*/ _jsxs(_Fragment, {
160
168
  children: [
161
- /*#__PURE__*/ _jsx("div", {
162
- className: "hidden rounded-8 border border-border-neutral-base md:block",
163
- children: /*#__PURE__*/ _jsxs(Table, {
164
- children: [
165
- /*#__PURE__*/ _jsx(TableHeader, {
166
- children: /*#__PURE__*/ _jsxs(TableRow, {
167
- children: [
168
- /*#__PURE__*/ _jsx(TableHead, {
169
- className: "w-40"
170
- }),
171
- /*#__PURE__*/ _jsx(TableHead, {
172
- children: "Workflow"
173
- }),
174
- /*#__PURE__*/ _jsx(TableHead, {
175
- className: "w-180",
176
- children: "Updated"
177
- }),
178
- /*#__PURE__*/ _jsx(TableHead, {
179
- className: "w-80 text-right"
180
- })
181
- ]
182
- })
183
- }),
184
- /*#__PURE__*/ _jsx(TableBody, {
185
- children: definitions.map((definition)=>{
186
- const runErrorMessage = runError?.definitionId === definition.id ? runError.message : null;
187
- const isRunning = runningDefinitionId === definition.id;
188
- return(// The workflow-name cell holds a `<button>` so the row is
189
- // keyboard-reachable (Tab focuses, Enter/Space activates
190
- // via native button semantics). The TableRow itself is no
191
- // longer clickable: a row-level onClick would be invisible
192
- // to keyboard users and require custom keydown handling.
193
- // The `group` class on the row still drives the Run button
194
- // reveal on hover or focus-within.
195
- /*#__PURE__*/ _jsxs(TableRow, {
196
- className: "group",
197
- children: [
198
- /*#__PURE__*/ _jsx(TableCell, {
199
- children: /*#__PURE__*/ _jsx(Icon, {
200
- name: sourceIcon(definition.source),
201
- className: "size-16 text-foreground-neutral-muted",
202
- "aria-hidden": "true"
169
+ /*#__PURE__*/ _jsxs(Panel, {
170
+ children: [
171
+ /*#__PURE__*/ _jsx("div", {
172
+ className: "hidden md:block",
173
+ children: /*#__PURE__*/ _jsxs(Table, {
174
+ children: [
175
+ /*#__PURE__*/ _jsx(TableHeader, {
176
+ children: /*#__PURE__*/ _jsxs(TableRow, {
177
+ children: [
178
+ /*#__PURE__*/ _jsx(TableHead, {
179
+ className: "w-40"
180
+ }),
181
+ /*#__PURE__*/ _jsx(TableHead, {
182
+ children: "Workflow"
183
+ }),
184
+ /*#__PURE__*/ _jsx(TableHead, {
185
+ className: "w-180",
186
+ children: "Updated"
187
+ }),
188
+ /*#__PURE__*/ _jsx(TableHead, {
189
+ className: "w-80 text-right"
203
190
  })
204
- }),
205
- /*#__PURE__*/ _jsx(TableCell, {
206
- className: "max-w-260",
207
- children: /*#__PURE__*/ _jsxs("div", {
208
- className: "flex min-w-0 flex-col gap-tight",
209
- children: [
210
- /*#__PURE__*/ _jsxs("button", {
211
- type: "button",
212
- onClick: ()=>onOpenDefinition(definition),
213
- className: "flex min-w-0 flex-col gap-tight text-left outline-none focus-visible:shadow-border-interactive-with-active rounded-4",
191
+ ]
192
+ })
193
+ }),
194
+ /*#__PURE__*/ _jsx(TableBody, {
195
+ children: definitions.map((definition)=>{
196
+ const runErrorMessage = runError?.definitionId === definition.id ? runError.message : null;
197
+ const isRunning = runningDefinitionId === definition.id;
198
+ return(// The workflow-name cell holds a `<button>` so the row is
199
+ // keyboard-reachable (Tab focuses, Enter/Space activates
200
+ // via native button semantics). The TableRow itself is no
201
+ // longer clickable: a row-level onClick would be invisible
202
+ // to keyboard users and require custom keydown handling.
203
+ // The `group` class on the row still drives the Run button
204
+ // reveal on hover or focus-within.
205
+ /*#__PURE__*/ _jsxs(TableRow, {
206
+ className: "group",
207
+ children: [
208
+ /*#__PURE__*/ _jsx(TableCell, {
209
+ children: /*#__PURE__*/ _jsx(Icon, {
210
+ name: sourceIcon(definition.source),
211
+ className: "size-16 text-foreground-neutral-muted",
212
+ "aria-hidden": "true"
213
+ })
214
+ }),
215
+ /*#__PURE__*/ _jsx(TableCell, {
216
+ className: "max-w-260",
217
+ children: /*#__PURE__*/ _jsxs("div", {
218
+ className: "flex min-w-0 flex-col gap-tight",
214
219
  children: [
215
- /*#__PURE__*/ _jsx(Text, {
216
- size: "sm",
217
- bold: true,
218
- className: "truncate",
219
- children: definition.name
220
+ /*#__PURE__*/ _jsxs("button", {
221
+ type: "button",
222
+ onClick: ()=>onOpenDefinition(definition),
223
+ className: "flex min-w-0 flex-col gap-tight rounded-4 text-left outline-none focus-visible:shadow-border-interactive-with-active",
224
+ children: [
225
+ /*#__PURE__*/ _jsx(Text, {
226
+ size: "sm",
227
+ bold: true,
228
+ className: "truncate",
229
+ children: definition.name
230
+ }),
231
+ /*#__PURE__*/ _jsx(Code, {
232
+ className: "truncate text-foreground-neutral-muted",
233
+ children: definition.configPath ?? 'Manual definition'
234
+ })
235
+ ]
220
236
  }),
221
- /*#__PURE__*/ _jsx(Code, {
222
- className: "truncate text-foreground-neutral-muted",
223
- children: definition.configPath ?? 'Manual definition'
224
- })
237
+ runErrorMessage ? /*#__PURE__*/ _jsx(Text, {
238
+ size: "xs",
239
+ className: "text-tag-error-text",
240
+ children: runErrorMessage
241
+ }) : null
225
242
  ]
226
- }),
227
- runErrorMessage ? /*#__PURE__*/ _jsx(Text, {
228
- size: "xs",
229
- className: "text-tag-error-text",
230
- children: runErrorMessage
243
+ })
244
+ }),
245
+ /*#__PURE__*/ _jsx(TableCell, {
246
+ className: "text-foreground-neutral-muted",
247
+ children: /*#__PURE__*/ _jsx(RelativeTime, {
248
+ value: definition.updatedAt
249
+ })
250
+ }),
251
+ /*#__PURE__*/ _jsx(TableCell, {
252
+ children: definition.manualTrigger ? /*#__PURE__*/ _jsx("div", {
253
+ className: "flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",
254
+ children: /*#__PURE__*/ _jsx(Button, {
255
+ size: "xs",
256
+ isLoading: isRunning,
257
+ onClick: ()=>onRun(definition),
258
+ children: "Run"
259
+ })
231
260
  }) : null
232
- ]
233
- })
234
- }),
235
- /*#__PURE__*/ _jsx(TableCell, {
236
- className: "text-foreground-neutral-muted",
237
- children: /*#__PURE__*/ _jsx(RelativeTime, {
238
- value: definition.updatedAt
239
- })
240
- }),
241
- /*#__PURE__*/ _jsx(TableCell, {
242
- children: definition.manualTrigger ? /*#__PURE__*/ _jsx("div", {
243
- className: "flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",
244
- children: /*#__PURE__*/ _jsx(Button, {
245
- size: "xs",
246
- isLoading: isRunning,
247
- onClick: ()=>onRun(definition),
248
- children: "Run"
249
261
  })
250
- }) : null
251
- })
252
- ]
253
- }, definition.id));
254
- })
262
+ ]
263
+ }, definition.id));
264
+ })
265
+ })
266
+ ]
255
267
  })
256
- ]
257
- })
258
- }),
259
- /*#__PURE__*/ _jsx("div", {
260
- className: "flex flex-col rounded-8 border border-border-neutral-base md:hidden",
261
- children: definitions.map((definition)=>{
262
- const runErrorMessage = runError?.definitionId === definition.id ? runError.message : null;
263
- const isRunning = runningDefinitionId === definition.id;
264
- return /*#__PURE__*/ _jsxs("div", {
265
- className: "flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0",
266
- children: [
267
- /*#__PURE__*/ _jsxs("button", {
268
- type: "button",
269
- className: "flex min-w-0 items-start gap-inline text-left",
270
- onClick: ()=>onOpenDefinition(definition),
268
+ }),
269
+ /*#__PURE__*/ _jsx("div", {
270
+ className: "flex flex-col md:hidden",
271
+ children: definitions.map((definition)=>{
272
+ const runErrorMessage = runError?.definitionId === definition.id ? runError.message : null;
273
+ const isRunning = runningDefinitionId === definition.id;
274
+ return /*#__PURE__*/ _jsxs("div", {
275
+ className: "flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0",
271
276
  children: [
272
- /*#__PURE__*/ _jsx(Icon, {
273
- name: sourceIcon(definition.source),
274
- className: "size-16 shrink-0 text-foreground-neutral-muted",
275
- "aria-hidden": "true"
276
- }),
277
- /*#__PURE__*/ _jsxs("div", {
278
- className: "flex min-w-0 flex-col gap-tight",
277
+ /*#__PURE__*/ _jsxs("button", {
278
+ type: "button",
279
+ className: "flex min-w-0 items-start gap-inline text-left",
280
+ onClick: ()=>onOpenDefinition(definition),
279
281
  children: [
280
- /*#__PURE__*/ _jsx(Text, {
281
- size: "sm",
282
- bold: true,
283
- className: "break-words",
284
- children: definition.name
282
+ /*#__PURE__*/ _jsx(Icon, {
283
+ name: sourceIcon(definition.source),
284
+ className: "size-16 shrink-0 text-foreground-neutral-muted",
285
+ "aria-hidden": "true"
285
286
  }),
286
- /*#__PURE__*/ _jsx(Code, {
287
- className: "break-words text-foreground-neutral-muted",
288
- children: definition.configPath ?? 'Manual definition'
287
+ /*#__PURE__*/ _jsxs("div", {
288
+ className: "flex min-w-0 flex-col gap-tight",
289
+ children: [
290
+ /*#__PURE__*/ _jsx(Text, {
291
+ size: "sm",
292
+ bold: true,
293
+ className: "break-words",
294
+ children: definition.name
295
+ }),
296
+ /*#__PURE__*/ _jsx(Code, {
297
+ className: "break-words text-foreground-neutral-muted",
298
+ children: definition.configPath ?? 'Manual definition'
299
+ })
300
+ ]
289
301
  })
290
302
  ]
291
- })
292
- ]
293
- }),
294
- /*#__PURE__*/ _jsxs("div", {
295
- className: "flex items-center justify-between gap-inline",
296
- children: [
297
- /*#__PURE__*/ _jsxs(Text, {
298
- size: "xs",
299
- className: "text-foreground-neutral-muted",
303
+ }),
304
+ /*#__PURE__*/ _jsxs("div", {
305
+ className: "flex items-center justify-between gap-inline",
300
306
  children: [
301
- "Updated ",
302
- /*#__PURE__*/ _jsx(RelativeTime, {
303
- value: definition.updatedAt
304
- })
307
+ /*#__PURE__*/ _jsxs(Text, {
308
+ size: "xs",
309
+ className: "text-foreground-neutral-muted",
310
+ children: [
311
+ "Updated ",
312
+ /*#__PURE__*/ _jsx(RelativeTime, {
313
+ value: definition.updatedAt
314
+ })
315
+ ]
316
+ }),
317
+ definition.manualTrigger ? /*#__PURE__*/ _jsx(Button, {
318
+ size: "sm",
319
+ isLoading: isRunning,
320
+ onClick: ()=>onRun(definition),
321
+ children: "Run"
322
+ }) : null
305
323
  ]
306
324
  }),
307
- definition.manualTrigger ? /*#__PURE__*/ _jsx(Button, {
308
- size: "sm",
309
- isLoading: isRunning,
310
- onClick: ()=>onRun(definition),
311
- children: "Run"
325
+ runErrorMessage ? /*#__PURE__*/ _jsx(Text, {
326
+ size: "xs",
327
+ className: "text-tag-error-text",
328
+ children: runErrorMessage
312
329
  }) : null
313
330
  ]
314
- }),
315
- runErrorMessage ? /*#__PURE__*/ _jsx(Text, {
316
- size: "xs",
317
- className: "text-tag-error-text",
318
- children: runErrorMessage
319
- }) : null
320
- ]
321
- }, definition.id);
322
- })
331
+ }, definition.id);
332
+ })
333
+ })
334
+ ]
323
335
  }),
324
336
  isFetchNextPageError ? /*#__PURE__*/ _jsx(Callout, {
325
337
  role: "alert",
@@ -361,7 +373,8 @@ function WorkflowEmptyState({ sync }) {
361
373
  return /*#__PURE__*/ _jsx(EmptyState, {
362
374
  icon: "flowChart",
363
375
  title: "No workflows",
364
- description: message
376
+ description: message,
377
+ variant: "panel"
365
378
  });
366
379
  }
367
380
  function WorkflowSyncAlert({ sync }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/project-workflows-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {\n type Definition,\n type DefinitionSyncSummary,\n SourceStrip,\n useDefinitionsInfiniteQuery,\n useProjectQuery,\n} from '@shipfox/client-projects';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LoadErrorState} from '@shipfox/react-ui/load-error-state';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport {useFireManualWorkflowMutation} from '#hooks/api/workflow-runs.js';\n\nexport function ProjectWorkflowsPage({projectId}: {projectId: string}) {\n return (\n <RelativeTimeProvider>\n <ProjectWorkflowsPageInner projectId={projectId} />\n </RelativeTimeProvider>\n );\n}\n\nfunction ProjectWorkflowsPageInner({projectId}: {projectId: string}) {\n const projectQuery = useProjectQuery(projectId);\n const definitionsQuery = useDefinitionsInfiniteQuery(projectId);\n const fireManual = useFireManualWorkflowMutation();\n const [selectedDefinition, setSelectedDefinition] = useState<Definition | null>(null);\n const [runError, setRunError] = useState<{definitionId: string; message: string} | null>(null);\n const definitions = definitionsQuery.data?.pages.flatMap((page) => page.definitions) ?? [];\n const sync = definitionsQuery.data?.pages[0]?.sync;\n\n async function handleRun(definition: Definition) {\n setRunError(null);\n if (!definition.manualTrigger) return;\n try {\n await fireManual.mutateAsync({projectId, definitionId: definition.id});\n toast.success('Run queued');\n } catch (error) {\n const message = errorMessage(error, 'Could not queue run.');\n setRunError({definitionId: definition.id, message});\n toast.error(message);\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n {projectQuery.isPending ? (\n <div className=\"flex flex-col gap-cluster\">\n <Skeleton className=\"h-28 w-1/3\" />\n <Skeleton className=\"h-18 w-1/2\" />\n </div>\n ) : null}\n\n {projectQuery.isError && projectQuery.data === undefined ? (\n projectQuery.error instanceof ApiError && projectQuery.error.status === 404 ? (\n <EmptyState\n icon=\"errorWarningLine\"\n title=\"Project not found\"\n description=\"This project doesn't exist, or you don't have access to it.\"\n />\n ) : (\n <QueryLoadError query={projectQuery} subject=\"project\" />\n )\n ) : null}\n\n {projectQuery.data ? (\n <>\n <header className=\"flex flex-col gap-tight\">\n <Header variant=\"h2\">Workflows</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Synced workflow definitions for this project source.\n </Text>\n </header>\n\n <SourceStrip\n connectionId={projectQuery.data.source.connectionId}\n externalRepositoryId={projectQuery.data.source.externalRepositoryId}\n sync={sync}\n isPending={definitionsQuery.isPending}\n />\n\n <WorkflowSyncAlert sync={sync} />\n <WorkflowSyncWarnings sync={sync} />\n\n <WorkflowDefinitionsList\n definitions={definitions}\n isPending={definitionsQuery.isPending}\n isError={definitionsQuery.isError}\n sync={sync ?? null}\n runError={runError}\n runningDefinitionId={\n fireManual.isPending && fireManual.variables\n ? fireManual.variables.definitionId\n : null\n }\n hasNextPage={definitionsQuery.hasNextPage}\n isFetchingNextPage={definitionsQuery.isFetchingNextPage}\n isFetchNextPageError={definitionsQuery.isFetchNextPageError}\n onRetry={() => definitionsQuery.refetch()}\n onLoadMore={() => definitionsQuery.fetchNextPage()}\n onOpenDefinition={setSelectedDefinition}\n onRun={(definition) => {\n void handleRun(definition);\n }}\n />\n </>\n ) : null}\n\n <DefinitionSheet\n definition={selectedDefinition}\n onOpenChange={(open) => {\n if (!open) setSelectedDefinition(null);\n }}\n />\n </div>\n );\n}\n\nfunction WorkflowDefinitionsList({\n definitions,\n isPending,\n isError,\n sync,\n runError,\n runningDefinitionId,\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onRetry,\n onLoadMore,\n onOpenDefinition,\n onRun,\n}: {\n definitions: Definition[];\n isPending: boolean;\n isError: boolean;\n sync: DefinitionSyncSummary | null;\n runError: {definitionId: string; message: string} | null;\n runningDefinitionId: string | null;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onRetry: () => void;\n onLoadMore: () => void;\n onOpenDefinition: (definition: Definition) => void;\n onRun: (definition: Definition) => void;\n}) {\n if (isPending) {\n return (\n <div className=\"flex flex-col gap-inline\">\n <Skeleton className=\"h-40 w-full\" />\n <Skeleton className=\"h-40 w-full\" />\n <Skeleton className=\"h-40 w-full\" />\n </div>\n );\n }\n\n if (isError && definitions.length === 0) {\n return (\n <LoadErrorState\n title=\"Couldn't load workflows\"\n description=\"Definitions could not be loaded. Source metadata remains visible.\"\n onRetry={onRetry}\n retryLabel=\"Retry loading workflows\"\n />\n );\n }\n\n if (definitions.length === 0) {\n return <WorkflowEmptyState sync={sync} />;\n }\n\n return (\n <>\n <div className=\"hidden rounded-8 border border-border-neutral-base md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-40\"></TableHead>\n <TableHead>Workflow</TableHead>\n <TableHead className=\"w-180\">Updated</TableHead>\n <TableHead className=\"w-80 text-right\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n // The workflow-name cell holds a `<button>` so the row is\n // keyboard-reachable (Tab focuses, Enter/Space activates\n // via native button semantics). The TableRow itself is no\n // longer clickable: a row-level onClick would be invisible\n // to keyboard users and require custom keydown handling.\n // The `group` class on the row still drives the Run button\n // reveal on hover or focus-within.\n <TableRow key={definition.id} className=\"group\">\n <TableCell>\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n </TableCell>\n <TableCell className=\"max-w-260\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <button\n type=\"button\"\n onClick={() => onOpenDefinition(definition)}\n className=\"flex min-w-0 flex-col gap-tight text-left outline-none focus-visible:shadow-border-interactive-with-active rounded-4\"\n >\n <Text size=\"sm\" bold className=\"truncate\">\n {definition.name}\n </Text>\n <Code className=\"truncate text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </button>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={definition.updatedAt} />\n </TableCell>\n <TableCell>\n {definition.manualTrigger ? (\n <div className=\"flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <Button size=\"xs\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n </div>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex flex-col rounded-8 border border-border-neutral-base md:hidden\">\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n <div\n key={definition.id}\n className=\"flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0\"\n >\n <button\n type=\"button\"\n className=\"flex min-w-0 items-start gap-inline text-left\"\n onClick={() => onOpenDefinition(definition)}\n >\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 shrink-0 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"sm\" bold className=\"break-words\">\n {definition.name}\n </Text>\n <Code className=\"break-words text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </div>\n </button>\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Updated <RelativeTime value={definition.updatedAt} />\n </Text>\n {definition.manualTrigger ? (\n <Button size=\"sm\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n ) : null}\n </div>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n );\n })}\n </div>\n\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"sm\">Could not load more workflows.</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={onLoadMore}>\n Retry\n </Button>\n </div>\n </Callout>\n ) : null}\n\n {hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button size=\"sm\" variant=\"secondary\" isLoading={isFetchingNextPage} onClick={onLoadMore}>\n Load more\n </Button>\n </div>\n ) : null}\n </>\n );\n}\n\nfunction sourceIcon(source: 'manual' | 'vcs'): IconName {\n return source === 'vcs' ? ('gitBranchLine' as IconName) : ('terminalLine' as IconName);\n}\n\nfunction WorkflowEmptyState({sync}: {sync: DefinitionSyncSummary | null}) {\n const message =\n sync?.status === 'failed' && sync.lastErrorCode === 'no-workflow-files'\n ? 'No workflow files found under .shipfox/workflows/.'\n : sync?.status === 'failed'\n ? (sync.lastErrorMessage ?? 'Workflow definitions could not be synced.')\n : sync?.status === 'syncing'\n ? 'Workflow definitions are being discovered.'\n : sync?.status === 'succeeded'\n ? 'No workflow definitions found.'\n : 'Workflow sync has not reported yet.';\n\n return <EmptyState icon=\"flowChart\" title=\"No workflows\" description={message} />;\n}\n\nfunction WorkflowSyncAlert({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'failed') return null;\n\n return (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-tight\">\n <Text size=\"sm\" bold>\n Workflow sync failed\n </Text>\n <Text size=\"sm\">\n {sync.lastErrorMessage ?? 'The latest workflow sync failed before definitions updated.'}\n </Text>\n </div>\n </Callout>\n );\n}\n\nfunction WorkflowSyncWarnings({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'succeeded' || sync.warnings.length === 0) return null;\n\n const seenKeys = new Map<string, number>();\n const warningItems = sync.warnings.map((warning) => {\n const baseKey = `${warning.code}-${warning.path ?? 'workflow'}-${warning.message}`;\n const occurrence = seenKeys.get(baseKey) ?? 0;\n seenKeys.set(baseKey, occurrence + 1);\n return {key: `${baseKey}-${occurrence}`, warning};\n });\n\n return (\n <Callout role=\"status\" type=\"warning\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Workflow definition warnings\n </Text>\n <ul className=\"flex flex-col gap-tight\">\n {warningItems.map(({key, warning}) => (\n <li key={key}>\n <Text size=\"sm\">{warning.message}</Text>\n {warning.path ? (\n <Code className=\"text-foreground-neutral-muted\">{warning.path}</Code>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n </Callout>\n );\n}\n\nfunction DefinitionSheet({\n definition,\n onOpenChange,\n}: {\n definition: Definition | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const normalizedJson = definition\n ? JSON.stringify(\n {\n workflow_document: definition.workflowDocument,\n workflow_model: definition.workflowModel,\n },\n null,\n 2,\n )\n : '';\n\n return (\n <Sheet open={Boolean(definition)} onOpenChange={onOpenChange}>\n <SheetContent className=\"w-full sm:max-w-[560px]\">\n {definition ? (\n <>\n <SheetHeader>\n <SheetTitle>{definition.name}</SheetTitle>\n <SheetDescription>\n {definition.configPath ?? 'Manual workflow definition'}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-group\">\n <div className=\"grid w-full gap-inline\">\n <Metadata label=\"Definition id\" value={definition.id} />\n <Metadata label=\"Source\" value={definition.source} />\n <Metadata label=\"Ref\" value={definition.ref ?? 'Not set'} />\n <Metadata label=\"SHA\" value={definition.sha ?? 'Not set'} />\n </div>\n <div className=\"flex w-full flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Normalized definition\n </Text>\n <pre className=\"max-h-[52vh] w-full overflow-auto rounded-8 border border-border-neutral-base bg-background-neutral-subtle p-panel-compact scrollbar\">\n <Code as=\"code\" className=\"whitespace-pre text-foreground-neutral-base\">\n {normalizedJson}\n </Code>\n </pre>\n </div>\n </SheetBody>\n </>\n ) : null}\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction Metadata({label, value}: {label: string; value: string}) {\n return (\n <div className=\"min-w-0 py-row first:pt-0 last:pb-0\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n {label}\n </Text>\n <Text size=\"sm\" className=\"break-words\">\n {value}\n </Text>\n </div>\n );\n}\n\nfunction errorMessage(error: unknown, fallback: string) {\n if (error instanceof ApiError && error.message) return error.message;\n if (error instanceof Error && error.message) return error.message;\n return fallback;\n}\n"],"names":["ApiError","SourceStrip","useDefinitionsInfiniteQuery","useProjectQuery","QueryLoadError","Button","Callout","EmptyState","Icon","LoadErrorState","RelativeTime","RelativeTimeProvider","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useState","useFireManualWorkflowMutation","ProjectWorkflowsPage","projectId","ProjectWorkflowsPageInner","projectQuery","definitionsQuery","fireManual","selectedDefinition","setSelectedDefinition","runError","setRunError","definitions","data","pages","flatMap","page","sync","handleRun","definition","manualTrigger","mutateAsync","definitionId","id","success","error","message","errorMessage","div","className","isPending","isError","undefined","status","icon","title","description","query","subject","header","variant","size","connectionId","source","externalRepositoryId","WorkflowSyncAlert","WorkflowSyncWarnings","WorkflowDefinitionsList","runningDefinitionId","variables","hasNextPage","isFetchingNextPage","isFetchNextPageError","onRetry","refetch","onLoadMore","fetchNextPage","onOpenDefinition","onRun","DefinitionSheet","onOpenChange","open","length","retryLabel","WorkflowEmptyState","map","runErrorMessage","isRunning","name","sourceIcon","aria-hidden","button","type","onClick","bold","configPath","value","updatedAt","isLoading","role","lastErrorCode","lastErrorMessage","warnings","seenKeys","Map","warningItems","warning","baseKey","code","path","occurrence","get","set","key","ul","li","normalizedJson","JSON","stringify","workflow_document","workflowDocument","workflow_model","workflowModel","Boolean","Metadata","label","ref","sha","pre","as","fallback","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/project-workflows-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {\n type Definition,\n type DefinitionSyncSummary,\n SourceStrip,\n useDefinitionsInfiniteQuery,\n useProjectQuery,\n} from '@shipfox/client-projects';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LoadErrorState} from '@shipfox/react-ui/load-error-state';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport {useFireManualWorkflowMutation} from '#hooks/api/workflow-runs.js';\n\nexport function ProjectWorkflowsPage({projectId}: {projectId: string}) {\n return (\n <RelativeTimeProvider>\n <ProjectWorkflowsPageInner projectId={projectId} />\n </RelativeTimeProvider>\n );\n}\n\nfunction ProjectWorkflowsPageInner({projectId}: {projectId: string}) {\n const projectQuery = useProjectQuery(projectId);\n const definitionsQuery = useDefinitionsInfiniteQuery(projectId);\n const fireManual = useFireManualWorkflowMutation();\n const [selectedDefinition, setSelectedDefinition] = useState<Definition | null>(null);\n const [runError, setRunError] = useState<{definitionId: string; message: string} | null>(null);\n const definitions = definitionsQuery.data?.pages.flatMap((page) => page.definitions) ?? [];\n const sync = definitionsQuery.data?.pages[0]?.sync;\n\n async function handleRun(definition: Definition) {\n setRunError(null);\n if (!definition.manualTrigger) return;\n try {\n await fireManual.mutateAsync({projectId, definitionId: definition.id});\n toast.success('Run queued');\n } catch (error) {\n const message = errorMessage(error, 'Could not queue run.');\n setRunError({definitionId: definition.id, message});\n toast.error(message);\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n {projectQuery.isPending ? (\n <div className=\"flex flex-col gap-cluster\">\n <Skeleton className=\"h-28 w-1/3\" />\n <Skeleton className=\"h-18 w-1/2\" />\n </div>\n ) : null}\n\n {projectQuery.isError && projectQuery.data === undefined ? (\n projectQuery.error instanceof ApiError && projectQuery.error.status === 404 ? (\n <EmptyState\n icon=\"errorWarningLine\"\n title=\"Project not found\"\n description=\"This project doesn't exist, or you don't have access to it.\"\n />\n ) : (\n <QueryLoadError query={projectQuery} subject=\"project\" />\n )\n ) : null}\n\n {projectQuery.data ? (\n <>\n <header className=\"flex flex-col gap-tight\">\n <Header variant=\"h2\">Workflows</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Synced workflow definitions for this project source.\n </Text>\n </header>\n\n <SourceStrip\n connectionId={projectQuery.data.source.connectionId}\n externalRepositoryId={projectQuery.data.source.externalRepositoryId}\n sync={sync}\n isPending={definitionsQuery.isPending}\n />\n\n <WorkflowSyncAlert sync={sync} />\n <WorkflowSyncWarnings sync={sync} />\n\n <WorkflowDefinitionsList\n definitions={definitions}\n isPending={definitionsQuery.isPending}\n isError={definitionsQuery.isError}\n sync={sync ?? null}\n runError={runError}\n runningDefinitionId={\n fireManual.isPending && fireManual.variables\n ? fireManual.variables.definitionId\n : null\n }\n hasNextPage={definitionsQuery.hasNextPage}\n isFetchingNextPage={definitionsQuery.isFetchingNextPage}\n isFetchNextPageError={definitionsQuery.isFetchNextPageError}\n onRetry={() => definitionsQuery.refetch()}\n onLoadMore={() => definitionsQuery.fetchNextPage()}\n onOpenDefinition={setSelectedDefinition}\n onRun={(definition) => {\n void handleRun(definition);\n }}\n />\n </>\n ) : null}\n\n <DefinitionSheet\n definition={selectedDefinition}\n onOpenChange={(open) => {\n if (!open) setSelectedDefinition(null);\n }}\n />\n </div>\n );\n}\n\nfunction WorkflowDefinitionsList({\n definitions,\n isPending,\n isError,\n sync,\n runError,\n runningDefinitionId,\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onRetry,\n onLoadMore,\n onOpenDefinition,\n onRun,\n}: {\n definitions: Definition[];\n isPending: boolean;\n isError: boolean;\n sync: DefinitionSyncSummary | null;\n runError: {definitionId: string; message: string} | null;\n runningDefinitionId: string | null;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onRetry: () => void;\n onLoadMore: () => void;\n onOpenDefinition: (definition: Definition) => void;\n onRun: (definition: Definition) => void;\n}) {\n if (isPending) {\n return (\n <Panel role=\"status\" aria-label=\"Loading workflows\" className=\"divide-y\">\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n </Panel>\n );\n }\n\n if (isError && definitions.length === 0) {\n return (\n <Panel>\n <LoadErrorState\n title=\"Couldn't load workflows\"\n description=\"Definitions could not be loaded. Source metadata remains visible.\"\n onRetry={onRetry}\n retryLabel=\"Retry loading workflows\"\n variant=\"panel\"\n />\n </Panel>\n );\n }\n\n if (definitions.length === 0) {\n return (\n <Panel>\n <WorkflowEmptyState sync={sync} />\n </Panel>\n );\n }\n\n return (\n <>\n <Panel>\n <div className=\"hidden md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-40\"></TableHead>\n <TableHead>Workflow</TableHead>\n <TableHead className=\"w-180\">Updated</TableHead>\n <TableHead className=\"w-80 text-right\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n // The workflow-name cell holds a `<button>` so the row is\n // keyboard-reachable (Tab focuses, Enter/Space activates\n // via native button semantics). The TableRow itself is no\n // longer clickable: a row-level onClick would be invisible\n // to keyboard users and require custom keydown handling.\n // The `group` class on the row still drives the Run button\n // reveal on hover or focus-within.\n <TableRow key={definition.id} className=\"group\">\n <TableCell>\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n </TableCell>\n <TableCell className=\"max-w-260\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <button\n type=\"button\"\n onClick={() => onOpenDefinition(definition)}\n className=\"flex min-w-0 flex-col gap-tight rounded-4 text-left outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Text size=\"sm\" bold className=\"truncate\">\n {definition.name}\n </Text>\n <Code className=\"truncate text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </button>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={definition.updatedAt} />\n </TableCell>\n <TableCell>\n {definition.manualTrigger ? (\n <div className=\"flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <Button size=\"xs\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n </div>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex flex-col md:hidden\">\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n <div\n key={definition.id}\n className=\"flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0\"\n >\n <button\n type=\"button\"\n className=\"flex min-w-0 items-start gap-inline text-left\"\n onClick={() => onOpenDefinition(definition)}\n >\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 shrink-0 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"sm\" bold className=\"break-words\">\n {definition.name}\n </Text>\n <Code className=\"break-words text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </div>\n </button>\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Updated <RelativeTime value={definition.updatedAt} />\n </Text>\n {definition.manualTrigger ? (\n <Button size=\"sm\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n ) : null}\n </div>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n );\n })}\n </div>\n </Panel>\n\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"sm\">Could not load more workflows.</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={onLoadMore}>\n Retry\n </Button>\n </div>\n </Callout>\n ) : null}\n\n {hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button size=\"sm\" variant=\"secondary\" isLoading={isFetchingNextPage} onClick={onLoadMore}>\n Load more\n </Button>\n </div>\n ) : null}\n </>\n );\n}\n\nfunction sourceIcon(source: 'manual' | 'vcs'): IconName {\n return source === 'vcs' ? ('gitBranchLine' as IconName) : ('terminalLine' as IconName);\n}\n\nfunction WorkflowEmptyState({sync}: {sync: DefinitionSyncSummary | null}) {\n const message =\n sync?.status === 'failed' && sync.lastErrorCode === 'no-workflow-files'\n ? 'No workflow files found under .shipfox/workflows/.'\n : sync?.status === 'failed'\n ? (sync.lastErrorMessage ?? 'Workflow definitions could not be synced.')\n : sync?.status === 'syncing'\n ? 'Workflow definitions are being discovered.'\n : sync?.status === 'succeeded'\n ? 'No workflow definitions found.'\n : 'Workflow sync has not reported yet.';\n\n return <EmptyState icon=\"flowChart\" title=\"No workflows\" description={message} variant=\"panel\" />;\n}\n\nfunction WorkflowSyncAlert({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'failed') return null;\n\n return (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-tight\">\n <Text size=\"sm\" bold>\n Workflow sync failed\n </Text>\n <Text size=\"sm\">\n {sync.lastErrorMessage ?? 'The latest workflow sync failed before definitions updated.'}\n </Text>\n </div>\n </Callout>\n );\n}\n\nfunction WorkflowSyncWarnings({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'succeeded' || sync.warnings.length === 0) return null;\n\n const seenKeys = new Map<string, number>();\n const warningItems = sync.warnings.map((warning) => {\n const baseKey = `${warning.code}-${warning.path ?? 'workflow'}-${warning.message}`;\n const occurrence = seenKeys.get(baseKey) ?? 0;\n seenKeys.set(baseKey, occurrence + 1);\n return {key: `${baseKey}-${occurrence}`, warning};\n });\n\n return (\n <Callout role=\"status\" type=\"warning\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Workflow definition warnings\n </Text>\n <ul className=\"flex flex-col gap-tight\">\n {warningItems.map(({key, warning}) => (\n <li key={key}>\n <Text size=\"sm\">{warning.message}</Text>\n {warning.path ? (\n <Code className=\"text-foreground-neutral-muted\">{warning.path}</Code>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n </Callout>\n );\n}\n\nfunction DefinitionSheet({\n definition,\n onOpenChange,\n}: {\n definition: Definition | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const normalizedJson = definition\n ? JSON.stringify(\n {\n workflow_document: definition.workflowDocument,\n workflow_model: definition.workflowModel,\n },\n null,\n 2,\n )\n : '';\n\n return (\n <Sheet open={Boolean(definition)} onOpenChange={onOpenChange}>\n <SheetContent className=\"w-full sm:max-w-[560px]\">\n {definition ? (\n <>\n <SheetHeader>\n <SheetTitle>{definition.name}</SheetTitle>\n <SheetDescription>\n {definition.configPath ?? 'Manual workflow definition'}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-group\">\n <div className=\"grid w-full gap-inline\">\n <Metadata label=\"Definition id\" value={definition.id} />\n <Metadata label=\"Source\" value={definition.source} />\n <Metadata label=\"Ref\" value={definition.ref ?? 'Not set'} />\n <Metadata label=\"SHA\" value={definition.sha ?? 'Not set'} />\n </div>\n <div className=\"flex w-full flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Normalized definition\n </Text>\n <pre className=\"max-h-[52vh] w-full overflow-auto rounded-8 border border-border-neutral-base bg-background-neutral-subtle p-panel-compact scrollbar\">\n <Code as=\"code\" className=\"whitespace-pre text-foreground-neutral-base\">\n {normalizedJson}\n </Code>\n </pre>\n </div>\n </SheetBody>\n </>\n ) : null}\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction Metadata({label, value}: {label: string; value: string}) {\n return (\n <div className=\"min-w-0 py-row first:pt-0 last:pb-0\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n {label}\n </Text>\n <Text size=\"sm\" className=\"break-words\">\n {value}\n </Text>\n </div>\n );\n}\n\nfunction errorMessage(error: unknown, fallback: string) {\n if (error instanceof ApiError && error.message) return error.message;\n if (error instanceof Error && error.message) return error.message;\n return fallback;\n}\n"],"names":["ApiError","SourceStrip","useDefinitionsInfiniteQuery","useProjectQuery","QueryLoadError","Button","Callout","EmptyState","Icon","LoadErrorState","Panel","RelativeTime","RelativeTimeProvider","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useState","useFireManualWorkflowMutation","ProjectWorkflowsPage","projectId","ProjectWorkflowsPageInner","projectQuery","definitionsQuery","fireManual","selectedDefinition","setSelectedDefinition","runError","setRunError","definitions","data","pages","flatMap","page","sync","handleRun","definition","manualTrigger","mutateAsync","definitionId","id","success","error","message","errorMessage","div","className","isPending","isError","undefined","status","icon","title","description","query","subject","header","variant","size","connectionId","source","externalRepositoryId","WorkflowSyncAlert","WorkflowSyncWarnings","WorkflowDefinitionsList","runningDefinitionId","variables","hasNextPage","isFetchingNextPage","isFetchNextPageError","onRetry","refetch","onLoadMore","fetchNextPage","onOpenDefinition","onRun","DefinitionSheet","onOpenChange","open","role","aria-label","length","retryLabel","WorkflowEmptyState","map","runErrorMessage","isRunning","name","sourceIcon","aria-hidden","button","type","onClick","bold","configPath","value","updatedAt","isLoading","lastErrorCode","lastErrorMessage","warnings","seenKeys","Map","warningItems","warning","baseKey","code","path","occurrence","get","set","key","ul","li","normalizedJson","JSON","stringify","workflow_document","workflowDocument","workflow_model","workflowModel","Boolean","Metadata","label","ref","sha","pre","as","fallback","Error"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-job-detail-page.d.ts","sourceRoot":"","sources":["../../src/pages/workflow-job-detail-page.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAC,KAAK,iBAAiB,EAA0B,MAAM,mBAAmB,CAAC;AAElF,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,EACL,MAAW,GACZ,EAAE,0BAA0B,+BA2D5B"}
1
+ {"version":3,"file":"workflow-job-detail-page.d.ts","sourceRoot":"","sources":["../../src/pages/workflow-job-detail-page.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAC,KAAK,iBAAiB,EAA0B,MAAM,mBAAmB,CAAC;AAElF,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,EACL,MAAW,GACZ,EAAE,0BAA0B,+BA+D5B"}
@@ -39,7 +39,8 @@ export function WorkflowJobDetailPage({ projectId, workspaceSlug, projectSlug, w
39
39
  navigate
40
40
  ]);
41
41
  return /*#__PURE__*/ _jsx("div", {
42
- className: "flex min-h-0 flex-1 overflow-hidden bg-background-neutral-background",
42
+ "data-workflow-page-root": "job-detail",
43
+ className: "flex min-h-0 min-w-0 flex-1 overflow-hidden",
43
44
  children: /*#__PURE__*/ _jsx(WorkflowRunView, {
44
45
  projectId: projectId,
45
46
  workspaceSlug: workspaceSlug,
@@ -58,7 +59,7 @@ export function WorkflowJobDetailPage({ projectId, workspaceSlug, projectSlug, w
58
59
  newerAttempt: newerAttempt,
59
60
  newerJob: newerJob,
60
61
  onSelectionChange: onSelectionChange
61
- })
62
+ }, jobId)
62
63
  })
63
64
  });
64
65
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/workflow-job-detail-page.tsx"],"sourcesContent":["import {useNavigate} from '@tanstack/react-router';\nimport {useCallback, useMemo} from 'react';\nimport {JobDetailView} from '#components/job-detail/job-detail-view.js';\nimport {WorkflowRunView} from '#components/workflow-run-view/index.js';\nimport {isWorkflowRunTerminal} from '#core/workflow-run.js';\nimport {useWorkflowRunAttemptQuery, useWorkflowRunAttemptsQuery} from '#hooks/api/workflow-runs.js';\nimport {type WorkflowJobSearch, workflowJobSearchParams} from '#routes/inputs.js';\n\nexport interface WorkflowJobDetailPageProps {\n projectId: string;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n jobId: string;\n search?: WorkflowJobSearch;\n}\n\nexport function WorkflowJobDetailPage({\n projectId,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n jobId,\n search = {},\n}: WorkflowJobDetailPageProps) {\n const navigate = useNavigate();\n const runQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: search.runAttempt,\n });\n const attemptsQuery = useWorkflowRunAttemptsQuery({\n workflowRunId,\n enabled: Boolean(runQuery.data && isWorkflowRunTerminal(runQuery.data.runAttempt.status)),\n });\n const newerAttempt = useMemo(() => {\n const currentAttempt = runQuery.data?.runAttempt.attempt ?? search.runAttempt ?? 1;\n return attemptsQuery.data\n ?.filter((attempt) => attempt.attempt > currentAttempt)\n .sort((left, right) => right.attempt - left.attempt)[0]?.attempt;\n }, [attemptsQuery.data, runQuery.data?.runAttempt.attempt, search.runAttempt]);\n const newerRunQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: newerAttempt,\n enabled: newerAttempt !== undefined,\n });\n\n const currentJobKey = runQuery.data?.jobs.find((job) => job.id === jobId)?.key;\n const newerJob = currentJobKey\n ? newerRunQuery.data?.jobs.find((job) => job.key === currentJobKey)\n : undefined;\n\n const onSelectionChange = useCallback(\n (nextSelection: WorkflowJobSearch) => {\n navigate({search: workflowJobSearchParams(nextSelection) as never});\n },\n [navigate],\n );\n return (\n <div className=\"flex min-h-0 flex-1 overflow-hidden bg-background-neutral-background\">\n <WorkflowRunView\n projectId={projectId}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={search.runAttempt}\n activeJobId={jobId}\n jobSearch={search}\n jobContent={\n <JobDetailView\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n jobId={jobId}\n search={search}\n query={runQuery}\n newerAttempt={newerAttempt}\n newerJob={newerJob}\n onSelectionChange={onSelectionChange}\n />\n }\n />\n </div>\n );\n}\n"],"names":["useNavigate","useCallback","useMemo","JobDetailView","WorkflowRunView","isWorkflowRunTerminal","useWorkflowRunAttemptQuery","useWorkflowRunAttemptsQuery","workflowJobSearchParams","WorkflowJobDetailPage","projectId","workspaceSlug","projectSlug","workflowRunId","jobId","search","navigate","runQuery","runAttempt","attemptsQuery","enabled","Boolean","data","status","newerAttempt","currentAttempt","attempt","filter","sort","left","right","newerRunQuery","undefined","currentJobKey","jobs","find","job","id","key","newerJob","onSelectionChange","nextSelection","div","className","activeJobId","jobSearch","jobContent","query"],"mappings":";AAAA,SAAQA,WAAW,QAAO,yBAAyB;AACnD,SAAQC,WAAW,EAAEC,OAAO,QAAO,QAAQ;AAC3C,SAAQC,aAAa,QAAO,4CAA4C;AACxE,SAAQC,eAAe,QAAO,yCAAyC;AACvE,SAAQC,qBAAqB,QAAO,wBAAwB;AAC5D,SAAQC,0BAA0B,EAAEC,2BAA2B,QAAO,8BAA8B;AACpG,SAAgCC,uBAAuB,QAAO,oBAAoB;AAWlF,OAAO,SAASC,sBAAsB,EACpCC,SAAS,EACTC,aAAa,EACbC,WAAW,EACXC,aAAa,EACbC,KAAK,EACLC,SAAS,CAAC,CAAC,EACgB;IAC3B,MAAMC,WAAWhB;IACjB,MAAMiB,WAAWX,2BAA2B;QAC1CO;QACAK,YAAYH,OAAOG,UAAU;IAC/B;IACA,MAAMC,gBAAgBZ,4BAA4B;QAChDM;QACAO,SAASC,QAAQJ,SAASK,IAAI,IAAIjB,sBAAsBY,SAASK,IAAI,CAACJ,UAAU,CAACK,MAAM;IACzF;IACA,MAAMC,eAAetB,QAAQ;QAC3B,MAAMuB,iBAAiBR,SAASK,IAAI,EAAEJ,WAAWQ,WAAWX,OAAOG,UAAU,IAAI;QACjF,OAAOC,cAAcG,IAAI,EACrBK,OAAO,CAACD,UAAYA,QAAQA,OAAO,GAAGD,gBACvCG,KAAK,CAACC,MAAMC,QAAUA,MAAMJ,OAAO,GAAGG,KAAKH,OAAO,CAAC,CAAC,EAAE,EAAEA;IAC7D,GAAG;QAACP,cAAcG,IAAI;QAAEL,SAASK,IAAI,EAAEJ,WAAWQ;QAASX,OAAOG,UAAU;KAAC;IAC7E,MAAMa,gBAAgBzB,2BAA2B;QAC/CO;QACAK,YAAYM;QACZJ,SAASI,iBAAiBQ;IAC5B;IAEA,MAAMC,gBAAgBhB,SAASK,IAAI,EAAEY,KAAKC,KAAK,CAACC,MAAQA,IAAIC,EAAE,KAAKvB,QAAQwB;IAC3E,MAAMC,WAAWN,gBACbF,cAAcT,IAAI,EAAEY,KAAKC,KAAK,CAACC,MAAQA,IAAIE,GAAG,KAAKL,iBACnDD;IAEJ,MAAMQ,oBAAoBvC,YACxB,CAACwC;QACCzB,SAAS;YAACD,QAAQP,wBAAwBiC;QAAuB;IACnE,GACA;QAACzB;KAAS;IAEZ,qBACE,KAAC0B;QAAIC,WAAU;kBACb,cAAA,KAACvC;YACCM,WAAWA;YACXC,eAAeA;YACfC,aAAaA;YACbC,eAAeA;YACfK,YAAYH,OAAOG,UAAU;YAC7B0B,aAAa9B;YACb+B,WAAW9B;YACX+B,0BACE,KAAC3C;gBACCQ,eAAeA;gBACfC,aAAaA;gBACbC,eAAeA;gBACfC,OAAOA;gBACPC,QAAQA;gBACRgC,OAAO9B;gBACPO,cAAcA;gBACde,UAAUA;gBACVC,mBAAmBA;;;;AAM/B"}
1
+ {"version":3,"sources":["../../src/pages/workflow-job-detail-page.tsx"],"sourcesContent":["import {useNavigate} from '@tanstack/react-router';\nimport {useCallback, useMemo} from 'react';\nimport {JobDetailView} from '#components/job-detail/job-detail-view.js';\nimport {WorkflowRunView} from '#components/workflow-run-view/index.js';\nimport {isWorkflowRunTerminal} from '#core/workflow-run.js';\nimport {useWorkflowRunAttemptQuery, useWorkflowRunAttemptsQuery} from '#hooks/api/workflow-runs.js';\nimport {type WorkflowJobSearch, workflowJobSearchParams} from '#routes/inputs.js';\n\nexport interface WorkflowJobDetailPageProps {\n projectId: string;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n jobId: string;\n search?: WorkflowJobSearch;\n}\n\nexport function WorkflowJobDetailPage({\n projectId,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n jobId,\n search = {},\n}: WorkflowJobDetailPageProps) {\n const navigate = useNavigate();\n const runQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: search.runAttempt,\n });\n const attemptsQuery = useWorkflowRunAttemptsQuery({\n workflowRunId,\n enabled: Boolean(runQuery.data && isWorkflowRunTerminal(runQuery.data.runAttempt.status)),\n });\n const newerAttempt = useMemo(() => {\n const currentAttempt = runQuery.data?.runAttempt.attempt ?? search.runAttempt ?? 1;\n return attemptsQuery.data\n ?.filter((attempt) => attempt.attempt > currentAttempt)\n .sort((left, right) => right.attempt - left.attempt)[0]?.attempt;\n }, [attemptsQuery.data, runQuery.data?.runAttempt.attempt, search.runAttempt]);\n const newerRunQuery = useWorkflowRunAttemptQuery({\n workflowRunId,\n runAttempt: newerAttempt,\n enabled: newerAttempt !== undefined,\n });\n\n const currentJobKey = runQuery.data?.jobs.find((job) => job.id === jobId)?.key;\n const newerJob = currentJobKey\n ? newerRunQuery.data?.jobs.find((job) => job.key === currentJobKey)\n : undefined;\n\n const onSelectionChange = useCallback(\n (nextSelection: WorkflowJobSearch) => {\n navigate({search: workflowJobSearchParams(nextSelection) as never});\n },\n [navigate],\n );\n return (\n <div\n data-workflow-page-root=\"job-detail\"\n className=\"flex min-h-0 min-w-0 flex-1 overflow-hidden\"\n >\n <WorkflowRunView\n projectId={projectId}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={search.runAttempt}\n activeJobId={jobId}\n jobSearch={search}\n jobContent={\n <JobDetailView\n key={jobId}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n jobId={jobId}\n search={search}\n query={runQuery}\n newerAttempt={newerAttempt}\n newerJob={newerJob}\n onSelectionChange={onSelectionChange}\n />\n }\n />\n </div>\n );\n}\n"],"names":["useNavigate","useCallback","useMemo","JobDetailView","WorkflowRunView","isWorkflowRunTerminal","useWorkflowRunAttemptQuery","useWorkflowRunAttemptsQuery","workflowJobSearchParams","WorkflowJobDetailPage","projectId","workspaceSlug","projectSlug","workflowRunId","jobId","search","navigate","runQuery","runAttempt","attemptsQuery","enabled","Boolean","data","status","newerAttempt","currentAttempt","attempt","filter","sort","left","right","newerRunQuery","undefined","currentJobKey","jobs","find","job","id","key","newerJob","onSelectionChange","nextSelection","div","data-workflow-page-root","className","activeJobId","jobSearch","jobContent","query"],"mappings":";AAAA,SAAQA,WAAW,QAAO,yBAAyB;AACnD,SAAQC,WAAW,EAAEC,OAAO,QAAO,QAAQ;AAC3C,SAAQC,aAAa,QAAO,4CAA4C;AACxE,SAAQC,eAAe,QAAO,yCAAyC;AACvE,SAAQC,qBAAqB,QAAO,wBAAwB;AAC5D,SAAQC,0BAA0B,EAAEC,2BAA2B,QAAO,8BAA8B;AACpG,SAAgCC,uBAAuB,QAAO,oBAAoB;AAWlF,OAAO,SAASC,sBAAsB,EACpCC,SAAS,EACTC,aAAa,EACbC,WAAW,EACXC,aAAa,EACbC,KAAK,EACLC,SAAS,CAAC,CAAC,EACgB;IAC3B,MAAMC,WAAWhB;IACjB,MAAMiB,WAAWX,2BAA2B;QAC1CO;QACAK,YAAYH,OAAOG,UAAU;IAC/B;IACA,MAAMC,gBAAgBZ,4BAA4B;QAChDM;QACAO,SAASC,QAAQJ,SAASK,IAAI,IAAIjB,sBAAsBY,SAASK,IAAI,CAACJ,UAAU,CAACK,MAAM;IACzF;IACA,MAAMC,eAAetB,QAAQ;QAC3B,MAAMuB,iBAAiBR,SAASK,IAAI,EAAEJ,WAAWQ,WAAWX,OAAOG,UAAU,IAAI;QACjF,OAAOC,cAAcG,IAAI,EACrBK,OAAO,CAACD,UAAYA,QAAQA,OAAO,GAAGD,gBACvCG,KAAK,CAACC,MAAMC,QAAUA,MAAMJ,OAAO,GAAGG,KAAKH,OAAO,CAAC,CAAC,EAAE,EAAEA;IAC7D,GAAG;QAACP,cAAcG,IAAI;QAAEL,SAASK,IAAI,EAAEJ,WAAWQ;QAASX,OAAOG,UAAU;KAAC;IAC7E,MAAMa,gBAAgBzB,2BAA2B;QAC/CO;QACAK,YAAYM;QACZJ,SAASI,iBAAiBQ;IAC5B;IAEA,MAAMC,gBAAgBhB,SAASK,IAAI,EAAEY,KAAKC,KAAK,CAACC,MAAQA,IAAIC,EAAE,KAAKvB,QAAQwB;IAC3E,MAAMC,WAAWN,gBACbF,cAAcT,IAAI,EAAEY,KAAKC,KAAK,CAACC,MAAQA,IAAIE,GAAG,KAAKL,iBACnDD;IAEJ,MAAMQ,oBAAoBvC,YACxB,CAACwC;QACCzB,SAAS;YAACD,QAAQP,wBAAwBiC;QAAuB;IACnE,GACA;QAACzB;KAAS;IAEZ,qBACE,KAAC0B;QACCC,2BAAwB;QACxBC,WAAU;kBAEV,cAAA,KAACxC;YACCM,WAAWA;YACXC,eAAeA;YACfC,aAAaA;YACbC,eAAeA;YACfK,YAAYH,OAAOG,UAAU;YAC7B2B,aAAa/B;YACbgC,WAAW/B;YACXgC,0BACE,KAAC5C;gBAECQ,eAAeA;gBACfC,aAAaA;gBACbC,eAAeA;gBACfC,OAAOA;gBACPC,QAAQA;gBACRiC,OAAO/B;gBACPO,cAAcA;gBACde,UAAUA;gBACVC,mBAAmBA;eATd1B;;;AAejB"}
@@ -3,7 +3,8 @@ import { WorkflowRunView } from '#components/workflow-run-view/index.js';
3
3
  import { workflowRunTab } from '#routes/inputs.js';
4
4
  export function WorkflowRunDetailPage({ projectId, workspaceSlug, projectSlug, workflowRunId, search = {} }) {
5
5
  return /*#__PURE__*/ _jsx("div", {
6
- className: "flex min-h-0 flex-1 overflow-hidden bg-background-neutral-background",
6
+ "data-workflow-page-root": "run-detail",
7
+ className: "flex min-h-0 flex-1 overflow-hidden",
7
8
  children: /*#__PURE__*/ _jsx(WorkflowRunView, {
8
9
  projectId: projectId,
9
10
  workspaceSlug: workspaceSlug,