@shipfox/client-workflows 12.0.2 → 13.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 (232) hide show
  1. package/.storybook/preview.tsx +3 -3
  2. package/.turbo/turbo-build.log +1 -1
  3. package/CHANGELOG.md +56 -0
  4. package/dist/components/job-graph/job-duration-format.d.ts +2 -2
  5. package/dist/components/job-graph/job-duration-format.d.ts.map +1 -1
  6. package/dist/components/job-graph/job-duration-format.js +4 -2
  7. package/dist/components/job-graph/job-duration-format.js.map +1 -1
  8. package/dist/components/job-graph/job-node.d.ts +1 -1
  9. package/dist/components/job-graph/job-node.d.ts.map +1 -1
  10. package/dist/components/job-graph/job-node.js +5 -4
  11. package/dist/components/job-graph/job-node.js.map +1 -1
  12. package/dist/components/step-list/step-list.d.ts +2 -2
  13. package/dist/components/step-list/step-list.d.ts.map +1 -1
  14. package/dist/components/step-list/step-list.js.map +1 -1
  15. package/dist/components/workflow-run-list/job-status-strip.d.ts +21 -0
  16. package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -0
  17. package/dist/components/workflow-run-list/job-status-strip.js +185 -0
  18. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -0
  19. package/dist/components/workflow-run-list/run-display.d.ts +27 -3
  20. package/dist/components/workflow-run-list/run-display.d.ts.map +1 -1
  21. package/dist/components/workflow-run-list/run-display.js +78 -7
  22. package/dist/components/workflow-run-list/run-display.js.map +1 -1
  23. package/dist/components/workflow-run-list/types.d.ts +23 -24
  24. package/dist/components/workflow-run-list/types.d.ts.map +1 -1
  25. package/dist/components/workflow-run-list/types.js.map +1 -1
  26. package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts +22 -0
  27. package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts.map +1 -0
  28. package/dist/components/workflow-run-list/workflow-run-filter-menu.js +68 -0
  29. package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -0
  30. package/dist/components/workflow-run-list/workflow-run-filters.d.ts +18 -0
  31. package/dist/components/workflow-run-list/workflow-run-filters.d.ts.map +1 -0
  32. package/dist/components/workflow-run-list/workflow-run-filters.js +236 -0
  33. package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -0
  34. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts +8 -4
  35. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
  36. package/dist/components/workflow-run-list/workflow-run-list-content.js +40 -12
  37. package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
  38. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts +29 -2
  39. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
  40. package/dist/components/workflow-run-list/workflow-run-list-states.js +103 -44
  41. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  42. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
  43. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
  44. package/dist/components/workflow-run-list/workflow-run-list-view.js +60 -43
  45. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  46. package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
  47. package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
  48. package/dist/components/workflow-run-list/workflow-run-list.js +20 -8
  49. package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
  50. package/dist/components/workflow-run-list/workflow-run-row.d.ts +19 -9
  51. package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
  52. package/dist/components/workflow-run-list/workflow-run-row.js +179 -112
  53. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  54. package/dist/components/workflow-run-number-label.d.ts +15 -0
  55. package/dist/components/workflow-run-number-label.d.ts.map +1 -0
  56. package/dist/components/workflow-run-number-label.js +41 -0
  57. package/dist/components/workflow-run-number-label.js.map +1 -0
  58. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts +3 -3
  59. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts.map +1 -1
  60. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +8 -7
  61. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
  62. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +3 -3
  63. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  64. package/dist/components/workflow-run-summary/workflow-run-summary.js +16 -7
  65. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  66. package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts +2 -2
  67. package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts.map +1 -1
  68. package/dist/components/workflow-run-view/agent-config-failure-callout.js +4 -4
  69. package/dist/components/workflow-run-view/agent-config-failure-callout.js.map +1 -1
  70. package/dist/components/workflow-run-view/job-card.d.ts +2 -2
  71. package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
  72. package/dist/components/workflow-run-view/job-card.js +51 -32
  73. package/dist/components/workflow-run-view/job-card.js.map +1 -1
  74. package/dist/components/workflow-run-view/job-execution-switcher.d.ts +1 -1
  75. package/dist/components/workflow-run-view/job-execution-switcher.d.ts.map +1 -1
  76. package/dist/components/workflow-run-view/job-execution-switcher.js +20 -8
  77. package/dist/components/workflow-run-view/job-execution-switcher.js.map +1 -1
  78. package/dist/components/workflow-run-view/workflow-run-view.d.ts +3 -2
  79. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  80. package/dist/components/workflow-run-view/workflow-run-view.js +15 -11
  81. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  82. package/dist/components/workflow-status/status-visuals.d.ts +4 -4
  83. package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
  84. package/dist/components/workflow-status/status-visuals.js +7 -0
  85. package/dist/components/workflow-status/status-visuals.js.map +1 -1
  86. package/dist/components/workflow-status/workflow-status-icon.d.ts +3 -4
  87. package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
  88. package/dist/components/workflow-status/workflow-status-icon.js +6 -4
  89. package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
  90. package/dist/core/entities/job-execution.d.ts +10 -0
  91. package/dist/core/entities/job-execution.d.ts.map +1 -1
  92. package/dist/core/entities/job-execution.js +11 -0
  93. package/dist/core/entities/job-execution.js.map +1 -1
  94. package/dist/core/entities/job.d.ts +4 -2
  95. package/dist/core/entities/job.d.ts.map +1 -1
  96. package/dist/core/entities/job.js +8 -1
  97. package/dist/core/entities/job.js.map +1 -1
  98. package/dist/core/entities/workflow-run.d.ts +52 -4
  99. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  100. package/dist/core/entities/workflow-run.js +22 -3
  101. package/dist/core/entities/workflow-run.js.map +1 -1
  102. package/dist/core/workflow-run.d.ts +6 -6
  103. package/dist/core/workflow-run.d.ts.map +1 -1
  104. package/dist/core/workflow-run.js +3 -3
  105. package/dist/core/workflow-run.js.map +1 -1
  106. package/dist/feature.d.ts +7 -7
  107. package/dist/feature.js +5 -5
  108. package/dist/feature.js.map +1 -1
  109. package/dist/hooks/api/workflow-run-mapper.d.ts +4 -3
  110. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  111. package/dist/hooks/api/workflow-run-mapper.js +31 -3
  112. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  113. package/dist/hooks/api/workflow-runs.d.ts +4 -4
  114. package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
  115. package/dist/hooks/api/workflow-runs.js +12 -4
  116. package/dist/hooks/api/workflow-runs.js.map +1 -1
  117. package/dist/index.d.ts +4 -3
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +3 -2
  120. package/dist/index.js.map +1 -1
  121. package/dist/pages/project-workflows-page.js +46 -1
  122. package/dist/pages/project-workflows-page.js.map +1 -1
  123. package/dist/pages/workflow-run-detail-page.d.ts +11 -0
  124. package/dist/pages/workflow-run-detail-page.d.ts.map +1 -0
  125. package/dist/pages/workflow-run-detail-page.js +30 -0
  126. package/dist/pages/workflow-run-detail-page.js.map +1 -0
  127. package/dist/pages/workflow-run-list-page.d.ts +10 -0
  128. package/dist/pages/workflow-run-list-page.d.ts.map +1 -0
  129. package/dist/pages/workflow-run-list-page.js +43 -0
  130. package/dist/pages/workflow-run-list-page.js.map +1 -0
  131. package/dist/routes/inputs.d.ts +61 -5
  132. package/dist/routes/inputs.d.ts.map +1 -1
  133. package/dist/routes/inputs.js +150 -13
  134. package/dist/routes/inputs.js.map +1 -1
  135. package/dist/routes/project-route.d.ts +6 -0
  136. package/dist/routes/project-route.d.ts.map +1 -0
  137. package/dist/routes/project-route.js +25 -0
  138. package/dist/routes/project-route.js.map +1 -0
  139. package/dist/routes/run-detail.d.ts.map +1 -1
  140. package/dist/routes/run-detail.js +12 -7
  141. package/dist/routes/run-detail.js.map +1 -1
  142. package/dist/routes/runs.d.ts.map +1 -1
  143. package/dist/routes/runs.js +11 -6
  144. package/dist/routes/runs.js.map +1 -1
  145. package/dist/routes/workflows.d.ts.map +1 -1
  146. package/dist/routes/workflows.js +6 -5
  147. package/dist/routes/workflows.js.map +1 -1
  148. package/dist/tsconfig.test.tsbuildinfo +1 -1
  149. package/package.json +9 -9
  150. package/src/components/job-graph/job-duration-format.ts +11 -2
  151. package/src/components/job-graph/job-graph-view.test.tsx +19 -8
  152. package/src/components/job-graph/job-graph.stories.tsx +23 -19
  153. package/src/components/job-graph/job-node.stories.tsx +10 -5
  154. package/src/components/job-graph/job-node.test.tsx +55 -10
  155. package/src/components/job-graph/job-node.tsx +16 -9
  156. package/src/components/step-list/step-list.stories.tsx +2 -3
  157. package/src/components/step-list/step-list.tsx +3 -2
  158. package/src/components/workflow-run-list/job-status-strip.tsx +189 -0
  159. package/src/components/workflow-run-list/run-display.test.ts +169 -30
  160. package/src/components/workflow-run-list/run-display.ts +116 -9
  161. package/src/components/workflow-run-list/types.ts +21 -17
  162. package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +100 -0
  163. package/src/components/workflow-run-list/workflow-run-filters.tsx +243 -0
  164. package/src/components/workflow-run-list/workflow-run-list-content.tsx +44 -16
  165. package/src/components/workflow-run-list/workflow-run-list-states.tsx +128 -27
  166. package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +441 -104
  167. package/src/components/workflow-run-list/workflow-run-list-view.tsx +73 -43
  168. package/src/components/workflow-run-list/workflow-run-list.stories.tsx +140 -20
  169. package/src/components/workflow-run-list/workflow-run-list.tsx +20 -10
  170. package/src/components/workflow-run-list/workflow-run-row.tsx +173 -106
  171. package/src/components/workflow-run-number-label.test.tsx +45 -0
  172. package/src/components/workflow-run-number-label.tsx +47 -0
  173. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +7 -8
  174. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +13 -12
  175. package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +6 -8
  176. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +27 -2
  177. package/src/components/workflow-run-summary/workflow-run-summary.tsx +19 -9
  178. package/src/components/workflow-run-view/agent-config-failure-callout.stories.tsx +2 -3
  179. package/src/components/workflow-run-view/agent-config-failure-callout.tsx +4 -4
  180. package/src/components/workflow-run-view/job-card.stories.tsx +11 -10
  181. package/src/components/workflow-run-view/job-card.test.tsx +115 -0
  182. package/src/components/workflow-run-view/job-card.tsx +74 -35
  183. package/src/components/workflow-run-view/job-execution-switcher.tsx +31 -9
  184. package/src/components/workflow-run-view/workflow-run-view.test.tsx +88 -30
  185. package/src/components/workflow-run-view/workflow-run-view.tsx +24 -14
  186. package/src/components/workflow-status/status-visuals.test.ts +9 -0
  187. package/src/components/workflow-status/status-visuals.ts +6 -4
  188. package/src/components/workflow-status/workflow-status-icon.stories.tsx +10 -2
  189. package/src/components/workflow-status/workflow-status-icon.test.tsx +18 -0
  190. package/src/components/workflow-status/workflow-status-icon.tsx +17 -24
  191. package/src/core/entities/job-execution.ts +22 -0
  192. package/src/core/entities/job-status.test.ts +104 -0
  193. package/src/core/entities/job.ts +18 -3
  194. package/src/core/entities/workflow-run.ts +76 -7
  195. package/src/core/workflow-run.test.ts +24 -9
  196. package/src/core/workflow-run.ts +17 -2
  197. package/src/feature.ts +5 -5
  198. package/src/hooks/api/workflow-run-mapper.ts +30 -3
  199. package/src/hooks/api/workflow-runs.test.tsx +2 -0
  200. package/src/hooks/api/workflow-runs.ts +12 -7
  201. package/src/index.ts +7 -2
  202. package/src/page-harness-budget.test.ts +1 -1
  203. package/src/pages/project-workflows-page.test.tsx +59 -5
  204. package/src/pages/project-workflows-page.tsx +34 -1
  205. package/src/pages/workflow-run-detail-page.tsx +45 -0
  206. package/src/pages/workflow-run-list-page.tsx +65 -0
  207. package/src/pages/{workflow-run-page.test.tsx → workflow-run-pages.test.tsx} +211 -47
  208. package/src/routes/inputs.test.ts +193 -12
  209. package/src/routes/inputs.ts +170 -11
  210. package/src/routes/project-route.tsx +25 -0
  211. package/src/routes/run-detail.tsx +15 -8
  212. package/src/routes/runs.tsx +14 -7
  213. package/src/routes/workflows.tsx +5 -4
  214. package/test/fixtures/workflow-run.ts +76 -7
  215. package/test/pages.tsx +18 -8
  216. package/test/render.tsx +8 -2
  217. package/tsconfig.build.tsbuildinfo +1 -1
  218. package/dist/components/workflow-run-list/workflow-run-list-header.d.ts +0 -10
  219. package/dist/components/workflow-run-list/workflow-run-list-header.d.ts.map +0 -1
  220. package/dist/components/workflow-run-list/workflow-run-list-header.js +0 -55
  221. package/dist/components/workflow-run-list/workflow-run-list-header.js.map +0 -1
  222. package/dist/pages/workflow-run-first-time-use.d.ts +0 -6
  223. package/dist/pages/workflow-run-first-time-use.d.ts.map +0 -1
  224. package/dist/pages/workflow-run-first-time-use.js +0 -17
  225. package/dist/pages/workflow-run-first-time-use.js.map +0 -1
  226. package/dist/pages/workflow-run-page.d.ts +0 -10
  227. package/dist/pages/workflow-run-page.d.ts.map +0 -1
  228. package/dist/pages/workflow-run-page.js +0 -90
  229. package/dist/pages/workflow-run-page.js.map +0 -1
  230. package/src/components/workflow-run-list/workflow-run-list-header.tsx +0 -53
  231. package/src/pages/workflow-run-first-time-use.tsx +0 -17
  232. package/src/pages/workflow-run-page.tsx +0 -94
