@shipfox/client-workflows 21.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 (48) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +22 -0
  3. package/dist/components/job-detail/job-detail-view.js +1 -2
  4. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  5. package/dist/components/job-detail/job-empty-states.js +2 -2
  6. package/dist/components/job-detail/job-empty-states.js.map +1 -1
  7. package/dist/components/job-graph/job-graph-content.js +2 -2
  8. package/dist/components/job-graph/job-graph-content.js.map +1 -1
  9. package/dist/components/step-list/step-list.js +1 -2
  10. package/dist/components/step-list/step-list.js.map +1 -1
  11. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
  12. package/dist/components/workflow-run-list/workflow-run-list-content.js +13 -7
  13. package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
  14. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
  15. package/dist/components/workflow-run-list/workflow-run-list-states.js +42 -37
  16. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  17. package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
  18. package/dist/components/workflow-run-list/workflow-run-row.js +14 -10
  19. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  20. package/dist/components/workflow-run-summary/workflow-run-summary.js +3 -3
  21. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  22. package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
  23. package/dist/components/workflow-run-view/run-workspace-nav.js +20 -7
  24. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  25. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  26. package/dist/components/workflow-run-view/workflow-run-view.js +68 -50
  27. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  28. package/dist/pages/project-workflows-page.js +170 -158
  29. package/dist/pages/project-workflows-page.js.map +1 -1
  30. package/dist/tsconfig.test.tsbuildinfo +1 -1
  31. package/package.json +8 -8
  32. package/src/components/job-detail/job-detail-view.tsx +1 -2
  33. package/src/components/job-detail/job-empty-states.tsx +2 -2
  34. package/src/components/job-graph/job-graph-content.tsx +2 -2
  35. package/src/components/step-list/step-list.tsx +1 -2
  36. package/src/components/workflow-run-list/workflow-run-list-content.tsx +7 -2
  37. package/src/components/workflow-run-list/workflow-run-list-states.tsx +41 -40
  38. package/src/components/workflow-run-list/workflow-run-row.tsx +11 -8
  39. package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +1 -1
  40. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +9 -1
  41. package/src/components/workflow-run-summary/workflow-run-summary.tsx +3 -3
  42. package/src/components/workflow-run-view/run-workspace-nav.test.tsx +40 -2
  43. package/src/components/workflow-run-view/run-workspace-nav.tsx +28 -9
  44. package/src/components/workflow-run-view/workflow-run-view.stories.tsx +3 -1
  45. package/src/components/workflow-run-view/workflow-run-view.test.tsx +11 -8
  46. package/src/components/workflow-run-view/workflow-run-view.tsx +78 -70
  47. package/src/pages/project-workflows-page.tsx +134 -125
  48. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,6 +1,7 @@
1
1
  import {ApiError} from '@shipfox/client-api';
2
2
  import {QueryLoadError} from '@shipfox/client-ui';
3
3
  import {EmptyState} from '@shipfox/react-ui/empty-state';
