@shipfox/client-workflows 12.0.2 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/main.ts +16 -1
- package/.storybook/preview.tsx +3 -3
- package/.storybook/workspace-source.ts +31 -0
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +79 -0
- package/dist/components/job-graph/job-duration-format.d.ts +2 -2
- package/dist/components/job-graph/job-duration-format.d.ts.map +1 -1
- package/dist/components/job-graph/job-duration-format.js +4 -2
- package/dist/components/job-graph/job-duration-format.js.map +1 -1
- package/dist/components/job-graph/job-duration-label.js +1 -1
- package/dist/components/job-graph/job-duration-label.js.map +1 -1
- package/dist/components/job-graph/job-graph-content.d.ts +2 -1
- package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +3 -3
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/job-graph/job-graph-view.d.ts +2 -1
- package/dist/components/job-graph/job-graph-view.d.ts.map +1 -1
- package/dist/components/job-graph/job-graph-view.js +2 -2
- package/dist/components/job-graph/job-graph-view.js.map +1 -1
- package/dist/components/job-graph/job-node.d.ts +1 -1
- package/dist/components/job-graph/job-node.d.ts.map +1 -1
- package/dist/components/job-graph/job-node.js +10 -9
- package/dist/components/job-graph/job-node.js.map +1 -1
- package/dist/components/job-graph/types.d.ts +2 -1
- package/dist/components/job-graph/types.d.ts.map +1 -1
- package/dist/components/job-graph/types.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +2 -2
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-duration-label.js +1 -1
- package/dist/components/workflow-run-duration-label.js.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.d.ts +21 -0
- package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -0
- package/dist/components/workflow-run-list/job-status-strip.js +185 -0
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -0
- package/dist/components/workflow-run-list/run-display.d.ts +27 -3
- package/dist/components/workflow-run-list/run-display.d.ts.map +1 -1
- package/dist/components/workflow-run-list/run-display.js +78 -7
- package/dist/components/workflow-run-list/run-display.js.map +1 -1
- package/dist/components/workflow-run-list/types.d.ts +23 -24
- package/dist/components/workflow-run-list/types.d.ts.map +1 -1
- package/dist/components/workflow-run-list/types.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts +22 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js +68 -0
- package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filters.d.ts +18 -0
- package/dist/components/workflow-run-list/workflow-run-filters.d.ts.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-filters.js +236 -0
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -0
- package/dist/components/workflow-run-list/workflow-run-list-content.d.ts +8 -4
- package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-content.js +40 -12
- package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.d.ts +29 -2
- package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +103 -44
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +60 -43
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list.js +20 -8
- package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts +19 -9
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +179 -112
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-number-label.d.ts +15 -0
- package/dist/components/workflow-run-number-label.d.ts.map +1 -0
- package/dist/components/workflow-run-number-label.js +41 -0
- package/dist/components/workflow-run-number-label.js.map +1 -0
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts +3 -3
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +10 -9
- package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +4 -9
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +107 -74
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-tabs/index.d.ts +6 -0
- package/dist/components/workflow-run-tabs/index.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/index.js +7 -0
- package/dist/components/workflow-run-tabs/index.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts +11 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +71 -0
- package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts +2 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.js +11 -0
- package/dist/components/workflow-run-tabs/run-annotations-empty.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts +18 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.js +107 -0
- package/dist/components/workflow-run-tabs/run-jobs-list.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts +6 -0
- package/dist/components/workflow-run-tabs/run-tab-count.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-count.js +27 -0
- package/dist/components/workflow-run-tabs/run-tab-count.js.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts +8 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.d.ts.map +1 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.js +82 -0
- package/dist/components/workflow-run-tabs/run-tab-strip.js.map +1 -0
- package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts +2 -2
- package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts.map +1 -1
- package/dist/components/workflow-run-view/agent-config-failure-callout.js +4 -4
- package/dist/components/workflow-run-view/agent-config-failure-callout.js.map +1 -1
- package/dist/components/workflow-run-view/job-card.d.ts +2 -2
- package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
- package/dist/components/workflow-run-view/job-card.js +51 -32
- package/dist/components/workflow-run-view/job-card.js.map +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.d.ts +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.d.ts.map +1 -1
- package/dist/components/workflow-run-view/job-execution-switcher.js +20 -8
- package/dist/components/workflow-run-view/job-execution-switcher.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-selection.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-selection.js +40 -1
- package/dist/components/workflow-run-view/workflow-run-selection.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.d.ts +1 -0
- package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +10 -1
- package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts +10 -5
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +136 -85
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/components/workflow-source-panel/index.d.ts +1 -0
- package/dist/components/workflow-source-panel/index.d.ts.map +1 -1
- package/dist/components/workflow-source-panel/index.js +1 -0
- package/dist/components/workflow-source-panel/index.js.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.d.ts +12 -0
- package/dist/components/workflow-source-panel/workflow-source-content.d.ts.map +1 -0
- package/dist/components/workflow-source-panel/workflow-source-content.js +53 -0
- package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -0
- package/dist/components/workflow-source-panel/workflow-source-panel.d.ts +1 -1
- package/dist/components/workflow-source-panel/workflow-source-panel.d.ts.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-panel.js +7 -54
- package/dist/components/workflow-source-panel/workflow-source-panel.js.map +1 -1
- package/dist/components/workflow-status/status-visuals.d.ts +4 -4
- package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
- package/dist/components/workflow-status/status-visuals.js +7 -0
- package/dist/components/workflow-status/status-visuals.js.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.d.ts +3 -4
- package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.js +6 -4
- package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +10 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js +11 -0
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job.d.ts +4 -2
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/job.js +8 -1
- package/dist/core/entities/job.js.map +1 -1
- package/dist/core/entities/step.d.ts +1 -1
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js +2 -0
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +52 -4
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js +22 -3
- package/dist/core/entities/workflow-run.js.map +1 -1
- package/dist/core/workflow-run-tabs.d.ts +9 -0
- package/dist/core/workflow-run-tabs.d.ts.map +1 -0
- package/dist/core/workflow-run-tabs.js +3 -0
- package/dist/core/workflow-run-tabs.js.map +1 -0
- package/dist/core/workflow-run.d.ts +6 -6
- package/dist/core/workflow-run.d.ts.map +1 -1
- package/dist/core/workflow-run.js +3 -3
- package/dist/core/workflow-run.js.map +1 -1
- package/dist/feature.d.ts +7 -7
- package/dist/feature.js +5 -5
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.d.ts +4 -3
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +31 -3
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/hooks/api/workflow-runs.d.ts +4 -4
- package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
- package/dist/hooks/api/workflow-runs.js +12 -4
- package/dist/hooks/api/workflow-runs.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/pages/project-workflows-page.js +46 -1
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-run-detail-page.d.ts +11 -0
- package/dist/pages/workflow-run-detail-page.d.ts.map +1 -0
- package/dist/pages/workflow-run-detail-page.js +52 -0
- package/dist/pages/workflow-run-detail-page.js.map +1 -0
- package/dist/pages/workflow-run-list-page.d.ts +10 -0
- package/dist/pages/workflow-run-list-page.d.ts.map +1 -0
- package/dist/pages/workflow-run-list-page.js +43 -0
- package/dist/pages/workflow-run-list-page.js.map +1 -0
- package/dist/routes/inputs.d.ts +94 -5
- package/dist/routes/inputs.d.ts.map +1 -1
- package/dist/routes/inputs.js +199 -13
- package/dist/routes/inputs.js.map +1 -1
- package/dist/routes/project-route.d.ts +6 -0
- package/dist/routes/project-route.d.ts.map +1 -0
- package/dist/routes/project-route.js +25 -0
- package/dist/routes/project-route.js.map +1 -0
- package/dist/routes/run-detail.d.ts.map +1 -1
- package/dist/routes/run-detail.js +12 -7
- package/dist/routes/run-detail.js.map +1 -1
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/runs.js +11 -6
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +6 -5
- package/dist/routes/workflows.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/components/job-graph/job-duration-format.ts +11 -2
- package/src/components/job-graph/job-duration-label.tsx +5 -1
- package/src/components/job-graph/job-graph-content.tsx +7 -4
- package/src/components/job-graph/job-graph-view.test.tsx +19 -8
- package/src/components/job-graph/job-graph-view.tsx +6 -3
- package/src/components/job-graph/job-graph.stories.tsx +24 -20
- package/src/components/job-graph/job-node.stories.tsx +11 -6
- package/src/components/job-graph/job-node.test.tsx +82 -12
- package/src/components/job-graph/job-node.tsx +22 -15
- package/src/components/job-graph/types.ts +5 -1
- package/src/components/step-list/step-list.stories.tsx +2 -3
- package/src/components/step-list/step-list.tsx +3 -2
- package/src/components/workflow-run-duration-label.tsx +1 -1
- package/src/components/workflow-run-list/job-status-strip.tsx +189 -0
- package/src/components/workflow-run-list/run-display.test.ts +169 -30
- package/src/components/workflow-run-list/run-display.ts +116 -9
- package/src/components/workflow-run-list/types.ts +21 -17
- package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +100 -0
- package/src/components/workflow-run-list/workflow-run-filters.tsx +243 -0
- package/src/components/workflow-run-list/workflow-run-list-content.tsx +44 -16
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +128 -27
- package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +441 -104
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +73 -43
- package/src/components/workflow-run-list/workflow-run-list.stories.tsx +140 -20
- package/src/components/workflow-run-list/workflow-run-list.tsx +20 -10
- package/src/components/workflow-run-list/workflow-run-row.tsx +173 -106
- package/src/components/workflow-run-number-label.test.tsx +45 -0
- package/src/components/workflow-run-number-label.tsx +47 -0
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +7 -8
- package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +15 -14
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +29 -38
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +30 -24
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +102 -77
- package/src/components/workflow-run-tabs/index.ts +5 -0
- package/src/components/workflow-run-tabs/run-annotation-summary-line.test.tsx +69 -0
- package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +97 -0
- package/src/components/workflow-run-tabs/run-annotations-empty.tsx +11 -0
- package/src/components/workflow-run-tabs/run-jobs-list.tsx +151 -0
- package/src/components/workflow-run-tabs/run-tab-count.tsx +28 -0
- package/src/components/workflow-run-tabs/run-tab-strip.stories.tsx +52 -0
- package/src/components/workflow-run-tabs/run-tab-strip.test.tsx +117 -0
- package/src/components/workflow-run-tabs/run-tab-strip.tsx +97 -0
- package/src/components/workflow-run-view/agent-config-failure-callout.stories.tsx +2 -3
- package/src/components/workflow-run-view/agent-config-failure-callout.tsx +4 -4
- package/src/components/workflow-run-view/job-card.stories.tsx +11 -10
- package/src/components/workflow-run-view/job-card.test.tsx +115 -0
- package/src/components/workflow-run-view/job-card.tsx +74 -35
- package/src/components/workflow-run-view/job-execution-switcher.tsx +31 -9
- package/src/components/workflow-run-view/workflow-run-selection.test.ts +48 -0
- package/src/components/workflow-run-view/workflow-run-selection.ts +48 -1
- package/src/components/workflow-run-view/workflow-run-states.tsx +12 -1
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +152 -94
- package/src/components/workflow-run-view/workflow-run-view.tsx +219 -95
- package/src/components/workflow-source-panel/index.ts +1 -0
- package/src/components/workflow-source-panel/workflow-source-content.tsx +84 -0
- package/src/components/workflow-source-panel/workflow-source-panel.tsx +14 -81
- package/src/components/workflow-status/status-visuals.test.ts +9 -0
- package/src/components/workflow-status/status-visuals.ts +6 -4
- package/src/components/workflow-status/workflow-status-icon.stories.tsx +10 -2
- package/src/components/workflow-status/workflow-status-icon.test.tsx +18 -0
- package/src/components/workflow-status/workflow-status-icon.tsx +17 -24
- package/src/core/entities/job-execution.ts +22 -0
- package/src/core/entities/job-status.test.ts +104 -0
- package/src/core/entities/job.ts +18 -3
- package/src/core/entities/step.ts +4 -0
- package/src/core/entities/workflow-run.ts +76 -7
- package/src/core/workflow-run-tabs.ts +8 -0
- package/src/core/workflow-run.test.ts +24 -9
- package/src/core/workflow-run.ts +17 -2
- package/src/feature.ts +5 -5
- package/src/hooks/api/workflow-run-mapper.ts +30 -3
- package/src/hooks/api/workflow-runs.test.tsx +2 -0
- package/src/hooks/api/workflow-runs.ts +12 -7
- package/src/index.ts +7 -2
- package/src/page-harness-budget.test.ts +1 -1
- package/src/pages/project-workflows-page.test.tsx +59 -5
- package/src/pages/project-workflows-page.tsx +34 -1
- package/src/pages/workflow-run-detail-page.tsx +72 -0
- package/src/pages/workflow-run-list-page.tsx +65 -0
- package/src/pages/workflow-run-pages.test.tsx +823 -0
- package/src/routes/inputs.test.ts +240 -12
- package/src/routes/inputs.ts +215 -11
- package/src/routes/project-route.tsx +25 -0
- package/src/routes/run-detail.tsx +15 -8
- package/src/routes/runs.tsx +14 -7
- package/src/routes/workflows.tsx +5 -4
- package/src/storybook-config.test.ts +27 -0
- package/test/fixtures/workflow-run.ts +76 -7
- package/test/pages.tsx +18 -8
- package/test/render.tsx +8 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.test.json +7 -1
- package/dist/components/workflow-run-list/workflow-run-list-header.d.ts +0 -10
- package/dist/components/workflow-run-list/workflow-run-list-header.d.ts.map +0 -1
- package/dist/components/workflow-run-list/workflow-run-list-header.js +0 -55
- package/dist/components/workflow-run-list/workflow-run-list-header.js.map +0 -1
- package/dist/pages/workflow-run-first-time-use.d.ts +0 -6
- package/dist/pages/workflow-run-first-time-use.d.ts.map +0 -1
- package/dist/pages/workflow-run-first-time-use.js +0 -17
- package/dist/pages/workflow-run-first-time-use.js.map +0 -1
- package/dist/pages/workflow-run-page.d.ts +0 -10
- package/dist/pages/workflow-run-page.d.ts.map +0 -1
- package/dist/pages/workflow-run-page.js +0 -90
- package/dist/pages/workflow-run-page.js.map +0 -1
- package/src/components/workflow-run-list/workflow-run-list-header.tsx +0 -53
- package/src/pages/workflow-run-first-time-use.tsx +0 -17
- package/src/pages/workflow-run-page.test.tsx +0 -519
- package/src/pages/workflow-run-page.tsx +0 -94
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {ApiError} from '@shipfox/client-api';
|
|
2
2
|
import {QueryLoadError} from '@shipfox/client-ui';
|
|
3
|
+
import {EmptyState} from '@shipfox/react-ui/empty-state';
|
|
3
4
|
import {RelativeTimeProvider} from '@shipfox/react-ui/relative-time';
|
|
5
|
+
import {Tabs, TabsContent, TabsContents} from '@shipfox/react-ui/tabs';
|
|
4
6
|
import {toast} from '@shipfox/react-ui/toast';
|
|
5
7
|
import {useNavigate} from '@tanstack/react-router';
|
|
6
8
|
import {useEffect, useId, useRef, useState} from 'react';
|
|
@@ -10,6 +12,7 @@ import {
|
|
|
10
12
|
type StepSourceLocation,
|
|
11
13
|
type WorkflowRunRerunMode,
|
|
12
14
|
} from '#core/workflow-run.js';
|
|
15
|
+
import type {RunAnnotationSummary} from '#core/workflow-run-tabs.js';
|
|
13
16
|
import {
|
|
14
17
|
type WorkflowRunSelectionInput,
|
|
15
18
|
withoutWorkflowRunSelectionSearch,
|
|
@@ -19,12 +22,20 @@ import {
|
|
|
19
22
|
useRerunWorkflowRunMutation,
|
|
20
23
|
useWorkflowRunAttemptQuery,
|
|
21
24
|
} from '#hooks/api/workflow-runs.js';
|
|
25
|
+
import {WORKFLOW_RUN_TABS, type WorkflowRunTab} from '#routes/inputs.js';
|
|
22
26
|
import {JobGraph} from '../job-graph/index.js';
|
|
27
|
+
import type {JobGraphSelectionSource} from '../job-graph/types.js';
|
|
23
28
|
import {WorkflowRunSummary} from '../workflow-run-summary/index.js';
|
|
24
|
-
import {
|
|
25
|
-
|
|
29
|
+
import {
|
|
30
|
+
RunAnnotationSummaryLine,
|
|
31
|
+
RunAnnotationsEmpty,
|
|
32
|
+
RunJobsList,
|
|
33
|
+
RunTabStrip,
|
|
34
|
+
} from '../workflow-run-tabs/index.js';
|
|
35
|
+
import {WorkflowSourceContent, WorkflowSourcePanel} from '../workflow-source-panel/index.js';
|
|
26
36
|
import {resolveWorkflowRunSelection} from './workflow-run-selection.js';
|
|
27
37
|
import {
|
|
38
|
+
WorkflowRunContentSkeleton,
|
|
28
39
|
WorkflowRunNotFound,
|
|
29
40
|
WorkflowRunSkeleton,
|
|
30
41
|
WorkflowRunStaleError,
|
|
@@ -36,24 +47,31 @@ interface WorkflowSourceFocus {
|
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
export interface WorkflowRunViewProps {
|
|
39
|
-
workspaceId: string;
|
|
40
50
|
projectId: string;
|
|
51
|
+
workspaceSlug?: string | undefined;
|
|
52
|
+
projectSlug?: string | undefined;
|
|
41
53
|
workflowRunId?: string | undefined;
|
|
42
54
|
selection?: WorkflowRunSelectionInput | undefined;
|
|
43
55
|
onSelectionChange?: ((selection: WorkflowRunSelectionInput) => void) | undefined;
|
|
56
|
+
tab?: WorkflowRunTab | undefined;
|
|
57
|
+
onTabChange?: ((tab: WorkflowRunTab) => void) | undefined;
|
|
58
|
+
annotationSummary?: RunAnnotationSummary | undefined;
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
/**
|
|
47
|
-
* Renders the run for `workflowRunId`,
|
|
48
|
-
*
|
|
49
|
-
* loading state itself.
|
|
62
|
+
* Renders the run for `workflowRunId`, keeping the local tab strip mounted while the run
|
|
63
|
+
* request is pending so polling never inserts navigation under the user's cursor.
|
|
50
64
|
*/
|
|
51
65
|
export function WorkflowRunView({
|
|
52
|
-
workspaceId,
|
|
53
66
|
projectId,
|
|
67
|
+
workspaceSlug,
|
|
68
|
+
projectSlug,
|
|
54
69
|
workflowRunId,
|
|
55
70
|
selection,
|
|
56
71
|
onSelectionChange,
|
|
72
|
+
tab,
|
|
73
|
+
onTabChange,
|
|
74
|
+
annotationSummary,
|
|
57
75
|
}: WorkflowRunViewProps) {
|
|
58
76
|
const runQuery = useWorkflowRunAttemptQuery({workflowRunId, runAttempt: selection?.runAttempt});
|
|
59
77
|
const rerunMutation = useRerunWorkflowRunMutation(projectId);
|
|
@@ -62,12 +80,15 @@ export function WorkflowRunView({
|
|
|
62
80
|
<RelativeTimeProvider>
|
|
63
81
|
<div className="flex min-h-0 min-w-0 flex-1 overflow-hidden">
|
|
64
82
|
<RunViewContent
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
workspaceSlug={workspaceSlug}
|
|
84
|
+
projectSlug={projectSlug}
|
|
67
85
|
query={runQuery}
|
|
68
86
|
rerunMutation={rerunMutation}
|
|
69
87
|
selection={selection}
|
|
70
88
|
onSelectionChange={onSelectionChange}
|
|
89
|
+
tab={tab}
|
|
90
|
+
onTabChange={onTabChange}
|
|
91
|
+
annotationSummary={annotationSummary}
|
|
71
92
|
/>
|
|
72
93
|
</div>
|
|
73
94
|
</RelativeTimeProvider>
|
|
@@ -75,31 +96,38 @@ export function WorkflowRunView({
|
|
|
75
96
|
}
|
|
76
97
|
|
|
77
98
|
function RunViewContent({
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
workspaceSlug,
|
|
100
|
+
projectSlug,
|
|
80
101
|
query,
|
|
81
102
|
rerunMutation,
|
|
82
103
|
selection,
|
|
83
104
|
onSelectionChange,
|
|
105
|
+
tab,
|
|
106
|
+
onTabChange,
|
|
107
|
+
annotationSummary,
|
|
84
108
|
}: {
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
workspaceSlug: string | undefined;
|
|
110
|
+
projectSlug: string | undefined;
|
|
87
111
|
query: ReturnType<typeof useWorkflowRunAttemptQuery>;
|
|
88
112
|
rerunMutation: ReturnType<typeof useRerunWorkflowRunMutation>;
|
|
89
113
|
selection: WorkflowRunSelectionInput | undefined;
|
|
90
114
|
onSelectionChange: ((selection: WorkflowRunSelectionInput) => void) | undefined;
|
|
115
|
+
tab: WorkflowRunTab | undefined;
|
|
116
|
+
onTabChange: ((tab: WorkflowRunTab) => void) | undefined;
|
|
117
|
+
annotationSummary: RunAnnotationSummary | undefined;
|
|
91
118
|
}) {
|
|
92
119
|
const navigate = useNavigate();
|
|
93
120
|
const [selectedJobId, setSelectedJobId] = useState<string | undefined>();
|
|
94
121
|
const [selectedJobExecutionId, setSelectedJobExecutionId] = useState<string | undefined>();
|
|
122
|
+
const [localTab, setLocalTab] = useState<WorkflowRunTab>(tab ?? 'summary');
|
|
95
123
|
const [sourcePanelOpen, setSourcePanelOpen] = useState(false);
|
|
96
124
|
const [sourceFocus, setSourceFocus] = useState<WorkflowSourceFocus | null>(null);
|
|
97
125
|
const sourcePanelId = useId();
|
|
98
|
-
|
|
99
|
-
// The button that last opened the panel (summary or a step detail), so Escape /
|
|
100
|
-
// Close returns focus to whoever opened it.
|
|
126
|
+
// The step Source button that last opened the panel, so Escape / Close returns focus to it.
|
|
101
127
|
const lastSourceTriggerRef = useRef<HTMLButtonElement | null>(null);
|
|
102
128
|
const selectionControlled = selection !== undefined;
|
|
129
|
+
const tabControlled = onTabChange !== undefined;
|
|
130
|
+
const activeTab = tabControlled ? (tab ?? 'summary') : localTab;
|
|
103
131
|
const sourceAvailable =
|
|
104
132
|
query.data?.sourceSnapshot !== null && query.data?.sourceSnapshot !== undefined;
|
|
105
133
|
const cancelMutation = useCancelWorkflowRunMutation(query.data);
|
|
@@ -111,8 +139,8 @@ function RunViewContent({
|
|
|
111
139
|
}
|
|
112
140
|
}, [sourceAvailable]);
|
|
113
141
|
|
|
114
|
-
// If a refetch drops the focused step or its location,
|
|
115
|
-
//
|
|
142
|
+
// If a refetch drops the focused step or its location, close the panel so it never points at
|
|
143
|
+
// an unmounted Source button.
|
|
116
144
|
useEffect(() => {
|
|
117
145
|
if (!sourceFocus) return;
|
|
118
146
|
const stillLocated = query.data?.jobs.some((job) =>
|
|
@@ -122,31 +150,26 @@ function RunViewContent({
|
|
|
122
150
|
);
|
|
123
151
|
if (!stillLocated) {
|
|
124
152
|
setSourceFocus(null);
|
|
125
|
-
|
|
153
|
+
setSourcePanelOpen(false);
|
|
126
154
|
}
|
|
127
155
|
}, [sourceFocus, query.data]);
|
|
128
156
|
|
|
129
|
-
if (query.isPending) return <WorkflowRunSkeleton />;
|
|
130
|
-
|
|
131
|
-
// Only show the full error placeholder when nothing ever loaded. A refetch that fails after
|
|
132
|
-
// a prior success keeps the loaded run on screen (see below) instead of wiping the pane,
|
|
133
|
-
// since active-run polling can hit a transient API error.
|
|
134
|
-
if (query.isError && query.data === undefined) {
|
|
135
|
-
if (query.error instanceof ApiError && query.error.status === 404) {
|
|
136
|
-
return <WorkflowRunNotFound />;
|
|
137
|
-
}
|
|
138
|
-
return <QueryLoadError query={query} subject="workflow run" icon="pulseLine" />;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (query.data === undefined) return <WorkflowRunSkeleton />;
|
|
142
|
-
|
|
143
157
|
const runData = query.data;
|
|
144
|
-
const resolvedSelection =
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
const resolvedSelection =
|
|
159
|
+
selectionControlled && runData
|
|
160
|
+
? resolveWorkflowRunSelection({
|
|
161
|
+
run: runData,
|
|
162
|
+
selection: selection as WorkflowRunSelectionInput,
|
|
163
|
+
})
|
|
164
|
+
: undefined;
|
|
165
|
+
const hasExplicitJobSelection = Boolean(
|
|
166
|
+
selection?.jobId || selection?.jobExecutionId || selection?.stepId || selection?.stepAttemptId,
|
|
167
|
+
);
|
|
147
168
|
const selectedJob = selectionControlled
|
|
148
|
-
?
|
|
149
|
-
|
|
169
|
+
? hasExplicitJobSelection
|
|
170
|
+
? resolvedSelection?.job
|
|
171
|
+
: undefined
|
|
172
|
+
: (runData?.jobs.find((job) => job.id === selectedJobId) ?? runData?.jobs.at(0));
|
|
150
173
|
const selectedJobExecution = selectionControlled
|
|
151
174
|
? resolvedSelection?.jobExecution
|
|
152
175
|
: selectedJob
|
|
@@ -155,18 +178,45 @@ function RunViewContent({
|
|
|
155
178
|
const selectedAttemptId = selectionControlled
|
|
156
179
|
? (resolvedSelection?.selectedAttemptId ?? null)
|
|
157
180
|
: undefined;
|
|
158
|
-
// Explicit per-step focus wins; fall back to the URL-selected step so deep links
|
|
159
|
-
//
|
|
181
|
+
// Explicit per-step focus wins; fall back to the URL-selected step so deep links still
|
|
182
|
+
// pre-highlight source in the Source tab.
|
|
160
183
|
const highlightedLineRange =
|
|
161
184
|
sourceFocus?.location ?? resolvedSelection?.step?.sourceLocation ?? null;
|
|
162
|
-
const sourceSnapshot = runData
|
|
185
|
+
const sourceSnapshot = runData?.sourceSnapshot ?? null;
|
|
186
|
+
|
|
187
|
+
function changeTab(nextTab: WorkflowRunTab) {
|
|
188
|
+
if (!tabControlled) {
|
|
189
|
+
setLocalTab(nextTab);
|
|
190
|
+
} else if (activeTab !== nextTab) {
|
|
191
|
+
onTabChange?.(nextTab);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (nextTab !== 'jobs') {
|
|
195
|
+
setSourcePanelOpen(false);
|
|
196
|
+
setSourceFocus(null);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function handleTabChange(nextTab: string) {
|
|
201
|
+
if (!WORKFLOW_RUN_TABS.some((value) => value === nextTab)) return;
|
|
202
|
+
changeTab(nextTab as WorkflowRunTab);
|
|
203
|
+
}
|
|
204
|
+
|
|
163
205
|
async function rerun(mode: WorkflowRunRerunMode) {
|
|
206
|
+
if (!runData || !workspaceSlug || !projectSlug) {
|
|
207
|
+
toast.error('Could not start re-run from this route.');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
164
210
|
try {
|
|
165
211
|
const run = await rerunMutation.mutateAsync({workflowRunId: runData.id, mode});
|
|
166
212
|
toast.success('Re-run started');
|
|
167
213
|
await navigate({
|
|
168
|
-
to: '/
|
|
169
|
-
params: {
|
|
214
|
+
to: '/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId',
|
|
215
|
+
params: {
|
|
216
|
+
workspaceSlug,
|
|
217
|
+
projectSlug,
|
|
218
|
+
workflowRunId: run.id,
|
|
219
|
+
},
|
|
170
220
|
search: ((previous: Record<string, unknown>) =>
|
|
171
221
|
withoutWorkflowRunSelectionSearch(previous)) as never,
|
|
172
222
|
});
|
|
@@ -175,12 +225,16 @@ function RunViewContent({
|
|
|
175
225
|
}
|
|
176
226
|
}
|
|
177
227
|
|
|
178
|
-
function selectJob(jobId: string | undefined) {
|
|
228
|
+
function selectJob(jobId: string | undefined, source: JobGraphSelectionSource = 'pointer') {
|
|
229
|
+
if (source === 'pointer') changeTab('jobs');
|
|
179
230
|
if (!selectionControlled) {
|
|
180
231
|
setSelectedJobId(jobId);
|
|
181
232
|
setSelectedJobExecutionId(undefined);
|
|
182
233
|
return;
|
|
183
234
|
}
|
|
235
|
+
// Keyboard roving focus is an interaction within the Summary graph. Keep that panel mounted
|
|
236
|
+
// and let JobGraphView own the visual selection so focus is not moved to a different tab.
|
|
237
|
+
if (source === 'keyboard') return;
|
|
184
238
|
|
|
185
239
|
onSelectionChange?.(
|
|
186
240
|
jobId ? {jobId, runAttempt: selection?.runAttempt} : {runAttempt: selection?.runAttempt},
|
|
@@ -225,20 +279,6 @@ function RunViewContent({
|
|
|
225
279
|
});
|
|
226
280
|
}
|
|
227
281
|
|
|
228
|
-
function openWholeWorkflowSource() {
|
|
229
|
-
setSourceFocus(null);
|
|
230
|
-
lastSourceTriggerRef.current = sourceButtonRef.current;
|
|
231
|
-
setSourcePanelOpen(true);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function toggleWholeWorkflowSource() {
|
|
235
|
-
if (sourcePanelOpen && sourceFocus === null) {
|
|
236
|
-
closeSourcePanel();
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
openWholeWorkflowSource();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
282
|
function openStepSource(
|
|
243
283
|
stepId: string,
|
|
244
284
|
location: StepSourceLocation,
|
|
@@ -251,13 +291,11 @@ function RunViewContent({
|
|
|
251
291
|
|
|
252
292
|
function closeSourcePanel() {
|
|
253
293
|
const trigger = lastSourceTriggerRef.current;
|
|
254
|
-
const fallbackTrigger = sourceButtonRef.current;
|
|
255
294
|
setSourcePanelOpen(false);
|
|
256
|
-
// Defer so focus lands after the panel unmounts; clear the focus only after
|
|
257
|
-
//
|
|
295
|
+
// Defer so focus lands after the panel unmounts; clear the focus only after focusing so the
|
|
296
|
+
// opener button is still expanded (force-visible) on return.
|
|
258
297
|
window.setTimeout(() => {
|
|
259
|
-
|
|
260
|
-
focusTarget?.focus();
|
|
298
|
+
if (trigger?.isConnected) trigger.focus();
|
|
261
299
|
setSourceFocus(null);
|
|
262
300
|
}, 0);
|
|
263
301
|
}
|
|
@@ -270,38 +308,73 @@ function RunViewContent({
|
|
|
270
308
|
});
|
|
271
309
|
}
|
|
272
310
|
|
|
311
|
+
const fatalError = query.isError && runData === undefined;
|
|
312
|
+
const tabState = fatalError ? (
|
|
313
|
+
query.error instanceof ApiError && query.error.status === 404 ? (
|
|
314
|
+
<WorkflowRunNotFound />
|
|
315
|
+
) : (
|
|
316
|
+
<QueryLoadError query={query} subject="workflow run" icon="pulseLine" />
|
|
317
|
+
)
|
|
318
|
+
) : query.isPending || runData === undefined ? (
|
|
319
|
+
<WorkflowRunContentSkeleton />
|
|
320
|
+
) : null;
|
|
321
|
+
|
|
273
322
|
return (
|
|
274
323
|
<>
|
|
275
|
-
<
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
324
|
+
<Tabs
|
|
325
|
+
value={activeTab}
|
|
326
|
+
onValueChange={handleTabChange}
|
|
327
|
+
className="flex min-w-0 flex-1 flex-col gap-0"
|
|
328
|
+
>
|
|
329
|
+
{runData ? (
|
|
330
|
+
<WorkflowRunSummary
|
|
331
|
+
workspaceSlug={workspaceSlug}
|
|
332
|
+
projectSlug={projectSlug}
|
|
333
|
+
run={runData}
|
|
334
|
+
cancelling={cancelMutation.isPending}
|
|
335
|
+
onCancel={cancelRun}
|
|
336
|
+
rerunPending={rerunMutation.isPending}
|
|
337
|
+
onRerun={(mode) => void rerun(mode)}
|
|
338
|
+
latestAttempt={runData.latestAttempt}
|
|
339
|
+
/>
|
|
340
|
+
) : (
|
|
341
|
+
<WorkflowRunSkeleton />
|
|
342
|
+
)}
|
|
343
|
+
{runData && query.isError ? <WorkflowRunStaleError query={query} /> : null}
|
|
344
|
+
<RunTabStrip
|
|
345
|
+
jobCount={runData?.jobs.length}
|
|
346
|
+
jobsFailed={runData?.jobs.filter((job) => job.status === 'failed').length}
|
|
347
|
+
annotationSummary={annotationSummary}
|
|
290
348
|
/>
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
349
|
+
<TabsContents className="min-h-0 flex-1 overflow-auto bg-background-neutral-background pb-24 pt-16">
|
|
350
|
+
<TabsContent
|
|
351
|
+
value="summary"
|
|
352
|
+
tabIndex={-1}
|
|
353
|
+
className="mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24 outline-none"
|
|
354
|
+
>
|
|
355
|
+
{runData ? (
|
|
356
|
+
<JobGraph
|
|
357
|
+
run={runData}
|
|
358
|
+
selectedJobId={selectedJob?.id}
|
|
359
|
+
onSelectedJobChange={selectJob}
|
|
360
|
+
/>
|
|
361
|
+
) : (
|
|
362
|
+
tabState
|
|
363
|
+
)}
|
|
364
|
+
</TabsContent>
|
|
365
|
+
<TabsContent
|
|
366
|
+
value="jobs"
|
|
367
|
+
tabIndex={-1}
|
|
368
|
+
className="mx-auto w-full max-w-[1120px] px-24 outline-none"
|
|
369
|
+
>
|
|
370
|
+
{runData ? (
|
|
371
|
+
<RunJobsList
|
|
372
|
+
jobs={runData.jobs}
|
|
373
|
+
selectedJobId={selectedJob?.id}
|
|
374
|
+
onSelectedJobChange={selectJob}
|
|
375
|
+
workspaceSlug={workspaceSlug}
|
|
303
376
|
selectedJobExecution={selectedJobExecution}
|
|
304
|
-
selectedAttemptId={
|
|
377
|
+
selectedAttemptId={selectedAttemptId}
|
|
305
378
|
onSelectedJobExecutionChange={selectJobExecution}
|
|
306
379
|
onSelectedAttemptChange={selectionControlled ? selectAttempt : undefined}
|
|
307
380
|
sourcePanelId={sourcePanelId}
|
|
@@ -309,10 +382,61 @@ function RunViewContent({
|
|
|
309
382
|
focusedSourceStepId={sourceFocus?.stepId ?? null}
|
|
310
383
|
onOpenStepSource={openStepSource}
|
|
311
384
|
/>
|
|
312
|
-
) :
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
385
|
+
) : (
|
|
386
|
+
tabState
|
|
387
|
+
)}
|
|
388
|
+
</TabsContent>
|
|
389
|
+
<TabsContent
|
|
390
|
+
value="annotations"
|
|
391
|
+
tabIndex={-1}
|
|
392
|
+
className="mx-auto flex w-full max-w-[1120px] flex-col gap-16 px-24 outline-none"
|
|
393
|
+
>
|
|
394
|
+
{runData ? (
|
|
395
|
+
<>
|
|
396
|
+
<RunAnnotationSummaryLine
|
|
397
|
+
summary={annotationSummary}
|
|
398
|
+
workspaceSlug={workspaceSlug}
|
|
399
|
+
projectSlug={projectSlug}
|
|
400
|
+
workflowRunId={runData.id}
|
|
401
|
+
search={selection}
|
|
402
|
+
/>
|
|
403
|
+
<RunAnnotationsEmpty />
|
|
404
|
+
</>
|
|
405
|
+
) : (
|
|
406
|
+
tabState
|
|
407
|
+
)}
|
|
408
|
+
</TabsContent>
|
|
409
|
+
<TabsContent
|
|
410
|
+
value="source"
|
|
411
|
+
keepMounted={sourceSnapshot !== null}
|
|
412
|
+
tabIndex={-1}
|
|
413
|
+
className="mx-auto flex min-h-full w-full max-w-[1120px] px-24 outline-none"
|
|
414
|
+
>
|
|
415
|
+
{runData ? (
|
|
416
|
+
sourceSnapshot ? (
|
|
417
|
+
<WorkflowSourceContent
|
|
418
|
+
source={sourceSnapshot}
|
|
419
|
+
highlightedLineRange={highlightedLineRange}
|
|
420
|
+
scrollHighlightedIntoView
|
|
421
|
+
/>
|
|
422
|
+
) : (
|
|
423
|
+
<EmptyState
|
|
424
|
+
className="min-h-160 w-full"
|
|
425
|
+
icon="fileDamageLine"
|
|
426
|
+
title="Source snapshot unavailable"
|
|
427
|
+
description={
|
|
428
|
+
runData.isTemporary
|
|
429
|
+
? 'Temporary runs do not capture workflow source.'
|
|
430
|
+
: 'This run was created before workflow source snapshots were captured.'
|
|
431
|
+
}
|
|
432
|
+
/>
|
|
433
|
+
)
|
|
434
|
+
) : (
|
|
435
|
+
tabState
|
|
436
|
+
)}
|
|
437
|
+
</TabsContent>
|
|
438
|
+
</TabsContents>
|
|
439
|
+
</Tabs>
|
|
316
440
|
<WorkflowSourcePanel
|
|
317
441
|
id={sourcePanelId}
|
|
318
442
|
source={sourceSnapshot}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CodeBlock,
|
|
3
|
+
CodeBlockBody,
|
|
4
|
+
CodeBlockContent,
|
|
5
|
+
CodeBlockCopyButton,
|
|
6
|
+
CodeBlockFilename,
|
|
7
|
+
CodeBlockFiles,
|
|
8
|
+
CodeBlockHeader,
|
|
9
|
+
type CodeBlockHighlightedLineRange,
|
|
10
|
+
CodeBlockItem,
|
|
11
|
+
} from '@shipfox/react-ui/code-block';
|
|
12
|
+
import {cn} from '@shipfox/react-ui/utils';
|
|
13
|
+
import type {ReactNode} from 'react';
|
|
14
|
+
import type {WorkflowSourceSnapshot} from '#core/workflow-run.js';
|
|
15
|
+
|
|
16
|
+
const WORKFLOW_SOURCE_FILENAME = 'workflow.yaml';
|
|
17
|
+
const WORKFLOW_SOURCE_CODE_THEMES = {
|
|
18
|
+
light: 'vitesse-dark',
|
|
19
|
+
dark: 'vitesse-dark',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface WorkflowSourceContentProps {
|
|
23
|
+
source: WorkflowSourceSnapshot;
|
|
24
|
+
highlightedLineRange?: CodeBlockHighlightedLineRange | null | undefined;
|
|
25
|
+
scrollHighlightedIntoView?: boolean | undefined;
|
|
26
|
+
headerAction?: ReactNode;
|
|
27
|
+
className?: string | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function WorkflowSourceContent({
|
|
31
|
+
source,
|
|
32
|
+
highlightedLineRange,
|
|
33
|
+
scrollHighlightedIntoView,
|
|
34
|
+
headerAction,
|
|
35
|
+
className,
|
|
36
|
+
}: WorkflowSourceContentProps) {
|
|
37
|
+
const data = [
|
|
38
|
+
{
|
|
39
|
+
language: 'yaml',
|
|
40
|
+
filename: WORKFLOW_SOURCE_FILENAME,
|
|
41
|
+
code: source.content,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<CodeBlock
|
|
47
|
+
data={data}
|
|
48
|
+
className={cn(
|
|
49
|
+
'flex size-full flex-col rounded-none bg-background-contrast-base shadow-none',
|
|
50
|
+
className,
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
<CodeBlockHeader className="shrink-0 border-b border-border-contrast-base bg-background-contrast-base">
|
|
54
|
+
<CodeBlockFiles>
|
|
55
|
+
{(item) => <CodeBlockFilename value={item.filename}>{item.filename}</CodeBlockFilename>}
|
|
56
|
+
</CodeBlockFiles>
|
|
57
|
+
<CodeBlockCopyButton />
|
|
58
|
+
{headerAction}
|
|
59
|
+
</CodeBlockHeader>
|
|
60
|
+
<CodeBlockBody className="flex min-h-0 flex-1 overflow-auto scrollbar">
|
|
61
|
+
{(item) => (
|
|
62
|
+
<CodeBlockItem
|
|
63
|
+
value={item.filename}
|
|
64
|
+
className={cn(
|
|
65
|
+
'min-h-full px-0 pb-0',
|
|
66
|
+
'[&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base [&>div]:dark:bg-background-contrast-base',
|
|
67
|
+
'[&_code]:!text-sm [&_code]:!text-foreground-neutral-on-inverted [&_.line]:!text-sm [&_.line]:before:!text-sm [&_.line]:before:!text-foreground-neutral-muted',
|
|
68
|
+
)}
|
|
69
|
+
>
|
|
70
|
+
<CodeBlockContent
|
|
71
|
+
language="yaml"
|
|
72
|
+
themes={WORKFLOW_SOURCE_CODE_THEMES}
|
|
73
|
+
syntaxHighlighting
|
|
74
|
+
highlightedLineRange={highlightedLineRange}
|
|
75
|
+
scrollHighlightedIntoView={scrollHighlightedIntoView}
|
|
76
|
+
>
|
|
77
|
+
{item.code}
|
|
78
|
+
</CodeBlockContent>
|
|
79
|
+
</CodeBlockItem>
|
|
80
|
+
)}
|
|
81
|
+
</CodeBlockBody>
|
|
82
|
+
</CodeBlock>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import {Button} from '@shipfox/react-ui/button';
|
|
2
|
-
import {
|
|
3
|
-
CodeBlock,
|
|
4
|
-
CodeBlockBody,
|
|
5
|
-
CodeBlockContent,
|
|
6
|
-
CodeBlockCopyButton,
|
|
7
|
-
CodeBlockFilename,
|
|
8
|
-
CodeBlockFiles,
|
|
9
|
-
CodeBlockHeader,
|
|
10
|
-
type CodeBlockHighlightedLineRange,
|
|
11
|
-
CodeBlockItem,
|
|
12
|
-
} from '@shipfox/react-ui/code-block';
|
|
2
|
+
import type {CodeBlockHighlightedLineRange} from '@shipfox/react-ui/code-block';
|
|
13
3
|
import {Sheet, SheetClose, SheetContent, SheetTitle} from '@shipfox/react-ui/sheet';
|
|
14
4
|
import {cn} from '@shipfox/react-ui/utils';
|
|
15
5
|
import type {WorkflowSourceSnapshot} from '#core/workflow-run.js';
|
|
16
|
-
|
|
17
|
-
const WORKFLOW_SOURCE_FILENAME = 'workflow.yaml';
|
|
18
|
-
const WORKFLOW_SOURCE_CODE_THEMES = {
|
|
19
|
-
light: 'vitesse-dark',
|
|
20
|
-
dark: 'vitesse-dark',
|
|
21
|
-
};
|
|
6
|
+
import {WorkflowSourceContent} from './workflow-source-content.js';
|
|
22
7
|
|
|
23
8
|
export interface WorkflowSourcePanelProps {
|
|
24
9
|
id: string;
|
|
@@ -61,76 +46,24 @@ export function WorkflowSourcePanel({
|
|
|
61
46
|
)}
|
|
62
47
|
>
|
|
63
48
|
<SheetTitle className="sr-only">Workflow source</SheetTitle>
|
|
64
|
-
<
|
|
49
|
+
<WorkflowSourceContent
|
|
65
50
|
source={source}
|
|
66
51
|
highlightedLineRange={highlightedLineRange}
|
|
67
52
|
scrollHighlightedIntoView={scrollHighlightedIntoView}
|
|
53
|
+
headerAction={
|
|
54
|
+
<SheetClose asChild>
|
|
55
|
+
<Button
|
|
56
|
+
type="button"
|
|
57
|
+
variant="transparentMuted"
|
|
58
|
+
size="sm"
|
|
59
|
+
iconLeft="close"
|
|
60
|
+
aria-label="Close source"
|
|
61
|
+
/>
|
|
62
|
+
</SheetClose>
|
|
63
|
+
}
|
|
68
64
|
/>
|
|
69
65
|
</SheetContent>
|
|
70
66
|
) : null}
|
|
71
67
|
</Sheet>
|
|
72
68
|
);
|
|
73
69
|
}
|
|
74
|
-
|
|
75
|
-
function WorkflowSourcePanelContent({
|
|
76
|
-
source,
|
|
77
|
-
highlightedLineRange,
|
|
78
|
-
scrollHighlightedIntoView,
|
|
79
|
-
}: {
|
|
80
|
-
source: WorkflowSourceSnapshot;
|
|
81
|
-
highlightedLineRange: CodeBlockHighlightedLineRange | null | undefined;
|
|
82
|
-
scrollHighlightedIntoView: boolean | undefined;
|
|
83
|
-
}) {
|
|
84
|
-
const data = [
|
|
85
|
-
{
|
|
86
|
-
language: 'yaml',
|
|
87
|
-
filename: WORKFLOW_SOURCE_FILENAME,
|
|
88
|
-
code: source.content,
|
|
89
|
-
},
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<CodeBlock
|
|
94
|
-
data={data}
|
|
95
|
-
className="flex size-full flex-col rounded-none bg-background-contrast-base shadow-none"
|
|
96
|
-
>
|
|
97
|
-
<CodeBlockHeader className="shrink-0 border-b border-border-contrast-base bg-background-contrast-base">
|
|
98
|
-
<CodeBlockFiles>
|
|
99
|
-
{(item) => <CodeBlockFilename value={item.filename}>{item.filename}</CodeBlockFilename>}
|
|
100
|
-
</CodeBlockFiles>
|
|
101
|
-
<CodeBlockCopyButton />
|
|
102
|
-
<SheetClose asChild>
|
|
103
|
-
<Button
|
|
104
|
-
type="button"
|
|
105
|
-
variant="transparentMuted"
|
|
106
|
-
size="sm"
|
|
107
|
-
iconLeft="close"
|
|
108
|
-
aria-label="Close source"
|
|
109
|
-
/>
|
|
110
|
-
</SheetClose>
|
|
111
|
-
</CodeBlockHeader>
|
|
112
|
-
<CodeBlockBody className="flex min-h-0 flex-1 overflow-auto scrollbar">
|
|
113
|
-
{(item) => (
|
|
114
|
-
<CodeBlockItem
|
|
115
|
-
value={item.filename}
|
|
116
|
-
className={cn(
|
|
117
|
-
'min-h-full px-0 pb-0',
|
|
118
|
-
'[&>div]:rounded-none [&>div]:border-0 [&>div]:bg-background-contrast-base [&>div]:dark:bg-background-contrast-base',
|
|
119
|
-
'[&_code]:!text-sm [&_code]:!text-foreground-neutral-on-inverted [&_.line]:!text-sm [&_.line]:before:!text-sm [&_.line]:before:!text-foreground-neutral-muted',
|
|
120
|
-
)}
|
|
121
|
-
>
|
|
122
|
-
<CodeBlockContent
|
|
123
|
-
language="yaml"
|
|
124
|
-
themes={WORKFLOW_SOURCE_CODE_THEMES}
|
|
125
|
-
syntaxHighlighting
|
|
126
|
-
highlightedLineRange={highlightedLineRange}
|
|
127
|
-
scrollHighlightedIntoView={scrollHighlightedIntoView}
|
|
128
|
-
>
|
|
129
|
-
{item.code}
|
|
130
|
-
</CodeBlockContent>
|
|
131
|
-
</CodeBlockItem>
|
|
132
|
-
)}
|
|
133
|
-
</CodeBlockBody>
|
|
134
|
-
</CodeBlock>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
@@ -35,4 +35,13 @@ describe('getWorkflowStatusVisual', () => {
|
|
|
35
35
|
|
|
36
36
|
expect(visual).toEqual({kind: 'running', label: 'Running', dot: 'info', badge: 'info'});
|
|
37
37
|
});
|
|
38
|
+
|
|
39
|
+
test('returns the active listener visual', () => {
|
|
40
|
+
expect(getWorkflowStatusVisual('listening')).toEqual({
|
|
41
|
+
kind: 'listening',
|
|
42
|
+
label: 'Listening',
|
|
43
|
+
dot: 'info',
|
|
44
|
+
badge: 'info',
|
|
45
|
+
});
|
|
46
|
+
});
|
|
38
47
|
});
|