@@ -1,171 +1,238 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { TriggerSourceIcon } from '@shipfox/client-triggers';
3
+ import { Icon } from '@shipfox/react-ui/icon';
3
4
  import { RelativeTime } from '@shipfox/react-ui/relative-time';
4
5
  import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
5
6
  import { Code, Text } from '@shipfox/react-ui/typography';
6
7
  import { cn } from '@shipfox/react-ui/utils';
7
8
  import { Link } from '@tanstack/react-router';
8
9
  import { useWorkflowRunDurationAccessibleLabel, WorkflowRunDurationLabel } from '#components/workflow-run-duration-label.js';
10
+ import { formatWorkflowRunNumberLabel, WorkflowRunNumberLabel } from '#components/workflow-run-number-label.js';
9
11
  import { getWorkflowStatusVisual } from '#components/workflow-status/status-visuals.js';
10
12
  import { WorkflowStatusIcon } from '#components/workflow-status/workflow-status-icon.js';
13
+ import { workflowRunActor, workflowRunBranchLabel, workflowRunCommitLabel } from '#core/workflow-run.js';
11
14
  import { withoutWorkflowRunSelectionSearch } from '#core/workflow-run-url-state.js';
12
- export function WorkflowRunRowList({ runs, workspaceId, projectId, selectedWorkflowRunId }) {
13
- return /*#__PURE__*/ _jsx("nav", {
14
- "aria-label": "Run history",
15
- children: /*#__PURE__*/ _jsx("ul", {
16
- className: "flex flex-col gap-4 p-8",
17
- children: runs.map((run)=>/*#__PURE__*/ _jsx("li", {
18
- children: /*#__PURE__*/ _jsx(WorkflowRunRow, {
19
- run: run,
20
- workspaceId: workspaceId,
21
- projectId: projectId,
22
- selected: run.id === selectedWorkflowRunId
23
- })
24
- }, run.id))
25
- })
26
- });
15
+ import { JobStatusStrip, jobStatusSummary } from './job-status-strip.js';
16
+ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
17
+ return(// A container, not the viewport, drives the row's breakpoints. The list is capped at
18
+ // 1120px inside a wider page, so what a row can afford is its own width; keying off the
19
+ // viewport would keep the job strip hidden on a wide screen or crush it on a narrow one.
20
+ /*#__PURE__*/ _jsx("ul", {
21
+ className: "@container divide-y divide-border-neutral-base border-t border-border-neutral-base",
22
+ children: runs.map((run)=>/*#__PURE__*/ _jsx("li", {
23
+ children: /*#__PURE__*/ _jsx(WorkflowRunRow, {
24
+ run: run,
25
+ workspaceSlug: workspaceSlug,
26
+ projectSlug: projectSlug
27
+ })
28
+ }, run.id))
29
+ }));
27
30
  }