4
+ import {Panel, PanelBody, PanelHeader} from '@shipfox/react-ui/panel';
4
5
  import {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';
5
6
  import {
6
7
  Select,
@@ -11,7 +12,6 @@ import {
11
12
  } from '@shipfox/react-ui/select';
12
13
  import {toast} from '@shipfox/react-ui/toast';
13
14
  import {Text} from '@shipfox/react-ui/typography';
14
- import {cn} from '@shipfox/react-ui/utils';
15
15
  import {useNavigate} from '@tanstack/react-router';
16
16
  import {type ReactNode, useEffect, useMemo} from 'react';
17
17
  import {buildRunAnnotationList, type RunAnnotationSummary} from '#core/run-annotation.js';
@@ -54,7 +54,6 @@ import {
54
54
  } from './workflow-run-states.js';
55
55
 
56
56
  type RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;
57
- const RUN_WORKSPACE_FRAME_CLASS_NAME = 'mx-auto w-full max-w-[calc(240px_+_1120px)]';
58
57
 
59
58
  export interface WorkflowRunViewProps {
60
59
  projectId: string;
@@ -159,7 +158,6 @@ function RunViewContent({
159
158
  const activeSection = runWorkspaceSection(tab);
160
159
  const cancelMutation = useCancelWorkflowRunMutation(runData);
161
160
  const sourceSnapshot = runData?.sourceSnapshot ?? null;
162
- const hasJobContent = Boolean(jobContent);
163
161
  const resolvedSelection =
164
162
  runData && selection ? resolveWorkflowRunSelection({run: runData, selection}) : undefined;
165
163
  const highlightedLineRange = resolvedSelection?.step?.sourceLocation ?? null;
@@ -316,10 +314,7 @@ function RunViewContent({
316
314
  >
317
315
  <div
318
316
  data-run-workspace-frame
319
- className={cn(
320
- 'flex min-h-0 min-w-0 w-full flex-1 flex-col min-[768px]:flex-row',
321
- !hasJobContent && RUN_WORKSPACE_FRAME_CLASS_NAME,
322
- )}
317
+ className="flex min-h-0 min-w-0 w-full flex-1 flex-col min-[768px]:flex-row"
323
318
  >
324
319
  {runData && workspaceSlug && projectSlug ? (
325
320
  <RunWorkspaceNav
@@ -403,16 +398,20 @@ function RunSectionContent({
403
398
  aria-label="All jobs summary"
404
399
  className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
405
400
  >
406
- <div className="mx-auto flex w-full flex-col gap-group px-frame">
401
+ <div className="flex w-full flex-col gap-group">
407
402
  <Text as="h2" className="sr-only">
408
403
  All jobs summary
409
404
  </Text>
410
- <JobGraph
411
- run={run}
412
- selectedJobId={selectedJobId}
413
- onSelectedJobChange={onSelectGraphJob}
414
- className="min-h-160 overflow-hidden"
415
- />
405
+ <Panel className="min-h-160">
406
+ <PanelBody className="min-h-160 bg-background-components-base p-0">
407
+ <JobGraph
408
+ run={run}
409
+ selectedJobId={selectedJobId}
410
+ onSelectedJobChange={onSelectGraphJob}
411
+ className="min-h-160 overflow-hidden"
412
+ />
413
+ </PanelBody>
414
+ </Panel>
416
415
  </div>
417
416
  </section>
418
417
  );
@@ -439,28 +438,33 @@ function RunSectionContent({
439
438
  aria-label="Workflow source"
440
439
  className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
441
440
  >
442
- <div className="mx-auto flex min-h-full w-full flex-col px-frame">
441
+ <div className="flex min-h-full w-full flex-col">
443
442
  <Text as="h2" className="sr-only">
444
443
  Workflow source
445
444
  </Text>
446
- {sourceSnapshot ? (
447
- <WorkflowSourceContent
448
- source={sourceSnapshot}
449
- highlightedLineRange={highlightedLineRange}
450
- scrollHighlightedIntoView
451
- />
452
- ) : (
453
- <EmptyState
454
- className="min-h-160 w-full"
455
- icon="fileDamageLine"
456
- title="Source snapshot unavailable"
457
- description={
458
- run.isTemporary
459
- ? 'Temporary runs do not capture workflow source.'
460
- : 'This run was created before workflow source snapshots were captured.'
461
- }
462
- />
463
- )}
445
+ <Panel className="min-h-160 flex-1">
446
+ <PanelBody className="min-h-160 flex-1 p-0">
447
+ {sourceSnapshot ? (
448
+ <WorkflowSourceContent
449
+ source={sourceSnapshot}
450
+ highlightedLineRange={highlightedLineRange}
451
+ scrollHighlightedIntoView
452
+ />
453
+ ) : (
454
+ <EmptyState
455
+ variant="panel"
456
+ className="min-h-160"
457
+ icon="fileDamageLine"
458
+ title="Source snapshot unavailable"
459
+ description={
460
+ run.isTemporary
461
+ ? 'Temporary runs do not capture workflow source.'
462
+ : 'This run was created before workflow source snapshots were captured.'
463
+ }
464
+ />
465
+ )}
466
+ </PanelBody>
467
+ </Panel>
464
468
  </div>
465
469
  </section>
466
470
  );
@@ -534,45 +538,49 @@ function RunAnnotationsSection({
534
538
  aria-label="Run annotations"
535
539
  className="min-h-0 flex-1 overflow-auto pb-panel pt-[16px]"
536
540
  >
537
- <div className="mx-auto flex w-full flex-col gap-group px-frame">
541
+ <div className="flex w-full flex-col">
538
542
  <Text as="h2" className="sr-only">
539
543
  Annotations
540
544
  </Text>
541
- <div className="flex flex-wrap items-center justify-between gap-inline">
542
- <RunAnnotationSummaryLine
543
- summary={annotationSummary}
544
- workspaceSlug={workspaceSlug}
545
- projectSlug={projectSlug}
546
- workflowRunId={run.id}
547
- search={selection}
548
- />
549
- <AnnotationJobFilter
550
- jobs={run.jobs}
551
- selectedJobId={selectedJob?.id}
552
- onSelect={onSelectAnnotationJob}
553
- />
554
- </div>
555
- <RunAnnotationList
556
- // Remounting on a filter or run-attempt change resets the render window, so the next
557
- // list never inherits a "show more" position from different data.
558
- key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}
559
- query={annotations.query}
560
- entries={entries}
561
- derivedAnnotations={derivedAnnotations}
562
- workspaceSlug={workspaceSlug}
563
- projectSlug={projectSlug}
564
- workflowRunId={run.id}
565
- runAttempt={run.runAttempt.attempt}
566
- // A run with no annotations at all offers no filter to clear, whatever the URL says.
567
- filtered={Boolean(
568
- (severity || selectedJob || selection?.annotation) &&
569
- ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations),
570
- )}
571
- filteredJobName={selectedJob?.displayName}
572
- filteredSeverity={severity}
573
- onClearFilters={onClearAnnotationFilters}
574
- selectedAnnotationId={selection?.annotation}
575
- />
545
+ <Panel>
546
+ <PanelHeader className="flex-wrap">
547
+ <RunAnnotationSummaryLine
548
+ summary={annotationSummary}
549
+ workspaceSlug={workspaceSlug}
550
+ projectSlug={projectSlug}
551
+ workflowRunId={run.id}
552
+ search={selection}
553
+ />
554
+ <AnnotationJobFilter
555
+ jobs={run.jobs}
556
+ selectedJobId={selectedJob?.id}
557
+ onSelect={onSelectAnnotationJob}
558
+ />
559
+ </PanelHeader>
560
+ <PanelBody className="gap-group p-panel">
561
+ <RunAnnotationList
562
+ // Remounting on a filter or run-attempt change resets the render window, so the next
563
+ // list never inherits a "show more" position from different data.
564
+ key={`${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`}
565
+ query={annotations.query}
566
+ entries={entries}
567
+ derivedAnnotations={derivedAnnotations}
568
+ workspaceSlug={workspaceSlug}
569
+ projectSlug={projectSlug}
570
+ workflowRunId={run.id}
571
+ runAttempt={run.runAttempt.attempt}
572
+ // A run with no annotations at all offers no filter to clear, whatever the URL says.
573
+ filtered={Boolean(
574
+ (severity || selectedJob || selection?.annotation) &&
575
+ ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations),
576
+ )}
577
+ filteredJobName={selectedJob?.displayName}
578
+ filteredSeverity={severity}
579
+ onClearFilters={onClearAnnotationFilters}
580
+ selectedAnnotationId={selection?.annotation}
581
+ />
582
+ </PanelBody>
583
+ </Panel>
576
584
  </div>
577
585
  </section>
578
586
  );
@@ -674,7 +682,7 @@ function RunWorkspaceNavSkeleton() {
674
682
  return (
675
683
  <aside
676
684
  aria-label="Loading run navigation"
677
- className="hidden w-240 shrink-0 border-r border-border-neutral-base p-panel-compact min-[768px]:block"
685
+ className="hidden w-240 shrink-0 p-panel-compact min-[768px]:block"
678
686
  >
679
687
  <div className="flex flex-col gap-group">
680
688
  <div className="h-32 rounded-4 bg-background-components-subtle" />
@@ -171,152 +171,161 @@ function WorkflowDefinitionsList({
171
171
  }) {
172
172
  if (isPending) {
173
173
  return (
174
- <div className="flex flex-col gap-inline">
175
- <Skeleton className="h-40 w-full" />
176
- <Skeleton className="h-40 w-full" />
177
- <Skeleton className="h-40 w-full" />
178
- </div>
174
+ <Panel role="status" aria-label="Loading workflows" className="divide-y">
175
+ <Skeleton className="h-44 w-full rounded-none" />
176
+ <Skeleton className="h-44 w-full rounded-none" />
177
+ <Skeleton className="h-44 w-full rounded-none" />
178
+ </Panel>
179
179
  );
180
180
  }
181
181
 
182
182
  if (isError && definitions.length === 0) {
183
183
  return (
184
- <LoadErrorState
185
- title="Couldn't load workflows"
186
- description="Definitions could not be loaded. Source metadata remains visible."
187
- onRetry={onRetry}
188
- retryLabel="Retry loading workflows"
189
- />
184
+ <Panel>
185
+ <LoadErrorState
186
+ title="Couldn't load workflows"
187
+ description="Definitions could not be loaded. Source metadata remains visible."
188
+ onRetry={onRetry}
189
+ retryLabel="Retry loading workflows"
190
+ variant="panel"
191
+ />
192
+ </Panel>
190
193
  );
191
194
  }
192
195
 
193
196
  if (definitions.length === 0) {
194
- return <WorkflowEmptyState sync={sync} />;
197
+ return (
198
+ <Panel>
199
+ <WorkflowEmptyState sync={sync} />
200
+ </Panel>
201
+ );
195
202
  }
196
203
 
197
204
  return (
198
205
  <>
199
- <Panel className="hidden md:flex">
200
- <Table>
201
- <TableHeader>
202
- <TableRow>
203
- <TableHead className="w-40"></TableHead>
204
- <TableHead>Workflow</TableHead>
205
- <TableHead className="w-180">Updated</TableHead>
206
- <TableHead className="w-80 text-right"></TableHead>
207
- </TableRow>
208
- </TableHeader>
209
- <TableBody>
210
- {definitions.map((definition) => {
211
- const runErrorMessage =
212
- runError?.definitionId === definition.id ? runError.message : null;
213
- const isRunning = runningDefinitionId === definition.id;
206
+ <Panel>
207
+ <div className="hidden md:block">
208
+ <Table>
209
+ <TableHeader>
210
+ <TableRow>
211
+ <TableHead className="w-40"></TableHead>
212
+ <TableHead>Workflow</TableHead>
213
+ <TableHead className="w-180">Updated</TableHead>
214
+ <TableHead className="w-80 text-right"></TableHead>
215
+ </TableRow>
216
+ </TableHeader>
217
+ <TableBody>
218
+ {definitions.map((definition) => {
219
+ const runErrorMessage =
220
+ runError?.definitionId === definition.id ? runError.message : null;
221
+ const isRunning = runningDefinitionId === definition.id;
214
222
 
215
- return (
216
- // The workflow-name cell holds a `<button>` so the row is
217
- // keyboard-reachable (Tab focuses, Enter/Space activates
218
- // via native button semantics). The TableRow itself is no
219
- // longer clickable: a row-level onClick would be invisible
220
- // to keyboard users and require custom keydown handling.
221
- // The `group` class on the row still drives the Run button
222
- // reveal on hover or focus-within.
223
- <TableRow key={definition.id} className="group">
224
- <TableCell>
225
- <Icon
226
- name={sourceIcon(definition.source)}
227
- className="size-16 text-foreground-neutral-muted"
228
- aria-hidden="true"
229
- />
230
- </TableCell>
231
- <TableCell className="max-w-260">
232
- <div className="flex min-w-0 flex-col gap-tight">
233
- <button
234
- type="button"
235
- onClick={() => onOpenDefinition(definition)}
236
- className="flex min-w-0 flex-col gap-tight text-left outline-none focus-visible:shadow-border-interactive-with-active rounded-4"
237
- >
238
- <Text size="sm" bold className="truncate">
239
- {definition.name}
240
- </Text>
241
- <Code className="truncate text-foreground-neutral-muted">
242
- {definition.configPath ?? 'Manual definition'}
243
- </Code>
244
- </button>
245
- {runErrorMessage ? (
246
- <Text size="xs" className="text-tag-error-text">
247
- {runErrorMessage}
248
- </Text>
249
- ) : null}
250
- </div>
251
- </TableCell>
252
- <TableCell className="text-foreground-neutral-muted">
253
- <RelativeTime value={definition.updatedAt} />
254
- </TableCell>
255
- <TableCell>
256
- {definition.manualTrigger ? (
257
- <div className="flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
258
- <Button size="xs" isLoading={isRunning} onClick={() => onRun(definition)}>
259
- Run
260
- </Button>
223
+ return (
224
+ // The workflow-name cell holds a `<button>` so the row is
225
+ // keyboard-reachable (Tab focuses, Enter/Space activates
226
+ // via native button semantics). The TableRow itself is no
227
+ // longer clickable: a row-level onClick would be invisible
228
+ // to keyboard users and require custom keydown handling.
229
+ // The `group` class on the row still drives the Run button
230
+ // reveal on hover or focus-within.
231
+ <TableRow key={definition.id} className="group">
232
+ <TableCell>
233
+ <Icon
234
+ name={sourceIcon(definition.source)}
235
+ className="size-16 text-foreground-neutral-muted"
236
+ aria-hidden="true"
237
+ />
238
+ </TableCell>
239
+ <TableCell className="max-w-260">
240
+ <div className="flex min-w-0 flex-col gap-tight">
241
+ <button
242
+ type="button"
243
+ onClick={() => onOpenDefinition(definition)}
244
+ className="flex min-w-0 flex-col gap-tight rounded-4 text-left outline-none focus-visible:shadow-border-interactive-with-active"
245
+ >
246
+ <Text size="sm" bold className="truncate">
247
+ {definition.name}
248
+ </Text>
249
+ <Code className="truncate text-foreground-neutral-muted">
250
+ {definition.configPath ?? 'Manual definition'}
251
+ </Code>
252
+ </button>
253
+ {runErrorMessage ? (
254
+ <Text size="xs" className="text-tag-error-text">
255
+ {runErrorMessage}
256
+ </Text>
257
+ ) : null}
261
258
  </div>
262
- ) : null}
263
- </TableCell>
264
- </TableRow>
265
- );
266
- })}
267
- </TableBody>
268
- </Table>
269
- </Panel>
259
+ </TableCell>
260
+ <TableCell className="text-foreground-neutral-muted">
261
+ <RelativeTime value={definition.updatedAt} />
262
+ </TableCell>
263
+ <TableCell>
264
+ {definition.manualTrigger ? (
265
+ <div className="flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
266
+ <Button size="xs" isLoading={isRunning} onClick={() => onRun(definition)}>
267
+ Run
268
+ </Button>
269
+ </div>
270
+ ) : null}
271
+ </TableCell>
272
+ </TableRow>
273
+ );
274
+ })}
275
+ </TableBody>
276
+ </Table>
277
+ </div>
270
278
 
271
- <div className="flex flex-col rounded-8 border border-border-neutral-base md:hidden">
272
- {definitions.map((definition) => {
273
- const runErrorMessage =
274
- runError?.definitionId === definition.id ? runError.message : null;
275
- const isRunning = runningDefinitionId === definition.id;
279
+ <div className="flex flex-col md:hidden">
280
+ {definitions.map((definition) => {
281
+ const runErrorMessage =
282
+ runError?.definitionId === definition.id ? runError.message : null;
283
+ const isRunning = runningDefinitionId === definition.id;
276
284
 
277
- return (
278
- <div
279
- key={definition.id}
280
- className="flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0"
281
- >
282
- <button
283
- type="button"
284
- className="flex min-w-0 items-start gap-inline text-left"
285
- onClick={() => onOpenDefinition(definition)}
285
+ return (
286
+ <div
287
+ key={definition.id}
288
+ className="flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0"
286
289
  >
287
- <Icon
288
- name={sourceIcon(definition.source)}
289
- className="size-16 shrink-0 text-foreground-neutral-muted"
290
- aria-hidden="true"
291
- />
292
- <div className="flex min-w-0 flex-col gap-tight">
293
- <Text size="sm" bold className="break-words">
294
- {definition.name}
290
+ <button
291
+ type="button"
292
+ className="flex min-w-0 items-start gap-inline text-left"
293
+ onClick={() => onOpenDefinition(definition)}
294
+ >
295
+ <Icon
296
+ name={sourceIcon(definition.source)}
297
+ className="size-16 shrink-0 text-foreground-neutral-muted"
298
+ aria-hidden="true"
299
+ />
300
+ <div className="flex min-w-0 flex-col gap-tight">
301
+ <Text size="sm" bold className="break-words">
302
+ {definition.name}
303
+ </Text>
304
+ <Code className="break-words text-foreground-neutral-muted">
305
+ {definition.configPath ?? 'Manual definition'}
306
+ </Code>
307
+ </div>
308
+ </button>
309
+ <div className="flex items-center justify-between gap-inline">
310
+ <Text size="xs" className="text-foreground-neutral-muted">
311
+ Updated <RelativeTime value={definition.updatedAt} />
295
312
  </Text>
296
- <Code className="break-words text-foreground-neutral-muted">
297
- {definition.configPath ?? 'Manual definition'}
298
- </Code>
313
+ {definition.manualTrigger ? (
314
+ <Button size="sm" isLoading={isRunning} onClick={() => onRun(definition)}>
315
+ Run
316
+ </Button>
317
+ ) : null}
299
318
  </div>
300
- </button>
301
- <div className="flex items-center justify-between gap-inline">
302
- <Text size="xs" className="text-foreground-neutral-muted">
303
- Updated <RelativeTime value={definition.updatedAt} />
304
- </Text>
305
- {definition.manualTrigger ? (
306
- <Button size="sm" isLoading={isRunning} onClick={() => onRun(definition)}>
307
- Run
308
- </Button>
319
+ {runErrorMessage ? (
320
+ <Text size="xs" className="text-tag-error-text">
321
+ {runErrorMessage}
322
+ </Text>
309
323
  ) : null}
310
324
  </div>
311
- {runErrorMessage ? (
312
- <Text size="xs" className="text-tag-error-text">
313
- {runErrorMessage}
314
- </Text>
315
- ) : null}
316
- </div>
317
- );
318
- })}
319
- </div>
325
+ );
326
+ })}
327
+ </div>
328
+ </Panel>
320
329
 
321
330
  {isFetchNextPageError ? (
322
331
  <Callout role="alert" type="error">
@@ -356,7 +365,7 @@ function WorkflowEmptyState({sync}: {sync: DefinitionSyncSummary | null}) {
356
365
  ? 'No workflow definitions found.'
357
366
  : 'Workflow sync has not reported yet.';
358
367
 
359
- return <EmptyState icon="flowChart" title="No workflows" description={message} />;
368
+ return <EmptyState icon="flowChart" title="No workflows" description={message} variant="panel" />;
360
369
  }
361
370
 
362
371
  function WorkflowSyncAlert({sync}: {sync: DefinitionSyncSummary | null | undefined}) {