28
- export function WorkflowRunRow({ run, workspaceId, projectId, selected }) {
31
+ /**
32
+ * One run at full width.
33
+ *
34
+ * A single 44px line once the list is at least 976px wide, reflowing to two lines below that:
35
+ * the identity and the numerics keep their places on line one, and the provenance metadata
36
+ * drops beneath. The numeric columns are fixed-width so duration and time form real columns
37
+ * down the list rather than tracking each row's name length.
38
+ *
39
+ * The thresholds are the container widths the spec's viewport breakpoints produce, given a
40
+ * column capped at 1120px with 24px of page padding on each side: a 1280px viewport leaves
41
+ * the row 1072px, and a 1024px viewport leaves it 976px.
42
+ */ export function WorkflowRunRow({ run, workspaceSlug, projectSlug }) {
29
43
  const durationLabel = useWorkflowRunDurationAccessibleLabel(run.runAttempt.displayDuration);
30
44
  const statusLabel = getWorkflowStatusVisual(run.status).label;
45
+ const runNumberLabel = formatWorkflowRunNumberLabel(run);
46
+ const branch = workflowRunBranchLabel(run);
47
+ const commit = workflowRunCommitLabel(run);
48
+ const actor = workflowRunActor(run);
31
49
  const body = /*#__PURE__*/ _jsxs(_Fragment, {
32
50
  children: [
33
- selected ? /*#__PURE__*/ _jsx("span", {
34
- "aria-hidden": "true",
35
- className: "absolute inset-y-8 left-0 w-3 rounded-full bg-border-highlights-interactive"
36
- }) : null,
37
- /*#__PURE__*/ _jsxs("div", {
38
- className: "flex min-w-0 items-center gap-8",
39
- children: [
40
- /*#__PURE__*/ _jsx(WorkflowStatusIcon, {
41
- status: run.status,
42
- size: 14
43
- }),
44
- /*#__PURE__*/ _jsx(Code, {
45
- variant: "label",
46
- bold: true,
47
- className: "truncate text-foreground-neutral-base",
48
- children: run.name
49
- })
50
- ]
51
+ /*#__PURE__*/ _jsx(WorkflowStatusIcon, {
52
+ status: run.status,
53
+ size: 14,
54
+ className: "shrink-0"
51
55
  }),
52
56
  /*#__PURE__*/ _jsxs("div", {
53
- className: "flex min-w-0 items-center gap-8",
57
+ className: "flex min-w-0 flex-1 flex-col gap-2 @min-[976px]:flex-row @min-[976px]:items-center @min-[976px]:gap-12",
54
58
  children: [
55
- run.triggerDisplayLabel ? /*#__PURE__*/ _jsx(TriggerLabel, {
56
- run: run
57
- }) : /*#__PURE__*/ _jsxs("span", {
58
- className: "flex min-w-0 flex-1 items-center gap-8 truncate text-foreground-neutral-muted",
59
+ /*#__PURE__*/ _jsxs("span", {
60
+ className: "flex min-w-0 items-center gap-8 @min-[976px]:flex-1",
59
61
  children: [
60
- /*#__PURE__*/ _jsx("span", {
61
- "aria-hidden": "true",
62
- className: "size-14 shrink-0"
62
+ /*#__PURE__*/ _jsx(Code, {
63
+ variant: "label",
64
+ bold: true,
65
+ className: "truncate text-foreground-neutral-base",
66
+ children: run.name
63
67
  }),
64
- /*#__PURE__*/ _jsx("span", {
65
- className: "sr-only",
66
- children: "Run updated "
67
- })
68
+ run.number !== null ? /*#__PURE__*/ _jsx(WorkflowRunNumberLabel, {
69
+ run: run
70
+ }) : null
68
71
  ]
69
72
  }),
70
73
  /*#__PURE__*/ _jsxs("span", {
71
- className: "ml-auto flex shrink-0 items-center gap-6",
74
+ className: "flex min-w-0 flex-wrap items-center gap-10 text-foreground-neutral-subtle @min-[976px]:flex-nowrap @min-[976px]:shrink-0",
72
75
  children: [
73
- /*#__PURE__*/ _jsx(WorkflowRunDurationLabel, {
74
- duration: run.runAttempt.displayDuration,
75
- className: "text-foreground-neutral-disabled"
76
- }),
77
- durationLabel ? /*#__PURE__*/ _jsx(RunMetadataSeparator, {}) : null,
78
- /*#__PURE__*/ _jsx(Code, {
79
- variant: "label",
80
- className: "shrink-0 text-foreground-neutral-disabled",
81
- children: /*#__PURE__*/ _jsx(RelativeTime, {
82
- value: run.updatedAt
83
- })
84
- })
76
+ run.triggerDisplayLabel ? /*#__PURE__*/ _jsx(TriggerLabel, {
77
+ run: run
78
+ }) : null,
79
+ branch ? /*#__PURE__*/ _jsx(BranchLabel, {
80
+ branch: branch,
81
+ isPullRequest: branch.startsWith('#')
82
+ }) : null,
83
+ commit ? /*#__PURE__*/ _jsx(CommitLabel, {
84
+ commit: commit
85
+ }) : null,
86
+ actor ? /*#__PURE__*/ _jsx(ActorLabel, {
87
+ actor: actor
88
+ }) : null
85
89
  ]
86
90
  })
87
91
  ]
92
+ }),
93
+ /*#__PURE__*/ _jsxs("span", {
94
+ className: "flex shrink-0 items-center gap-12",
95
+ children: [
96
+ /*#__PURE__*/ _jsx("span", {
97
+ className: "hidden w-160 @min-[1040px]:flex",
98
+ children: /*#__PURE__*/ _jsx(JobStatusStrip, {
99
+ jobs: run.jobs
100
+ })
101
+ }),
102
+ /*#__PURE__*/ _jsx("span", {
103
+ className: "flex w-64 justify-end",
104
+ children: /*#__PURE__*/ _jsx(WorkflowRunDurationLabel, {
105
+ duration: run.runAttempt.displayDuration
106
+ })
107
+ }),
108
+ /*#__PURE__*/ _jsx(Code, {
109
+ variant: "label",
110
+ className: "w-64 shrink-0 text-right tabular-nums text-foreground-neutral-muted",
111
+ children: /*#__PURE__*/ _jsx(RelativeTime, {
112
+ value: run.createdAt
113
+ })
114
+ })
115
+ ]
88
116
  })
89
117
  ]
90
118
  });
119
+ // Rows run edge to edge inside the list's scroll container, which would clip the standard
120
+ // outset focus ring, so this one is inset per the design system's focus-ring rule.
121
+ const rowClassName = 'flex w-full min-w-0 items-center gap-10 px-12 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';
91
122
  // Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row
92
123
  // replaces them on the next poll, so they render non-interactively instead of as a link
93
124
  // that would navigate to a workflow run id the detail route rejects.
94
- if (run.isTemporary) {
125
+ if (run.isTemporary || !workspaceSlug || !projectSlug) {
95
126
  return /*#__PURE__*/ _jsx("div", {
96
- className: "relative flex w-full flex-col gap-4 rounded-8 border border-transparent px-10 py-8 text-left",
127
+ className: rowClassName,
97
128
  children: body
98
129
  });
99
130
  }
100
- const runLink = /*#__PURE__*/ _jsx(Link, {
101
- to: "/workspaces/$wid/projects/$pid/runs/$workflowRunId",
131
+ return /*#__PURE__*/ _jsx(Link, {
132
+ to: "/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId",
102
133
  params: {
103
- wid: workspaceId,
104
- pid: projectId,
134
+ workspaceSlug,
135
+ projectSlug,
105
136
  workflowRunId: run.id
106
137
  },
107
138
  search: (previous)=>withoutWorkflowRunSelectionSearch(previous),
108
- "aria-current": selected ? 'page' : undefined,
139
+ // An aria-label is the link's whole accessible name, so anything inside the row that
140
+ // carries its own label (the status glyph, the job strip) goes unspoken unless it is
141
+ // curated in here. The job breakdown is the reason this list is worth its width, so it
142
+ // belongs in what a tabbing user hears, not only in browse mode.
109
143
  "aria-label": [
110
144
  run.name,
145
+ runNumberLabel,
111
146
  statusLabel,
112
147
  durationLabel,
113
- run.triggerLabel
148
+ run.triggerLabel,
149
+ branch ? `branch ${branch}` : undefined,
150
+ actor ? `by ${actor}` : undefined,
151
+ run.jobs.total > 0 ? jobStatusSummary(run.jobs) : undefined
114
152
  ].filter((part)=>Boolean(part)).join(', '),
115
- className: cn('group relative flex w-full flex-col gap-4 rounded-8 border border-transparent px-10 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-border-interactive-with-active focus-visible:outline-none', selected && 'bg-background-components-hover'),
153
+ className: rowClassName,
116
154
  children: body
117
155
  });
118
- return runLink;
119
156
  }
120
157
  function TriggerLabel({ run }) {
121
- return /*#__PURE__*/ _jsx("span", {
122
- className: "flex min-w-0 flex-1 items-center",
123
- children: /*#__PURE__*/ _jsxs(Tooltip, {
124
- children: [
125
- /*#__PURE__*/ _jsx(TooltipTrigger, {
126
- asChild: true,
127
- children: /*#__PURE__*/ _jsxs("span", {
128
- className: "flex w-fit max-w-full min-w-0 items-center gap-8 rounded-6 outline-none",
129
- children: [
130
- /*#__PURE__*/ _jsx(TriggerSourceIcon, {
131
- provider: run.triggerProvider,
132
- source: run.triggerSource,
133
- "aria-hidden": true,
134
- className: "size-14 shrink-0 text-foreground-neutral-muted"
135
- }),
136
- /*#__PURE__*/ _jsx(Text, {
137
- as: "span",
138
- size: "xs",
139
- className: "min-w-0 truncate text-foreground-neutral-subtle",
140
- children: run.triggerDisplayLabel
141
- })
142
- ]
143
- })
144
- }),
145
- /*#__PURE__*/ _jsx(TriggerTooltip, {
146
- label: run.triggerLabel
158
+ return /*#__PURE__*/ _jsxs(Tooltip, {
159
+ children: [
160
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
161
+ asChild: true,
162
+ children: /*#__PURE__*/ _jsxs("span", {
163
+ className: "flex min-w-0 max-w-[140px] items-center gap-6 outline-none",
164
+ children: [
165
+ /*#__PURE__*/ _jsx(TriggerSourceIcon, {
166
+ provider: run.triggerProvider,
167
+ source: run.triggerSource,
168
+ "aria-hidden": "true",
169
+ className: "size-12 shrink-0 text-foreground-neutral-muted"
170
+ }),
171
+ /*#__PURE__*/ _jsx(Text, {
172
+ as: "span",
173
+ size: "xs",
174
+ className: "min-w-0 truncate",
175
+ children: run.triggerDisplayLabel
176
+ })
177
+ ]
178
+ })
179
+ }),
180
+ /*#__PURE__*/ _jsx(TooltipContent, {
181
+ children: /*#__PURE__*/ _jsx(Text, {
182
+ as: "span",
183
+ size: "xs",
184
+ className: "block max-w-[360px] break-words",
185
+ children: run.triggerLabel
147
186
  })
148
- ]
149
- })
187
+ })
188
+ ]
189
+ });
190
+ }
191
+ function BranchLabel({ branch, isPullRequest }) {
192
+ return /*#__PURE__*/ _jsx(MetadataChip, {
193
+ icon: isPullRequest ? 'gitPullRequestLine' : 'gitBranchLine',
194
+ title: isPullRequest ? `Pull request ${branch}` : `Branch ${branch}`,
195
+ className: "max-w-[180px]",
196
+ children: branch
197
+ });
198
+ }
199
+ function CommitLabel({ commit }) {
200
+ return /*#__PURE__*/ _jsx(MetadataChip, {
201
+ icon: "gitCommitLine",
202
+ title: `Commit ${commit}`,
203
+ children: commit
150
204
  });
151
205
  }
152
- function TriggerTooltip({ label }) {
153
- return /*#__PURE__*/ _jsx(TooltipContent, {
154
- children: /*#__PURE__*/ _jsx(Text, {
155
- as: "span",
156
- size: "xs",
157
- className: "block max-w-[360px] break-words",
158
- children: label
159
- })
206
+ function ActorLabel({ actor }) {
207
+ return /*#__PURE__*/ _jsx(MetadataChip, {
208
+ icon: "userLine",
209
+ title: `Triggered by ${actor}`,
210
+ // Dropped once the row is two lines, where the provenance line has to stay readable on
211
+ // a phone.
212
+ className: "hidden max-w-[120px] @min-[976px]:flex",
213
+ children: actor
160
214
  });
161
215
  }
162
- function RunMetadataSeparator() {
163
- return /*#__PURE__*/ _jsx(Code, {
164
- as: "span",
165
- variant: "label",
166
- "aria-hidden": "true",
167
- className: "shrink-0 text-foreground-neutral-disabled",
168
- children: "·"
216
+ /**
217
+ * A ref, SHA, or handle: monospace because it is content a user copies or pattern-matches,
218
+ * with the icon carrying the kind so the value itself never needs a written label.
219
+ */ function MetadataChip({ icon, title, className, children }) {
220
+ return /*#__PURE__*/ _jsxs("span", {
221
+ className: cn('flex min-w-0 shrink-0 items-center gap-4', className),
222
+ title: title,
223
+ children: [
224
+ /*#__PURE__*/ _jsx(Icon, {
225
+ name: icon,
226
+ className: "size-12 shrink-0 text-foreground-neutral-muted",
227
+ "aria-hidden": true
228
+ }),
229
+ /*#__PURE__*/ _jsx(Code, {
230
+ as: "span",
231
+ variant: "label",
232
+ className: "min-w-0 truncate",
233
+ children: children
234
+ })
235
+ ]
169
236
  });
170
237
  }
171
238
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {\n useWorkflowRunDurationAccessibleLabel,\n WorkflowRunDurationLabel,\n} from '#components/workflow-run-duration-label.js';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {WorkflowRunListItem} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\n\nexport function WorkflowRunRowList({\n runs,\n workspaceId,\n projectId,\n selectedWorkflowRunId,\n}: {\n runs: WorkflowRunListItem[];\n workspaceId: string;\n projectId: string;\n selectedWorkflowRunId?: string | undefined;\n}) {\n return (\n <nav aria-label=\"Run history\">\n <ul className=\"flex flex-col gap-4 p-8\">\n {runs.map((run) => (\n <li key={run.id}>\n <WorkflowRunRow\n run={run}\n workspaceId={workspaceId}\n projectId={projectId}\n selected={run.id === selectedWorkflowRunId}\n />\n </li>\n ))}\n </ul>\n </nav>\n );\n}\n\nexport function WorkflowRunRow({\n run,\n workspaceId,\n projectId,\n selected,\n}: {\n run: WorkflowRunListItem;\n workspaceId: string;\n projectId: string;\n selected: boolean;\n}) {\n const durationLabel = useWorkflowRunDurationAccessibleLabel(run.runAttempt.displayDuration);\n const statusLabel = getWorkflowStatusVisual(run.status).label;\n const body = (\n <>\n {selected ? (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-y-8 left-0 w-3 rounded-full bg-border-highlights-interactive\"\n />\n ) : null}\n\n <div className=\"flex min-w-0 items-center gap-8\">\n <WorkflowStatusIcon status={run.status} size={14} />\n <Code variant=\"label\" bold className=\"truncate text-foreground-neutral-base\">\n {run.name}\n </Code>\n </div>\n\n <div className=\"flex min-w-0 items-center gap-8\">\n {run.triggerDisplayLabel ? (\n <TriggerLabel run={run} />\n ) : (\n <span className=\"flex min-w-0 flex-1 items-center gap-8 truncate text-foreground-neutral-muted\">\n <span aria-hidden=\"true\" className=\"size-14 shrink-0\" />\n <span className=\"sr-only\">Run updated </span>\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-6\">\n <WorkflowRunDurationLabel\n duration={run.runAttempt.displayDuration}\n className=\"text-foreground-neutral-disabled\"\n />\n {durationLabel ? <RunMetadataSeparator /> : null}\n <Code variant=\"label\" className=\"shrink-0 text-foreground-neutral-disabled\">\n <RelativeTime value={run.updatedAt} />\n </Code>\n </span>\n </div>\n </>\n );\n\n // Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row\n // replaces them on the next poll, so they render non-interactively instead of as a link\n // that would navigate to a workflow run id the detail route rejects.\n if (run.isTemporary) {\n return (\n <div className=\"relative flex w-full flex-col gap-4 rounded-8 border border-transparent px-10 py-8 text-left\">\n {body}\n </div>\n );\n }\n\n const runLink = (\n <Link\n to=\"/workspaces/$wid/projects/$pid/runs/$workflowRunId\"\n params={{wid: workspaceId, pid: projectId, workflowRunId: run.id}}\n search={\n ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never\n }\n aria-current={selected ? 'page' : undefined}\n aria-label={[run.name, statusLabel, durationLabel, run.triggerLabel]\n .filter((part): part is string => Boolean(part))\n .join(', ')}\n className={cn(\n 'group relative flex w-full flex-col gap-4 rounded-8 border border-transparent px-10 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-border-interactive-with-active focus-visible:outline-none',\n selected && 'bg-background-components-hover',\n )}\n >\n {body}\n </Link>\n );\n\n return runLink;\n}\n\nfunction TriggerLabel({run}: {run: WorkflowRunListItem}) {\n return (\n <span className=\"flex min-w-0 flex-1 items-center\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex w-fit max-w-full min-w-0 items-center gap-8 rounded-6 outline-none\">\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden\n className=\"size-14 shrink-0 text-foreground-neutral-muted\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate text-foreground-neutral-subtle\">\n {run.triggerDisplayLabel}\n </Text>\n </span>\n </TooltipTrigger>\n <TriggerTooltip label={run.triggerLabel} />\n </Tooltip>\n </span>\n );\n}\n\nfunction TriggerTooltip({label}: {label: string}) {\n return (\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {label}\n </Text>\n </TooltipContent>\n );\n}\n\nfunction RunMetadataSeparator() {\n return (\n <Code\n as=\"span\"\n variant=\"label\"\n aria-hidden=\"true\"\n className=\"shrink-0 text-foreground-neutral-disabled\"\n >\n ·\n </Code>\n );\n}\n"],"names":["TriggerSourceIcon","RelativeTime","Tooltip","TooltipContent","TooltipTrigger","Code","Text","cn","Link","useWorkflowRunDurationAccessibleLabel","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowStatusIcon","withoutWorkflowRunSelectionSearch","WorkflowRunRowList","runs","workspaceId","projectId","selectedWorkflowRunId","nav","aria-label","ul","className","map","run","li","WorkflowRunRow","selected","id","durationLabel","runAttempt","displayDuration","statusLabel","status","label","body","span","aria-hidden","div","size","variant","bold","name","triggerDisplayLabel","TriggerLabel","duration","RunMetadataSeparator","value","updatedAt","isTemporary","runLink","to","params","wid","pid","workflowRunId","search","previous","aria-current","undefined","triggerLabel","filter","part","Boolean","join","asChild","provider","triggerProvider","source","triggerSource","as","TriggerTooltip"],"mappings":";AAAA,SAAQA,iBAAiB,QAAO,2BAA2B;AAC3D,SAAQC,YAAY,QAAO,kCAAkC;AAC7D,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,EAAEC,IAAI,QAAO,+BAA+B;AACxD,SAAQC,EAAE,QAAO,0BAA0B;AAC3C,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SACEC,qCAAqC,EACrCC,wBAAwB,QACnB,6CAA6C;AACpD,SAAQC,uBAAuB,QAAO,gDAAgD;AACtF,SAAQC,kBAAkB,QAAO,sDAAsD;AAEvF,SAAQC,iCAAiC,QAAO,kCAAkC;AAElF,OAAO,SAASC,mBAAmB,EACjCC,IAAI,EACJC,WAAW,EACXC,SAAS,EACTC,qBAAqB,EAMtB;IACC,qBACE,KAACC;QAAIC,cAAW;kBACd,cAAA,KAACC;YAAGC,WAAU;sBACXP,KAAKQ,GAAG,CAAC,CAACC,oBACT,KAACC;8BACC,cAAA,KAACC;wBACCF,KAAKA;wBACLR,aAAaA;wBACbC,WAAWA;wBACXU,UAAUH,IAAII,EAAE,KAAKV;;mBALhBM,IAAII,EAAE;;;AAYzB;AAEA,OAAO,SAASF,eAAe,EAC7BF,GAAG,EACHR,WAAW,EACXC,SAAS,EACTU,QAAQ,EAMT;IACC,MAAME,gBAAgBpB,sCAAsCe,IAAIM,UAAU,CAACC,eAAe;IAC1F,MAAMC,cAAcrB,wBAAwBa,IAAIS,MAAM,EAAEC,KAAK;IAC7D,MAAMC,qBACJ;;YACGR,yBACC,KAACS;gBACCC,eAAY;gBACZf,WAAU;iBAEV;0BAEJ,MAACgB;gBAAIhB,WAAU;;kCACb,KAACV;wBAAmBqB,QAAQT,IAAIS,MAAM;wBAAEM,MAAM;;kCAC9C,KAAClC;wBAAKmC,SAAQ;wBAAQC,IAAI;wBAACnB,WAAU;kCAClCE,IAAIkB,IAAI;;;;0BAIb,MAACJ;gBAAIhB,WAAU;;oBACZE,IAAImB,mBAAmB,iBACtB,KAACC;wBAAapB,KAAKA;uCAEnB,MAACY;wBAAKd,WAAU;;0CACd,KAACc;gCAAKC,eAAY;gCAAOf,WAAU;;0CACnC,KAACc;gCAAKd,WAAU;0CAAU;;;;kCAG9B,MAACc;wBAAKd,WAAU;;0CACd,KAACZ;gCACCmC,UAAUrB,IAAIM,UAAU,CAACC,eAAe;gCACxCT,WAAU;;4BAEXO,8BAAgB,KAACiB,4BAA0B;0CAC5C,KAACzC;gCAAKmC,SAAQ;gCAAQlB,WAAU;0CAC9B,cAAA,KAACrB;oCAAa8C,OAAOvB,IAAIwB,SAAS;;;;;;;;;IAO5C,mFAAmF;IACnF,wFAAwF;IACxF,qEAAqE;IACrE,IAAIxB,IAAIyB,WAAW,EAAE;QACnB,qBACE,KAACX;YAAIhB,WAAU;sBACZa;;IAGP;IAEA,MAAMe,wBACJ,KAAC1C;QACC2C,IAAG;QACHC,QAAQ;YAACC,KAAKrC;YAAasC,KAAKrC;YAAWsC,eAAe/B,IAAII,EAAE;QAAA;QAChE4B,QACG,CAACC,WACA5C,kCAAkC4C;QAEtCC,gBAAc/B,WAAW,SAASgC;QAClCvC,cAAY;YAACI,IAAIkB,IAAI;YAAEV;YAAaH;YAAeL,IAAIoC,YAAY;SAAC,CACjEC,MAAM,CAAC,CAACC,OAAyBC,QAAQD,OACzCE,IAAI,CAAC;QACR1C,WAAWf,GACT,4OACAoB,YAAY;kBAGbQ;;IAIL,OAAOe;AACT;AAEA,SAASN,aAAa,EAACpB,GAAG,EAA6B;IACrD,qBACE,KAACY;QAAKd,WAAU;kBACd,cAAA,MAACpB;;8BACC,KAACE;oBAAe6D,OAAO;8BACrB,cAAA,MAAC7B;wBAAKd,WAAU;;0CACd,KAACtB;gCACCkE,UAAU1C,IAAI2C,eAAe;gCAC7BC,QAAQ5C,IAAI6C,aAAa;gCACzBhC,aAAW;gCACXf,WAAU;;0CAEZ,KAAChB;gCAAKgE,IAAG;gCAAO/B,MAAK;gCAAKjB,WAAU;0CACjCE,IAAImB,mBAAmB;;;;;8BAI9B,KAAC4B;oBAAerC,OAAOV,IAAIoC,YAAY;;;;;AAI/C;AAEA,SAASW,eAAe,EAACrC,KAAK,EAAkB;IAC9C,qBACE,KAAC/B;kBACC,cAAA,KAACG;YAAKgE,IAAG;YAAO/B,MAAK;YAAKjB,WAAU;sBACjCY;;;AAIT;AAEA,SAASY;IACP,qBACE,KAACzC;QACCiE,IAAG;QACH9B,SAAQ;QACRH,eAAY;QACZf,WAAU;kBACX;;AAIL"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {\n useWorkflowRunDurationAccessibleLabel,\n WorkflowRunDurationLabel,\n} from '#components/workflow-run-duration-label.js';\nimport {\n formatWorkflowRunNumberLabel,\n WorkflowRunNumberLabel,\n} from '#components/workflow-run-number-label.js';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport {\n type WorkflowRunListItem,\n workflowRunActor,\n workflowRunBranchLabel,\n workflowRunCommitLabel,\n} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {JobStatusStrip, jobStatusSummary} from './job-status-strip.js';\n\nexport function WorkflowRunRowList({\n runs,\n workspaceSlug,\n projectSlug,\n}: {\n runs: WorkflowRunListItem[];\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n return (\n // A container, not the viewport, drives the row's breakpoints. The list is capped at\n // 1120px inside a wider page, so what a row can afford is its own width; keying off the\n // viewport would keep the job strip hidden on a wide screen or crush it on a narrow one.\n <ul className=\"@container divide-y divide-border-neutral-base border-t border-border-neutral-base\">\n {runs.map((run) => (\n <li key={run.id}>\n <WorkflowRunRow run={run} workspaceSlug={workspaceSlug} projectSlug={projectSlug} />\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * One run at full width.\n *\n * A single 44px line once the list is at least 976px wide, reflowing to two lines below that:\n * the identity and the numerics keep their places on line one, and the provenance metadata\n * drops beneath. The numeric columns are fixed-width so duration and time form real columns\n * down the list rather than tracking each row's name length.\n *\n * The thresholds are the container widths the spec's viewport breakpoints produce, given a\n * column capped at 1120px with 24px of page padding on each side: a 1280px viewport leaves\n * the row 1072px, and a 1024px viewport leaves it 976px.\n */\nexport function WorkflowRunRow({\n run,\n workspaceSlug,\n projectSlug,\n}: {\n run: WorkflowRunListItem;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n const durationLabel = useWorkflowRunDurationAccessibleLabel(run.runAttempt.displayDuration);\n const statusLabel = getWorkflowStatusVisual(run.status).label;\n const runNumberLabel = formatWorkflowRunNumberLabel(run);\n const branch = workflowRunBranchLabel(run);\n const commit = workflowRunCommitLabel(run);\n const actor = workflowRunActor(run);\n\n const body = (\n <>\n <WorkflowStatusIcon status={run.status} size={14} className=\"shrink-0\" />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-2 @min-[976px]:flex-row @min-[976px]:items-center @min-[976px]:gap-12\">\n <span className=\"flex min-w-0 items-center gap-8 @min-[976px]:flex-1\">\n <Code variant=\"label\" bold className=\"truncate text-foreground-neutral-base\">\n {run.name}\n </Code>\n {run.number !== null ? <WorkflowRunNumberLabel run={run} /> : null}\n </span>\n\n <span className=\"flex min-w-0 flex-wrap items-center gap-10 text-foreground-neutral-subtle @min-[976px]:flex-nowrap @min-[976px]:shrink-0\">\n {run.triggerDisplayLabel ? <TriggerLabel run={run} /> : null}\n {branch ? <BranchLabel branch={branch} isPullRequest={branch.startsWith('#')} /> : null}\n {commit ? <CommitLabel commit={commit} /> : null}\n {actor ? <ActorLabel actor={actor} /> : null}\n </span>\n </div>\n\n <span className=\"flex shrink-0 items-center gap-12\">\n {/* Fixed at the strip's worst case (see MAX_VISIBLE_JOBS) so the overflow count cannot\n paint over the duration, and kept even when a run has no jobs planned yet, so the\n numerics stay in line down the list instead of stepping in and out. */}\n <span className=\"hidden w-160 @min-[1040px]:flex\">\n <JobStatusStrip jobs={run.jobs} />\n </span>\n <span className=\"flex w-64 justify-end\">\n <WorkflowRunDurationLabel duration={run.runAttempt.displayDuration} />\n </span>\n <Code\n variant=\"label\"\n className=\"w-64 shrink-0 text-right tabular-nums text-foreground-neutral-muted\"\n >\n <RelativeTime value={run.createdAt} />\n </Code>\n </span>\n </>\n );\n\n // Rows run edge to edge inside the list's scroll container, which would clip the standard\n // outset focus ring, so this one is inset per the design system's focus-ring rule.\n const rowClassName =\n 'flex w-full min-w-0 items-center gap-10 px-12 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';\n\n // Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row\n // replaces them on the next poll, so they render non-interactively instead of as a link\n // that would navigate to a workflow run id the detail route rejects.\n if (run.isTemporary || !workspaceSlug || !projectSlug) {\n return <div className={rowClassName}>{body}</div>;\n }\n\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id}}\n search={\n ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never\n }\n // An aria-label is the link's whole accessible name, so anything inside the row that\n // carries its own label (the status glyph, the job strip) goes unspoken unless it is\n // curated in here. The job breakdown is the reason this list is worth its width, so it\n // belongs in what a tabbing user hears, not only in browse mode.\n aria-label={[\n run.name,\n runNumberLabel,\n statusLabel,\n durationLabel,\n run.triggerLabel,\n branch ? `branch ${branch}` : undefined,\n actor ? `by ${actor}` : undefined,\n run.jobs.total > 0 ? jobStatusSummary(run.jobs) : undefined,\n ]\n .filter((part): part is string => Boolean(part))\n .join(', ')}\n className={rowClassName}\n >\n {body}\n </Link>\n );\n}\n\nfunction TriggerLabel({run}: {run: WorkflowRunListItem}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex min-w-0 max-w-[140px] items-center gap-6 outline-none\">\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0 text-foreground-neutral-muted\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </span>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {run.triggerLabel}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction BranchLabel({branch, isPullRequest}: {branch: string; isPullRequest: boolean}) {\n return (\n <MetadataChip\n icon={isPullRequest ? 'gitPullRequestLine' : 'gitBranchLine'}\n title={isPullRequest ? `Pull request ${branch}` : `Branch ${branch}`}\n className=\"max-w-[180px]\"\n >\n {branch}\n </MetadataChip>\n );\n}\n\nfunction CommitLabel({commit}: {commit: string}) {\n return (\n <MetadataChip icon=\"gitCommitLine\" title={`Commit ${commit}`}>\n {commit}\n </MetadataChip>\n );\n}\n\nfunction ActorLabel({actor}: {actor: string}) {\n return (\n <MetadataChip\n icon=\"userLine\"\n title={`Triggered by ${actor}`}\n // Dropped once the row is two lines, where the provenance line has to stay readable on\n // a phone.\n className=\"hidden max-w-[120px] @min-[976px]:flex\"\n >\n {actor}\n </MetadataChip>\n );\n}\n\n/**\n * A ref, SHA, or handle: monospace because it is content a user copies or pattern-matches,\n * with the icon carrying the kind so the value itself never needs a written label.\n */\nfunction MetadataChip({\n icon,\n title,\n className,\n children,\n}: {\n icon: IconName;\n title: string;\n className?: string | undefined;\n children: string;\n}) {\n return (\n <span className={cn('flex min-w-0 shrink-0 items-center gap-4', className)} title={title}>\n <Icon name={icon} className=\"size-12 shrink-0 text-foreground-neutral-muted\" aria-hidden />\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 truncate\">\n {children}\n </Code>\n </span>\n );\n}\n"],"names":["TriggerSourceIcon","Icon","RelativeTime","Tooltip","TooltipContent","TooltipTrigger","Code","Text","cn","Link","useWorkflowRunDurationAccessibleLabel","WorkflowRunDurationLabel","formatWorkflowRunNumberLabel","WorkflowRunNumberLabel","getWorkflowStatusVisual","WorkflowStatusIcon","workflowRunActor","workflowRunBranchLabel","workflowRunCommitLabel","withoutWorkflowRunSelectionSearch","JobStatusStrip","jobStatusSummary","WorkflowRunRowList","runs","workspaceSlug","projectSlug","ul","className","map","run","li","WorkflowRunRow","id","durationLabel","runAttempt","displayDuration","statusLabel","status","label","runNumberLabel","branch","commit","actor","body","size","div","span","variant","bold","name","number","triggerDisplayLabel","TriggerLabel","BranchLabel","isPullRequest","startsWith","CommitLabel","ActorLabel","jobs","duration","value","createdAt","rowClassName","isTemporary","to","params","workflowRunId","search","previous","aria-label","triggerLabel","undefined","total","filter","part","Boolean","join","asChild","provider","triggerProvider","source","triggerSource","aria-hidden","as","MetadataChip","icon","title","children"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { WorkflowRun } from '#core/workflow-run.js';
2
+ type WorkflowRunNumberLabelRun = Pick<WorkflowRun, 'number' | 'workflowName'> & Partial<Pick<WorkflowRun, 'name'>>;
3
+ export declare function formatWorkflowRunNumberLabel({ number, workflowName, }: WorkflowRunNumberLabelRun): string | undefined;
4
+ /**
5
+ * The run's identity beside its name.
6
+ *
7
+ * A run whose name was never overridden carries its workflow name twice on one line, so the
8
+ * visible label drops to the bare number in that case. The full label stays in the tooltip
9
+ * and in `formatWorkflowRunNumberLabel`, which feeds accessible names.
10
+ */
11
+ export declare function WorkflowRunNumberLabel({ run }: {
12
+ run: WorkflowRunNumberLabelRun;
13
+ }): import("react").JSX.Element | null;
14
+ export {};
15
+ //# sourceMappingURL=workflow-run-number-label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-run-number-label.d.ts","sourceRoot":"","sources":["../../src/components/workflow-run-number-label.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAEvD,KAAK,yBAAyB,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,cAAc,CAAC,GAC3E,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;AAErC,wBAAgB,4BAA4B,CAAC,EAC3C,MAAM,EACN,YAAY,GACb,EAAE,yBAAyB,GAAG,MAAM,GAAG,SAAS,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,EAAC,GAAG,EAAC,EAAE;IAAC,GAAG,EAAE,yBAAyB,CAAA;CAAC,sCAyB7E"}
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
3
+ import { Code } from '@shipfox/react-ui/typography';
4
+ export function formatWorkflowRunNumberLabel({ number, workflowName }) {
5
+ return number === null ? undefined : `${workflowName} #${number}`;
6
+ }
7
+ /**
8
+ * The run's identity beside its name.
9
+ *
10
+ * A run whose name was never overridden carries its workflow name twice on one line, so the
11
+ * visible label drops to the bare number in that case. The full label stays in the tooltip
12
+ * and in `formatWorkflowRunNumberLabel`, which feeds accessible names.
13
+ */ export function WorkflowRunNumberLabel({ run }) {
14
+ const label = formatWorkflowRunNumberLabel(run);
15
+ if (label === undefined) return null;
16
+ const namesTheWorkflowTwice = run.name === run.workflowName;
17
+ const visibleLabel = namesTheWorkflowTwice ? `#${run.number}` : label;
18
+ return /*#__PURE__*/ _jsxs(Tooltip, {
19
+ children: [
20
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
21
+ asChild: true,
22
+ children: /*#__PURE__*/ _jsx(Code, {
23
+ as: "span",
24
+ variant: "label",
25
+ className: "min-w-0 max-w-[240px] truncate text-foreground-neutral-muted",
26
+ children: visibleLabel
27
+ })
28
+ }),
29
+ /*#__PURE__*/ _jsx(TooltipContent, {
30
+ children: /*#__PURE__*/ _jsx(Code, {
31
+ as: "span",
32
+ variant: "label",
33
+ className: "block max-w-[360px] break-words",
34
+ children: label
35
+ })
36
+ })
37
+ ]
38
+ });
39
+ }
40
+
41
+ //# sourceMappingURL=workflow-run-number-label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/workflow-run-number-label.tsx"],"sourcesContent":["import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code} from '@shipfox/react-ui/typography';\nimport type {WorkflowRun} from '#core/workflow-run.js';\n\ntype WorkflowRunNumberLabelRun = Pick<WorkflowRun, 'number' | 'workflowName'> &\n Partial<Pick<WorkflowRun, 'name'>>;\n\nexport function formatWorkflowRunNumberLabel({\n number,\n workflowName,\n}: WorkflowRunNumberLabelRun): string | undefined {\n return number === null ? undefined : `${workflowName} #${number}`;\n}\n\n/**\n * The run's identity beside its name.\n *\n * A run whose name was never overridden carries its workflow name twice on one line, so the\n * visible label drops to the bare number in that case. The full label stays in the tooltip\n * and in `formatWorkflowRunNumberLabel`, which feeds accessible names.\n */\nexport function WorkflowRunNumberLabel({run}: {run: WorkflowRunNumberLabelRun}) {\n const label = formatWorkflowRunNumberLabel(run);\n if (label === undefined) return null;\n\n const namesTheWorkflowTwice = run.name === run.workflowName;\n const visibleLabel = namesTheWorkflowTwice ? `#${run.number}` : label;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Code\n as=\"span\"\n variant=\"label\"\n className=\"min-w-0 max-w-[240px] truncate text-foreground-neutral-muted\"\n >\n {visibleLabel}\n </Code>\n </TooltipTrigger>\n <TooltipContent>\n <Code as=\"span\" variant=\"label\" className=\"block max-w-[360px] break-words\">\n {label}\n </Code>\n </TooltipContent>\n </Tooltip>\n );\n}\n"],"names":["Tooltip","TooltipContent","TooltipTrigger","Code","formatWorkflowRunNumberLabel","number","workflowName","undefined","WorkflowRunNumberLabel","run","label","namesTheWorkflowTwice","name","visibleLabel","asChild","as","variant","className"],"mappings":";AAAA,SAAQA,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAMlD,OAAO,SAASC,6BAA6B,EAC3CC,MAAM,EACNC,YAAY,EACc;IAC1B,OAAOD,WAAW,OAAOE,YAAY,GAAGD,aAAa,EAAE,EAAED,QAAQ;AACnE;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,uBAAuB,EAACC,GAAG,EAAmC;IAC5E,MAAMC,QAAQN,6BAA6BK;IAC3C,IAAIC,UAAUH,WAAW,OAAO;IAEhC,MAAMI,wBAAwBF,IAAIG,IAAI,KAAKH,IAAIH,YAAY;IAC3D,MAAMO,eAAeF,wBAAwB,CAAC,CAAC,EAAEF,IAAIJ,MAAM,EAAE,GAAGK;IAEhE,qBACE,MAACV;;0BACC,KAACE;gBAAeY,OAAO;0BACrB,cAAA,KAACX;oBACCY,IAAG;oBACHC,SAAQ;oBACRC,WAAU;8BAETJ;;;0BAGL,KAACZ;0BACC,cAAA,KAACE;oBAAKY,IAAG;oBAAOC,SAAQ;oBAAQC,WAAU;8BACvCP;;;;;AAKX"}
@@ -1,9 +1,9 @@
1
1
  import type { WorkflowRunDetail } from '#core/workflow-run.js';
2
2
  export interface WorkflowRunAttemptSwitcherProps {
3
- workspaceId: string;
4
- projectId: string;
3
+ workspaceSlug?: string | undefined;
4
+ projectSlug?: string | undefined;
5
5
  run: WorkflowRunDetail;
6
6
  latestAttempt: number;
7
7
  }
8
- export declare function WorkflowRunAttemptSwitcher({ workspaceId, projectId, run, latestAttempt, }: WorkflowRunAttemptSwitcherProps): import("react").JSX.Element | null;
8
+ export declare function WorkflowRunAttemptSwitcher({ workspaceSlug, projectSlug, run, latestAttempt, }: WorkflowRunAttemptSwitcherProps): import("react").JSX.Element | null;
9
9
  //# sourceMappingURL=workflow-run-attempt-switcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-attempt-switcher.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAqB,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAKjF,MAAM,WAAW,+BAA+B;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,iBAAiB,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,WAAW,EACX,SAAS,EACT,GAAG,EACH,aAAa,GACd,EAAE,+BAA+B,sCAsDjC"}
1
+ {"version":3,"file":"workflow-run-attempt-switcher.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAqB,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAKjF,MAAM,WAAW,+BAA+B;IAC9C,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,GAAG,EAAE,iBAAiB,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,aAAa,EACb,WAAW,EACX,GAAG,EACH,aAAa,GACd,EAAE,+BAA+B,sCAuDjC"}
@@ -9,13 +9,14 @@ import { useState } from 'react';
9
9
  import { withoutWorkflowRunSelectionSearch } from '#core/workflow-run-url-state.js';
10
10
  import { useWorkflowRunAttemptsQuery } from '#hooks/api/workflow-runs.js';
11
11
  import { WorkflowStatusIcon } from '../workflow-status/workflow-status-icon.js';
12
- export function WorkflowRunAttemptSwitcher({ workspaceId, projectId, run, latestAttempt }) {
12
+ export function WorkflowRunAttemptSwitcher({ workspaceSlug, projectSlug, run, latestAttempt }) {
13
13
  const [open, setOpen] = useState(false);
14
14
  const attemptsQuery = useWorkflowRunAttemptsQuery({
15
15
  workflowRunId: run.id,
16
16
  enabled: open
17
17
  });
18
18
  if (latestAttempt <= 1) return null;
19
+ if (!workspaceSlug || !projectSlug) return null;
19
20
  const attempts = attemptsQuery.data ?? [];
20
21
  const latestLoadedAttempt = Math.max(0, ...attempts.map((attempt)=>attempt.attempt));
21
22
  const maxAttempt = Math.max(latestAttempt, run.runAttempt.attempt, latestLoadedAttempt);
@@ -61,8 +62,8 @@ export function WorkflowRunAttemptSwitcher({ workspaceId, projectId, run, latest
61
62
  attempt: attempt,
62
63
  current: attempt.id === run.runAttempt.id,
63
64
  workflowRunId: run.id,
64
- workspaceId: workspaceId,
65
- projectId: projectId
65
+ workspaceSlug: workspaceSlug,
66
+ projectSlug: projectSlug
66
67
  }, attempt.id)) : null
67
68
  ]
68
69
  })
@@ -92,15 +93,15 @@ function ErrorRow({ onRetry }) {
92
93
  })
93
94
  });
94
95
  }
95
- function AttemptItem({ attempt, current, workflowRunId, workspaceId, projectId }) {
96
+ function AttemptItem({ attempt, current, workflowRunId, workspaceSlug, projectSlug }) {
96
97
  return /*#__PURE__*/ _jsx(DropdownMenuItem, {
97
98
  asChild: true,
98
99
  className: cn(current && 'text-foreground-neutral-base'),
99
100
  children: /*#__PURE__*/ _jsxs(Link, {
100
- to: "/workspaces/$wid/projects/$pid/runs/$workflowRunId",
101
+ to: "/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId",
101
102
  params: {
102
- wid: workspaceId,
103
- pid: projectId,
103
+ workspaceSlug,
104
+ projectSlug,
104
105
  workflowRunId
105
106
  },
106
107
  search: (previous)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useState} from 'react';\nimport type {WorkflowRunAttempt, WorkflowRunDetail} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {useWorkflowRunAttemptsQuery} from '#hooks/api/workflow-runs.js';\nimport {WorkflowStatusIcon} from '../workflow-status/workflow-status-icon.js';\n\nexport interface WorkflowRunAttemptSwitcherProps {\n workspaceId: string;\n projectId: string;\n run: WorkflowRunDetail;\n latestAttempt: number;\n}\n\nexport function WorkflowRunAttemptSwitcher({\n workspaceId,\n projectId,\n run,\n latestAttempt,\n}: WorkflowRunAttemptSwitcherProps) {\n const [open, setOpen] = useState(false);\n const attemptsQuery = useWorkflowRunAttemptsQuery({\n workflowRunId: run.id,\n enabled: open,\n });\n\n if (latestAttempt <= 1) return null;\n\n const attempts = attemptsQuery.data ?? [];\n const latestLoadedAttempt = Math.max(0, ...attempts.map((attempt) => attempt.attempt));\n const maxAttempt = Math.max(latestAttempt, run.runAttempt.attempt, latestLoadedAttempt);\n const isLoadingMissingAttempt =\n attempts.length > 0 && attemptsQuery.isFetching && latestLoadedAttempt < maxAttempt;\n\n return (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"transparentMuted\"\n size=\"2xs\"\n iconRight=\"arrowDownSLine\"\n aria-label={`Switch attempt, currently ${run.runAttempt.attempt} of ${maxAttempt}`}\n className=\"h-20 px-4 text-foreground-neutral-muted hover:text-foreground-neutral-base\"\n >\n <Text as=\"span\" size=\"xs\" className=\"text-inherit\">\n Attempt {run.runAttempt.attempt} of {maxAttempt}\n </Text>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" size=\"lg\">\n {attemptsQuery.isPending && attempts.length === 0 ? <LoadingRow /> : null}\n {isLoadingMissingAttempt ? <LoadingRow /> : null}\n {attemptsQuery.isError && attempts.length === 0 ? (\n <ErrorRow onRetry={() => void attemptsQuery.refetch()} />\n ) : null}\n {attempts.length > 0\n ? [...attempts]\n .sort((left, right) => right.attempt - left.attempt)\n .map((attempt) => (\n <AttemptItem\n key={attempt.id}\n attempt={attempt}\n current={attempt.id === run.runAttempt.id}\n workflowRunId={run.id}\n workspaceId={workspaceId}\n projectId={projectId}\n />\n ))\n : null}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction LoadingRow() {\n return (\n <DropdownMenuItem disabled>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-neutral-muted\">\n Loading attempts...\n </Text>\n </DropdownMenuItem>\n );\n}\n\nfunction ErrorRow({onRetry}: {onRetry: () => void}) {\n return (\n <DropdownMenuItem closeOnSelect={false} onSelect={onRetry}>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-highlight-error\">\n Could not load attempts. Retry\n </Text>\n </DropdownMenuItem>\n );\n}\n\nfunction AttemptItem({\n attempt,\n current,\n workflowRunId,\n workspaceId,\n projectId,\n}: {\n attempt: WorkflowRunAttempt;\n current: boolean;\n workflowRunId: string;\n workspaceId: string;\n projectId: string;\n}) {\n return (\n <DropdownMenuItem asChild className={cn(current && 'text-foreground-neutral-base')}>\n <Link\n to=\"/workspaces/$wid/projects/$pid/runs/$workflowRunId\"\n params={{wid: workspaceId, pid: projectId, workflowRunId}}\n search={\n ((previous: Record<string, unknown>) => {\n if (current) return previous;\n return {\n ...withoutWorkflowRunSelectionSearch(previous),\n runAttempt: attempt.attempt,\n };\n }) as never\n }\n aria-current={current ? 'page' : undefined}\n >\n <WorkflowStatusIcon status={attempt.status} size={14} tooltip={false} />\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 flex-1 truncate text-inherit\">\n Attempt {attempt.attempt}\n </Code>\n <RelativeTime\n value={attempt.createdAt}\n className=\"shrink-0 whitespace-nowrap font-code text-xs leading-20 text-foreground-neutral-muted\"\n />\n </Link>\n </DropdownMenuItem>\n );\n}\n"],"names":["Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","RelativeTime","Code","Text","cn","Link","useState","withoutWorkflowRunSelectionSearch","useWorkflowRunAttemptsQuery","WorkflowStatusIcon","WorkflowRunAttemptSwitcher","workspaceId","projectId","run","latestAttempt","open","setOpen","attemptsQuery","workflowRunId","id","enabled","attempts","data","latestLoadedAttempt","Math","max","map","attempt","maxAttempt","runAttempt","isLoadingMissingAttempt","length","isFetching","onOpenChange","asChild","type","variant","size","iconRight","aria-label","className","as","align","isPending","LoadingRow","isError","ErrorRow","onRetry","refetch","sort","left","right","AttemptItem","current","disabled","closeOnSelect","onSelect","to","params","wid","pid","search","previous","aria-current","undefined","status","tooltip","value","createdAt"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useState} from 'react';\nimport type {WorkflowRunAttempt, WorkflowRunDetail} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {useWorkflowRunAttemptsQuery} from '#hooks/api/workflow-runs.js';\nimport {WorkflowStatusIcon} from '../workflow-status/workflow-status-icon.js';\n\nexport interface WorkflowRunAttemptSwitcherProps {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n run: WorkflowRunDetail;\n latestAttempt: number;\n}\n\nexport function WorkflowRunAttemptSwitcher({\n workspaceSlug,\n projectSlug,\n run,\n latestAttempt,\n}: WorkflowRunAttemptSwitcherProps) {\n const [open, setOpen] = useState(false);\n const attemptsQuery = useWorkflowRunAttemptsQuery({\n workflowRunId: run.id,\n enabled: open,\n });\n\n if (latestAttempt <= 1) return null;\n if (!workspaceSlug || !projectSlug) return null;\n\n const attempts = attemptsQuery.data ?? [];\n const latestLoadedAttempt = Math.max(0, ...attempts.map((attempt) => attempt.attempt));\n const maxAttempt = Math.max(latestAttempt, run.runAttempt.attempt, latestLoadedAttempt);\n const isLoadingMissingAttempt =\n attempts.length > 0 && attemptsQuery.isFetching && latestLoadedAttempt < maxAttempt;\n\n return (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"transparentMuted\"\n size=\"2xs\"\n iconRight=\"arrowDownSLine\"\n aria-label={`Switch attempt, currently ${run.runAttempt.attempt} of ${maxAttempt}`}\n className=\"h-20 px-4 text-foreground-neutral-muted hover:text-foreground-neutral-base\"\n >\n <Text as=\"span\" size=\"xs\" className=\"text-inherit\">\n Attempt {run.runAttempt.attempt} of {maxAttempt}\n </Text>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" size=\"lg\">\n {attemptsQuery.isPending && attempts.length === 0 ? <LoadingRow /> : null}\n {isLoadingMissingAttempt ? <LoadingRow /> : null}\n {attemptsQuery.isError && attempts.length === 0 ? (\n <ErrorRow onRetry={() => void attemptsQuery.refetch()} />\n ) : null}\n {attempts.length > 0\n ? [...attempts]\n .sort((left, right) => right.attempt - left.attempt)\n .map((attempt) => (\n <AttemptItem\n key={attempt.id}\n attempt={attempt}\n current={attempt.id === run.runAttempt.id}\n workflowRunId={run.id}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n />\n ))\n : null}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction LoadingRow() {\n return (\n <DropdownMenuItem disabled>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-neutral-muted\">\n Loading attempts...\n </Text>\n </DropdownMenuItem>\n );\n}\n\nfunction ErrorRow({onRetry}: {onRetry: () => void}) {\n return (\n <DropdownMenuItem closeOnSelect={false} onSelect={onRetry}>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-highlight-error\">\n Could not load attempts. Retry\n </Text>\n </DropdownMenuItem>\n );\n}\n\nfunction AttemptItem({\n attempt,\n current,\n workflowRunId,\n workspaceSlug,\n projectSlug,\n}: {\n attempt: WorkflowRunAttempt;\n current: boolean;\n workflowRunId: string;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n return (\n <DropdownMenuItem asChild className={cn(current && 'text-foreground-neutral-base')}>\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n ((previous: Record<string, unknown>) => {\n if (current) return previous;\n return {\n ...withoutWorkflowRunSelectionSearch(previous),\n runAttempt: attempt.attempt,\n };\n }) as never\n }\n aria-current={current ? 'page' : undefined}\n >\n <WorkflowStatusIcon status={attempt.status} size={14} tooltip={false} />\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 flex-1 truncate text-inherit\">\n Attempt {attempt.attempt}\n </Code>\n <RelativeTime\n value={attempt.createdAt}\n className=\"shrink-0 whitespace-nowrap font-code text-xs leading-20 text-foreground-neutral-muted\"\n />\n </Link>\n </DropdownMenuItem>\n );\n}\n"],"names":["Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","RelativeTime","Code","Text","cn","Link","useState","withoutWorkflowRunSelectionSearch","useWorkflowRunAttemptsQuery","WorkflowStatusIcon","WorkflowRunAttemptSwitcher","workspaceSlug","projectSlug","run","latestAttempt","open","setOpen","attemptsQuery","workflowRunId","id","enabled","attempts","data","latestLoadedAttempt","Math","max","map","attempt","maxAttempt","runAttempt","isLoadingMissingAttempt","length","isFetching","onOpenChange","asChild","type","variant","size","iconRight","aria-label","className","as","align","isPending","LoadingRow","isError","ErrorRow","onRetry","refetch","sort","left","right","AttemptItem","current","disabled","closeOnSelect","onSelect","to","params","search","previous","aria-current","undefined","status","tooltip","value","createdAt"],"mappings":"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"}