@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.
Files changed (325) hide show
  1. package/.storybook/main.ts +16 -1
  2. package/.storybook/preview.tsx +3 -3
  3. package/.storybook/workspace-source.ts +31 -0
  4. package/.turbo/turbo-build.log +1 -1
  5. package/CHANGELOG.md +79 -0
  6. package/dist/components/job-graph/job-duration-format.d.ts +2 -2
  7. package/dist/components/job-graph/job-duration-format.d.ts.map +1 -1
  8. package/dist/components/job-graph/job-duration-format.js +4 -2
  9. package/dist/components/job-graph/job-duration-format.js.map +1 -1
  10. package/dist/components/job-graph/job-duration-label.js +1 -1
  11. package/dist/components/job-graph/job-duration-label.js.map +1 -1
  12. package/dist/components/job-graph/job-graph-content.d.ts +2 -1
  13. package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
  14. package/dist/components/job-graph/job-graph-content.js +3 -3
  15. package/dist/components/job-graph/job-graph-content.js.map +1 -1
  16. package/dist/components/job-graph/job-graph-view.d.ts +2 -1
  17. package/dist/components/job-graph/job-graph-view.d.ts.map +1 -1
  18. package/dist/components/job-graph/job-graph-view.js +2 -2
  19. package/dist/components/job-graph/job-graph-view.js.map +1 -1
  20. package/dist/components/job-graph/job-node.d.ts +1 -1
  21. package/dist/components/job-graph/job-node.d.ts.map +1 -1
  22. package/dist/components/job-graph/job-node.js +10 -9
  23. package/dist/components/job-graph/job-node.js.map +1 -1
  24. package/dist/components/job-graph/types.d.ts +2 -1
  25. package/dist/components/job-graph/types.d.ts.map +1 -1
  26. package/dist/components/job-graph/types.js.map +1 -1
  27. package/dist/components/step-list/step-list.d.ts +2 -2
  28. package/dist/components/step-list/step-list.d.ts.map +1 -1
  29. package/dist/components/step-list/step-list.js.map +1 -1
  30. package/dist/components/workflow-run-duration-label.js +1 -1
  31. package/dist/components/workflow-run-duration-label.js.map +1 -1
  32. package/dist/components/workflow-run-list/job-status-strip.d.ts +21 -0
  33. package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -0
  34. package/dist/components/workflow-run-list/job-status-strip.js +185 -0
  35. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -0
  36. package/dist/components/workflow-run-list/run-display.d.ts +27 -3
  37. package/dist/components/workflow-run-list/run-display.d.ts.map +1 -1
  38. package/dist/components/workflow-run-list/run-display.js +78 -7
  39. package/dist/components/workflow-run-list/run-display.js.map +1 -1
  40. package/dist/components/workflow-run-list/types.d.ts +23 -24
  41. package/dist/components/workflow-run-list/types.d.ts.map +1 -1
  42. package/dist/components/workflow-run-list/types.js.map +1 -1
  43. package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts +22 -0
  44. package/dist/components/workflow-run-list/workflow-run-filter-menu.d.ts.map +1 -0
  45. package/dist/components/workflow-run-list/workflow-run-filter-menu.js +68 -0
  46. package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -0
  47. package/dist/components/workflow-run-list/workflow-run-filters.d.ts +18 -0
  48. package/dist/components/workflow-run-list/workflow-run-filters.d.ts.map +1 -0
  49. package/dist/components/workflow-run-list/workflow-run-filters.js +236 -0
  50. package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -0
  51. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts +8 -4
  52. package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
  53. package/dist/components/workflow-run-list/workflow-run-list-content.js +40 -12
  54. package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
  55. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts +29 -2
  56. package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
  57. package/dist/components/workflow-run-list/workflow-run-list-states.js +103 -44
  58. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  59. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
  60. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
  61. package/dist/components/workflow-run-list/workflow-run-list-view.js +60 -43
  62. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  63. package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
  64. package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
  65. package/dist/components/workflow-run-list/workflow-run-list.js +20 -8
  66. package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
  67. package/dist/components/workflow-run-list/workflow-run-row.d.ts +19 -9
  68. package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
  69. package/dist/components/workflow-run-list/workflow-run-row.js +179 -112
  70. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  71. package/dist/components/workflow-run-number-label.d.ts +15 -0
  72. package/dist/components/workflow-run-number-label.d.ts.map +1 -0
  73. package/dist/components/workflow-run-number-label.js +41 -0
  74. package/dist/components/workflow-run-number-label.js.map +1 -0
  75. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts +3 -3
  76. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.d.ts.map +1 -1
  77. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +10 -9
  78. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
  79. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +4 -9
  80. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  81. package/dist/components/workflow-run-summary/workflow-run-summary.js +107 -74
  82. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  83. package/dist/components/workflow-run-tabs/index.d.ts +6 -0
  84. package/dist/components/workflow-run-tabs/index.d.ts.map +1 -0
  85. package/dist/components/workflow-run-tabs/index.js +7 -0
  86. package/dist/components/workflow-run-tabs/index.js.map +1 -0
  87. package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts +11 -0
  88. package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -0
  89. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +71 -0
  90. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -0
  91. package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts +2 -0
  92. package/dist/components/workflow-run-tabs/run-annotations-empty.d.ts.map +1 -0
  93. package/dist/components/workflow-run-tabs/run-annotations-empty.js +11 -0
  94. package/dist/components/workflow-run-tabs/run-annotations-empty.js.map +1 -0
  95. package/dist/components/workflow-run-tabs/run-jobs-list.d.ts +18 -0
  96. package/dist/components/workflow-run-tabs/run-jobs-list.d.ts.map +1 -0
  97. package/dist/components/workflow-run-tabs/run-jobs-list.js +107 -0
  98. package/dist/components/workflow-run-tabs/run-jobs-list.js.map +1 -0
  99. package/dist/components/workflow-run-tabs/run-tab-count.d.ts +6 -0
  100. package/dist/components/workflow-run-tabs/run-tab-count.d.ts.map +1 -0
  101. package/dist/components/workflow-run-tabs/run-tab-count.js +27 -0
  102. package/dist/components/workflow-run-tabs/run-tab-count.js.map +1 -0
  103. package/dist/components/workflow-run-tabs/run-tab-strip.d.ts +8 -0
  104. package/dist/components/workflow-run-tabs/run-tab-strip.d.ts.map +1 -0
  105. package/dist/components/workflow-run-tabs/run-tab-strip.js +82 -0
  106. package/dist/components/workflow-run-tabs/run-tab-strip.js.map +1 -0
  107. package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts +2 -2
  108. package/dist/components/workflow-run-view/agent-config-failure-callout.d.ts.map +1 -1
  109. package/dist/components/workflow-run-view/agent-config-failure-callout.js +4 -4
  110. package/dist/components/workflow-run-view/agent-config-failure-callout.js.map +1 -1
  111. package/dist/components/workflow-run-view/job-card.d.ts +2 -2
  112. package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
  113. package/dist/components/workflow-run-view/job-card.js +51 -32
  114. package/dist/components/workflow-run-view/job-card.js.map +1 -1
  115. package/dist/components/workflow-run-view/job-execution-switcher.d.ts +1 -1
  116. package/dist/components/workflow-run-view/job-execution-switcher.d.ts.map +1 -1
  117. package/dist/components/workflow-run-view/job-execution-switcher.js +20 -8
  118. package/dist/components/workflow-run-view/job-execution-switcher.js.map +1 -1
  119. package/dist/components/workflow-run-view/workflow-run-selection.d.ts.map +1 -1
  120. package/dist/components/workflow-run-view/workflow-run-selection.js +40 -1
  121. package/dist/components/workflow-run-view/workflow-run-selection.js.map +1 -1
  122. package/dist/components/workflow-run-view/workflow-run-states.d.ts +1 -0
  123. package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
  124. package/dist/components/workflow-run-view/workflow-run-states.js +10 -1
  125. package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
  126. package/dist/components/workflow-run-view/workflow-run-view.d.ts +10 -5
  127. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  128. package/dist/components/workflow-run-view/workflow-run-view.js +136 -85
  129. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  130. package/dist/components/workflow-source-panel/index.d.ts +1 -0
  131. package/dist/components/workflow-source-panel/index.d.ts.map +1 -1
  132. package/dist/components/workflow-source-panel/index.js +1 -0
  133. package/dist/components/workflow-source-panel/index.js.map +1 -1
  134. package/dist/components/workflow-source-panel/workflow-source-content.d.ts +12 -0
  135. package/dist/components/workflow-source-panel/workflow-source-content.d.ts.map +1 -0
  136. package/dist/components/workflow-source-panel/workflow-source-content.js +53 -0
  137. package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -0
  138. package/dist/components/workflow-source-panel/workflow-source-panel.d.ts +1 -1
  139. package/dist/components/workflow-source-panel/workflow-source-panel.d.ts.map +1 -1
  140. package/dist/components/workflow-source-panel/workflow-source-panel.js +7 -54
  141. package/dist/components/workflow-source-panel/workflow-source-panel.js.map +1 -1
  142. package/dist/components/workflow-status/status-visuals.d.ts +4 -4
  143. package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
  144. package/dist/components/workflow-status/status-visuals.js +7 -0
  145. package/dist/components/workflow-status/status-visuals.js.map +1 -1
  146. package/dist/components/workflow-status/workflow-status-icon.d.ts +3 -4
  147. package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
  148. package/dist/components/workflow-status/workflow-status-icon.js +6 -4
  149. package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
  150. package/dist/core/entities/job-execution.d.ts +10 -0
  151. package/dist/core/entities/job-execution.d.ts.map +1 -1
  152. package/dist/core/entities/job-execution.js +11 -0
  153. package/dist/core/entities/job-execution.js.map +1 -1
  154. package/dist/core/entities/job.d.ts +4 -2
  155. package/dist/core/entities/job.d.ts.map +1 -1
  156. package/dist/core/entities/job.js +8 -1
  157. package/dist/core/entities/job.js.map +1 -1
  158. package/dist/core/entities/step.d.ts +1 -1
  159. package/dist/core/entities/step.d.ts.map +1 -1
  160. package/dist/core/entities/step.js +2 -0
  161. package/dist/core/entities/step.js.map +1 -1
  162. package/dist/core/entities/workflow-run.d.ts +52 -4
  163. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  164. package/dist/core/entities/workflow-run.js +22 -3
  165. package/dist/core/entities/workflow-run.js.map +1 -1
  166. package/dist/core/workflow-run-tabs.d.ts +9 -0
  167. package/dist/core/workflow-run-tabs.d.ts.map +1 -0
  168. package/dist/core/workflow-run-tabs.js +3 -0
  169. package/dist/core/workflow-run-tabs.js.map +1 -0
  170. package/dist/core/workflow-run.d.ts +6 -6
  171. package/dist/core/workflow-run.d.ts.map +1 -1
  172. package/dist/core/workflow-run.js +3 -3
  173. package/dist/core/workflow-run.js.map +1 -1
  174. package/dist/feature.d.ts +7 -7
  175. package/dist/feature.js +5 -5
  176. package/dist/feature.js.map +1 -1
  177. package/dist/hooks/api/workflow-run-mapper.d.ts +4 -3
  178. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  179. package/dist/hooks/api/workflow-run-mapper.js +31 -3
  180. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  181. package/dist/hooks/api/workflow-runs.d.ts +4 -4
  182. package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
  183. package/dist/hooks/api/workflow-runs.js +12 -4
  184. package/dist/hooks/api/workflow-runs.js.map +1 -1
  185. package/dist/index.d.ts +4 -3
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +3 -2
  188. package/dist/index.js.map +1 -1
  189. package/dist/pages/project-workflows-page.js +46 -1
  190. package/dist/pages/project-workflows-page.js.map +1 -1
  191. package/dist/pages/workflow-run-detail-page.d.ts +11 -0
  192. package/dist/pages/workflow-run-detail-page.d.ts.map +1 -0
  193. package/dist/pages/workflow-run-detail-page.js +52 -0
  194. package/dist/pages/workflow-run-detail-page.js.map +1 -0
  195. package/dist/pages/workflow-run-list-page.d.ts +10 -0
  196. package/dist/pages/workflow-run-list-page.d.ts.map +1 -0
  197. package/dist/pages/workflow-run-list-page.js +43 -0
  198. package/dist/pages/workflow-run-list-page.js.map +1 -0
  199. package/dist/routes/inputs.d.ts +94 -5
  200. package/dist/routes/inputs.d.ts.map +1 -1
  201. package/dist/routes/inputs.js +199 -13
  202. package/dist/routes/inputs.js.map +1 -1
  203. package/dist/routes/project-route.d.ts +6 -0
  204. package/dist/routes/project-route.d.ts.map +1 -0
  205. package/dist/routes/project-route.js +25 -0
  206. package/dist/routes/project-route.js.map +1 -0
  207. package/dist/routes/run-detail.d.ts.map +1 -1
  208. package/dist/routes/run-detail.js +12 -7
  209. package/dist/routes/run-detail.js.map +1 -1
  210. package/dist/routes/runs.d.ts.map +1 -1
  211. package/dist/routes/runs.js +11 -6
  212. package/dist/routes/runs.js.map +1 -1
  213. package/dist/routes/workflows.d.ts.map +1 -1
  214. package/dist/routes/workflows.js +6 -5
  215. package/dist/routes/workflows.js.map +1 -1
  216. package/dist/tsconfig.test.tsbuildinfo +1 -1
  217. package/package.json +9 -9
  218. package/src/components/job-graph/job-duration-format.ts +11 -2
  219. package/src/components/job-graph/job-duration-label.tsx +5 -1
  220. package/src/components/job-graph/job-graph-content.tsx +7 -4
  221. package/src/components/job-graph/job-graph-view.test.tsx +19 -8
  222. package/src/components/job-graph/job-graph-view.tsx +6 -3
  223. package/src/components/job-graph/job-graph.stories.tsx +24 -20
  224. package/src/components/job-graph/job-node.stories.tsx +11 -6
  225. package/src/components/job-graph/job-node.test.tsx +82 -12
  226. package/src/components/job-graph/job-node.tsx +22 -15
  227. package/src/components/job-graph/types.ts +5 -1
  228. package/src/components/step-list/step-list.stories.tsx +2 -3
  229. package/src/components/step-list/step-list.tsx +3 -2
  230. package/src/components/workflow-run-duration-label.tsx +1 -1
  231. package/src/components/workflow-run-list/job-status-strip.tsx +189 -0
  232. package/src/components/workflow-run-list/run-display.test.ts +169 -30
  233. package/src/components/workflow-run-list/run-display.ts +116 -9
  234. package/src/components/workflow-run-list/types.ts +21 -17
  235. package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +100 -0
  236. package/src/components/workflow-run-list/workflow-run-filters.tsx +243 -0
  237. package/src/components/workflow-run-list/workflow-run-list-content.tsx +44 -16
  238. package/src/components/workflow-run-list/workflow-run-list-states.tsx +128 -27
  239. package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +441 -104
  240. package/src/components/workflow-run-list/workflow-run-list-view.tsx +73 -43
  241. package/src/components/workflow-run-list/workflow-run-list.stories.tsx +140 -20
  242. package/src/components/workflow-run-list/workflow-run-list.tsx +20 -10
  243. package/src/components/workflow-run-list/workflow-run-row.tsx +173 -106
  244. package/src/components/workflow-run-number-label.test.tsx +45 -0
  245. package/src/components/workflow-run-number-label.tsx +47 -0
  246. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +7 -8
  247. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +15 -14
  248. package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +29 -38
  249. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +30 -24
  250. package/src/components/workflow-run-summary/workflow-run-summary.tsx +102 -77
  251. package/src/components/workflow-run-tabs/index.ts +5 -0
  252. package/src/components/workflow-run-tabs/run-annotation-summary-line.test.tsx +69 -0
  253. package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +97 -0
  254. package/src/components/workflow-run-tabs/run-annotations-empty.tsx +11 -0
  255. package/src/components/workflow-run-tabs/run-jobs-list.tsx +151 -0
  256. package/src/components/workflow-run-tabs/run-tab-count.tsx +28 -0
  257. package/src/components/workflow-run-tabs/run-tab-strip.stories.tsx +52 -0
  258. package/src/components/workflow-run-tabs/run-tab-strip.test.tsx +117 -0
  259. package/src/components/workflow-run-tabs/run-tab-strip.tsx +97 -0
  260. package/src/components/workflow-run-view/agent-config-failure-callout.stories.tsx +2 -3
  261. package/src/components/workflow-run-view/agent-config-failure-callout.tsx +4 -4
  262. package/src/components/workflow-run-view/job-card.stories.tsx +11 -10
  263. package/src/components/workflow-run-view/job-card.test.tsx +115 -0
  264. package/src/components/workflow-run-view/job-card.tsx +74 -35
  265. package/src/components/workflow-run-view/job-execution-switcher.tsx +31 -9
  266. package/src/components/workflow-run-view/workflow-run-selection.test.ts +48 -0
  267. package/src/components/workflow-run-view/workflow-run-selection.ts +48 -1
  268. package/src/components/workflow-run-view/workflow-run-states.tsx +12 -1
  269. package/src/components/workflow-run-view/workflow-run-view.test.tsx +152 -94
  270. package/src/components/workflow-run-view/workflow-run-view.tsx +219 -95
  271. package/src/components/workflow-source-panel/index.ts +1 -0
  272. package/src/components/workflow-source-panel/workflow-source-content.tsx +84 -0
  273. package/src/components/workflow-source-panel/workflow-source-panel.tsx +14 -81
  274. package/src/components/workflow-status/status-visuals.test.ts +9 -0
  275. package/src/components/workflow-status/status-visuals.ts +6 -4
  276. package/src/components/workflow-status/workflow-status-icon.stories.tsx +10 -2
  277. package/src/components/workflow-status/workflow-status-icon.test.tsx +18 -0
  278. package/src/components/workflow-status/workflow-status-icon.tsx +17 -24
  279. package/src/core/entities/job-execution.ts +22 -0
  280. package/src/core/entities/job-status.test.ts +104 -0
  281. package/src/core/entities/job.ts +18 -3
  282. package/src/core/entities/step.ts +4 -0
  283. package/src/core/entities/workflow-run.ts +76 -7
  284. package/src/core/workflow-run-tabs.ts +8 -0
  285. package/src/core/workflow-run.test.ts +24 -9
  286. package/src/core/workflow-run.ts +17 -2
  287. package/src/feature.ts +5 -5
  288. package/src/hooks/api/workflow-run-mapper.ts +30 -3
  289. package/src/hooks/api/workflow-runs.test.tsx +2 -0
  290. package/src/hooks/api/workflow-runs.ts +12 -7
  291. package/src/index.ts +7 -2
  292. package/src/page-harness-budget.test.ts +1 -1
  293. package/src/pages/project-workflows-page.test.tsx +59 -5
  294. package/src/pages/project-workflows-page.tsx +34 -1
  295. package/src/pages/workflow-run-detail-page.tsx +72 -0
  296. package/src/pages/workflow-run-list-page.tsx +65 -0
  297. package/src/pages/workflow-run-pages.test.tsx +823 -0
  298. package/src/routes/inputs.test.ts +240 -12
  299. package/src/routes/inputs.ts +215 -11
  300. package/src/routes/project-route.tsx +25 -0
  301. package/src/routes/run-detail.tsx +15 -8
  302. package/src/routes/runs.tsx +14 -7
  303. package/src/routes/workflows.tsx +5 -4
  304. package/src/storybook-config.test.ts +27 -0
  305. package/test/fixtures/workflow-run.ts +76 -7
  306. package/test/pages.tsx +18 -8
  307. package/test/render.tsx +8 -2
  308. package/tsconfig.build.tsbuildinfo +1 -1
  309. package/tsconfig.test.json +7 -1
  310. package/dist/components/workflow-run-list/workflow-run-list-header.d.ts +0 -10
  311. package/dist/components/workflow-run-list/workflow-run-list-header.d.ts.map +0 -1
  312. package/dist/components/workflow-run-list/workflow-run-list-header.js +0 -55
  313. package/dist/components/workflow-run-list/workflow-run-list-header.js.map +0 -1
  314. package/dist/pages/workflow-run-first-time-use.d.ts +0 -6
  315. package/dist/pages/workflow-run-first-time-use.d.ts.map +0 -1
  316. package/dist/pages/workflow-run-first-time-use.js +0 -17
  317. package/dist/pages/workflow-run-first-time-use.js.map +0 -1
  318. package/dist/pages/workflow-run-page.d.ts +0 -10
  319. package/dist/pages/workflow-run-page.d.ts.map +0 -1
  320. package/dist/pages/workflow-run-page.js +0 -90
  321. package/dist/pages/workflow-run-page.js.map +0 -1
  322. package/src/components/workflow-run-list/workflow-run-list-header.tsx +0 -53
  323. package/src/pages/workflow-run-first-time-use.tsx +0 -17
  324. package/src/pages/workflow-run-page.test.tsx +0 -519
  325. package/src/pages/workflow-run-page.tsx +0 -94
@@ -1,11 +1,11 @@
1
1
  import type {BadgeVariant} from '@shipfox/react-ui/badge';
2
2
  import type {DotVariant} from '@shipfox/react-ui/dot';
3
- import type {WorkflowStatus} from '#core/workflow-run.js';
3
+ import type {WorkflowDisplayStatus} from '#core/workflow-run.js';
4
4
 
5
- export type {WorkflowStatus};
5
+ export type {WorkflowDisplayStatus};
6
6
 
7
7
  export interface WorkflowStatusVisual {
8
- kind: WorkflowStatus;
8
+ kind: WorkflowDisplayStatus;
9
9
  label: string;
10
10
  dot: DotVariant;
11
11
  badge: BadgeVariant;
@@ -15,12 +15,14 @@ export interface WorkflowStatusVisual {
15
15
  // WorkflowStatusIcon (which renders the glyph per kind). The exhaustive switch turns any new
16
16
  // status the API grows into (DESIGN.md section 9) into a compile error; reserve the `warning`
17
17
  // tone for the queued/awaiting-* states when they land.
18
- export function getWorkflowStatusVisual(status: WorkflowStatus): WorkflowStatusVisual {
18
+ export function getWorkflowStatusVisual(status: WorkflowDisplayStatus): WorkflowStatusVisual {
19
19
  switch (status) {
20
20
  case 'pending':
21
21
  return {kind: 'pending', label: 'Pending', dot: 'neutral', badge: 'neutral'};
22
22
  case 'running':
23
23
  return {kind: 'running', label: 'Running', dot: 'info', badge: 'info'};
24
+ case 'listening':
25
+ return {kind: 'listening', label: 'Listening', dot: 'info', badge: 'info'};
24
26
  case 'succeeded':
25
27
  return {kind: 'succeeded', label: 'Succeeded', dot: 'success', badge: 'success'};
26
28
  case 'failed':
@@ -1,10 +1,18 @@
1
1
  import {Code, Text} from '@shipfox/react-ui/typography';
2
2
  import type {Meta, StoryObj} from '@storybook/react';
3
- import type {JobStatus} from '#core/workflow-run.js';
3
+ import type {WorkflowDisplayStatus} from '#core/workflow-run.js';
4
4
  import {getWorkflowStatusVisual} from './status-visuals.js';
5
5
  import {WorkflowStatusIcon} from './workflow-status-icon.js';
6
6
 
7
- const statuses: JobStatus[] = ['pending', 'running', 'succeeded', 'failed', 'cancelled', 'skipped'];
7
+ const statuses: WorkflowDisplayStatus[] = [
8
+ 'pending',
9
+ 'running',
10
+ 'listening',
11
+ 'succeeded',
12
+ 'failed',
13
+ 'cancelled',
14
+ 'skipped',
15
+ ];
8
16
 
9
17
  const meta = {
10
18
  title: 'Workflows/StatusIcon',
@@ -0,0 +1,18 @@
1
+ import {render, screen} from '@testing-library/react';
2
+ import {WorkflowStatusIcon} from './workflow-status-icon.js';
3
+
4
+ describe('WorkflowStatusIcon', () => {
5
+ test('keeps a running status as a dot', () => {
6
+ const {container} = render(<WorkflowStatusIcon status="running" tooltip={false} />);
7
+
8
+ expect(screen.getByRole('img', {name: 'Running'})).toBeInTheDocument();
9
+ expect(container.querySelector('svg')).toBeNull();
10
+ });
11
+
12
+ test('uses the pulse glyph for the listening status', () => {
13
+ const {container} = render(<WorkflowStatusIcon status="listening" tooltip={false} />);
14
+
15
+ expect(screen.getByRole('img', {name: 'Listening'})).toBeInTheDocument();
16
+ expect(container.querySelector('svg')).not.toBeNull();
17
+ });
18
+ });
@@ -3,7 +3,7 @@ import {Icon, type IconName} from '@shipfox/react-ui/icon';
3
3
  import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';
4
4
  import {cn} from '@shipfox/react-ui/utils';
5
5
  import type {ReactNode} from 'react';
6
- import {getWorkflowStatusVisual, type WorkflowStatus} from './status-visuals.js';
6
+ import {getWorkflowStatusVisual, type WorkflowDisplayStatus} from './status-visuals.js';
7
7
 
8
8
  // Status glyphs use the same saturated accent tokens as IconBadge/StatusBadge.
9
9
  const toneByVariant: Record<DotVariant, string> = {
@@ -17,7 +17,7 @@ const toneByVariant: Record<DotVariant, string> = {
17
17
 
18
18
  // Terminal states are self-contained solid discs; the shape names the state. Running and
19
19
  // pending render their own shapes (the live Dot and a bold ring), so they aren't here.
20
- const glyphByKind: Partial<Record<WorkflowStatus, IconName>> = {
20
+ const glyphByKind: Partial<Record<WorkflowDisplayStatus, IconName>> = {
21
21
  succeeded: 'checkCircleSolid',
22
22
  failed: 'xCircleSolid',
23
23
  cancelled: 'forbid2Fill',
@@ -45,8 +45,7 @@ const dotSizeClass: Record<number, string> = {
45
45
  const PENDING_RING_MASK = 'radial-gradient(circle closest-side, transparent 0 52%, #000 56%)';
46
46
 
47
47
  export interface WorkflowStatusIconProps {
48
- status: WorkflowStatus;
49
- jobMode?: 'one_shot' | 'listening';
48
+ status: WorkflowDisplayStatus;
50
49
  /** Optical diameter in px: 14 in the DAG node and run row. */
51
50
  size?: number;
52
51
  /** Pulsing halo for the running state. */
@@ -66,7 +65,6 @@ export interface WorkflowStatusIconProps {
66
65
  */
67
66
  export function WorkflowStatusIcon({
68
67
  status,
69
- jobMode = 'one_shot',
70
68
  size = 14,
71
69
  ripple = true,
72
70
  tooltip = true,
@@ -76,25 +74,20 @@ export function WorkflowStatusIcon({
76
74
  const box = dotSizeClass[size] ?? 'size-14';
77
75
 
78
76
  let glyph: ReactNode;
79
- if (visual.kind === 'running') {
80
- glyph =
81
- jobMode === 'listening' ? (
82
- <span
83
- className={cn(
84
- 'inline-flex shrink-0 items-center justify-center rounded-full bg-current',
85
- box,
86
- toneByVariant.info,
87
- )}
88
- >
89
- <Icon
90
- name="pulseLine"
91
- size={Math.max(8, Math.round(size * 0.7))}
92
- className="text-white"
93
- />
94
- </span>
95
- ) : (
96
- <Dot variant="info" ripple={ripple} className={box} />
97
- );
77
+ if (visual.kind === 'listening') {
78
+ glyph = (
79
+ <span
80
+ className={cn(
81
+ 'inline-flex shrink-0 items-center justify-center rounded-full bg-current',
82
+ box,
83
+ toneByVariant.info,
84
+ )}
85
+ >
86
+ <Icon name="pulseLine" size={Math.max(8, Math.round(size * 0.7))} className="text-white" />
87
+ </span>
88
+ );
89
+ } else if (visual.kind === 'running') {
90
+ glyph = <Dot variant="info" ripple={ripple} className={box} />;
98
91
  } else if (visual.kind === 'pending') {
99
92
  glyph = (
100
93
  <span
@@ -2,11 +2,16 @@ import {type Duration, intervalToDuration} from 'date-fns';
2
2
  import type {Step} from './step.js';
3
3
 
4
4
  export type JobExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
5
+ export type JobExecutionDisplayStatus = JobExecutionStatus;
5
6
  export interface WorkflowExecutionEvent {
6
7
  source: string;
7
8
  event: string;
8
9
  deliveryId: string;
9
10
  receivedAt: string;
11
+ project: {id: string} | null;
12
+ repository: string | null;
13
+ ref: string | null;
14
+ commit: string | null;
10
15
  data: unknown;
11
16
  }
12
17
  export type JobExecutionTime =
@@ -53,6 +58,10 @@ export class JobExecution {
53
58
  Object.assign(this, fields);
54
59
  }
55
60
 
61
+ get displayName(): string {
62
+ return this.name;
63
+ }
64
+
56
65
  get queueTime(): JobExecutionTime | null {
57
66
  return jobExecutionQueueTimeFromTimestamps(this);
58
67
  }
@@ -66,6 +75,19 @@ export class JobExecution {
66
75
  }
67
76
  }
68
77
 
78
+ export function deriveJobExecutionDisplayStatus({
79
+ status,
80
+ steps,
81
+ }: Pick<JobExecution, 'status' | 'steps'>): JobExecutionDisplayStatus {
82
+ if (isTerminalJobExecutionStatus(status)) return status;
83
+ if (steps.some((step) => step.status === 'running')) return 'running';
84
+ return 'pending';
85
+ }
86
+
87
+ export function isTerminalJobExecutionStatus(status: JobExecutionStatus): boolean {
88
+ return status === 'succeeded' || status === 'failed' || status === 'cancelled';
89
+ }
90
+
69
91
  export function jobExecutionQueueTimeFromTimestamps({
70
92
  queuedAt,
71
93
  startedAt,
@@ -0,0 +1,104 @@
1
+ import {deriveJobDisplayStatus, type JobDisplayStatus} from './job.js';
2
+ import {deriveJobExecutionDisplayStatus, type JobExecutionStatus} from './job-execution.js';
3
+
4
+ type DisplayStep = Parameters<typeof deriveJobExecutionDisplayStatus>[0]['steps'][number];
5
+
6
+ function displayStep(status: string): DisplayStep {
7
+ return {status} as DisplayStep;
8
+ }
9
+
10
+ const EXECUTION_STATUSES = ['pending', 'running', 'succeeded', 'failed', 'cancelled'] as const;
11
+ const TERMINAL_EXECUTION_STATUSES = ['succeeded', 'failed', 'cancelled'] as const;
12
+
13
+ describe('deriveJobExecutionDisplayStatus', () => {
14
+ test.each(
15
+ EXECUTION_STATUSES,
16
+ )('%s without a running step displays Pending unless terminal', (status) => {
17
+ const displayStatus = deriveJobExecutionDisplayStatus({status, steps: []});
18
+
19
+ expect(displayStatus).toBe(
20
+ TERMINAL_EXECUTION_STATUSES.includes(status as (typeof TERMINAL_EXECUTION_STATUSES)[number])
21
+ ? status
22
+ : 'pending',
23
+ );
24
+ });
25
+
26
+ test.each([
27
+ 'pending',
28
+ 'running',
29
+ ] as const)('%s with a running step displays Running', (status) => {
30
+ expect(deriveJobExecutionDisplayStatus({status, steps: [displayStep('running')]})).toBe(
31
+ 'running',
32
+ );
33
+ });
34
+
35
+ test.each(TERMINAL_EXECUTION_STATUSES)('%s wins over a running child step', (status) => {
36
+ expect(deriveJobExecutionDisplayStatus({status, steps: [displayStep('running')]})).toBe(status);
37
+ });
38
+ });
39
+
40
+ describe('deriveJobDisplayStatus', () => {
41
+ test('uses the execution activity for a one-shot job', () => {
42
+ const statuses: Array<[JobExecutionStatus, string[], JobDisplayStatus]> = [
43
+ ['pending', [], 'pending'],
44
+ ['pending', ['running'], 'running'],
45
+ ['running', [], 'pending'],
46
+ ['running', ['running'], 'running'],
47
+ ];
48
+
49
+ for (const [status, stepStatuses, expected] of statuses) {
50
+ expect(
51
+ deriveJobDisplayStatus({
52
+ mode: 'one_shot',
53
+ status: 'running',
54
+ listenerStatus: 'inactive',
55
+ jobExecutions: [
56
+ {
57
+ status,
58
+ steps: stepStatuses.map(displayStep),
59
+ sequence: 1,
60
+ },
61
+ ] as never,
62
+ }),
63
+ ).toBe(expected);
64
+ }
65
+ });
66
+
67
+ test.each([
68
+ 'succeeded',
69
+ 'failed',
70
+ 'cancelled',
71
+ 'skipped',
72
+ ] as const)('terminal job status %s wins over child activity', (status) => {
73
+ expect(
74
+ deriveJobDisplayStatus({
75
+ mode: 'one_shot',
76
+ status,
77
+ listenerStatus: 'inactive',
78
+ jobExecutions: [{status: 'running', steps: [{status: 'running'}], sequence: 1}] as never,
79
+ }),
80
+ ).toBe(status);
81
+ });
82
+
83
+ test('keeps an active listener as Listening without executions', () => {
84
+ expect(
85
+ deriveJobDisplayStatus({
86
+ mode: 'listening',
87
+ status: 'running',
88
+ listenerStatus: 'listening',
89
+ jobExecutions: [],
90
+ }),
91
+ ).toBe('listening');
92
+ });
93
+
94
+ test('uses the terminal job status when an active listener has resolved', () => {
95
+ expect(
96
+ deriveJobDisplayStatus({
97
+ mode: 'listening',
98
+ status: 'succeeded',
99
+ listenerStatus: 'listening',
100
+ jobExecutions: [],
101
+ }),
102
+ ).toBe('succeeded');
103
+ });
104
+ });
@@ -1,6 +1,11 @@
1
- import type {JobExecution, JobExecutionDisplayDuration} from './job-execution.js';
1
+ import {
2
+ deriveJobExecutionDisplayStatus,
3
+ type JobExecution,
4
+ type JobExecutionDisplayDuration,
5
+ } from './job-execution.js';
2
6
 
3
7
  export type JobStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';
8
+ export type JobDisplayStatus = JobStatus | 'listening';
4
9
  export type JobMode = 'one_shot' | 'listening';
5
10
  export type ListenerStatus = 'inactive' | 'listening' | 'resolved';
6
11
  export type ResolutionReason = 'until' | 'timeout' | 'max_executions' | 'cancelled';
@@ -103,7 +108,7 @@ export class Job {
103
108
  }
104
109
 
105
110
  get displayName(): string {
106
- return this.name || this.key;
111
+ return this.name ?? this.key;
107
112
  }
108
113
 
109
114
  get displayDuration(): JobDisplayDuration | null {
@@ -123,6 +128,16 @@ export function isTerminalJobStatus(status: JobStatus): boolean {
123
128
  return TERMINAL_JOB_STATUS_SET.has(status);
124
129
  }
125
130
 
131
+ export function deriveJobDisplayStatus(
132
+ job: Pick<Job, 'mode' | 'status' | 'listenerStatus' | 'jobExecutions'>,
133
+ ): JobDisplayStatus {
134
+ if (isTerminalJobStatus(job.status)) return job.status;
135
+ if (job.mode === 'listening' && job.listenerStatus === 'listening') return 'listening';
136
+
137
+ const execution = defaultJobExecution(job);
138
+ return execution ? deriveJobExecutionDisplayStatus(execution) : 'pending';
139
+ }
140
+
126
141
  export function resolveJobExecution(
127
142
  job: Job,
128
143
  jobExecutionId: string | undefined,
@@ -135,7 +150,7 @@ export function resolveJobExecution(
135
150
  return defaultJobExecution(job);
136
151
  }
137
152
 
138
- export function defaultJobExecution(job: Job): JobExecution | undefined {
153
+ export function defaultJobExecution(job: Pick<Job, 'jobExecutions'>): JobExecution | undefined {
139
154
  const runningExecution = job.jobExecutions.find(
140
155
  (jobExecution) => jobExecution.status === 'running',
141
156
  );
@@ -4,6 +4,8 @@ export type StepErrorReason =
4
4
  | 'checkout_failed'
5
5
  | 'checkout_auth_failed'
6
6
  | 'checkout_unavailable'
7
+ | 'checkout_path_invalid'
8
+ | 'checkout_destination_occupied'
7
9
  | 'git_unavailable'
8
10
  | 'workspace_prep_failed'
9
11
  | 'setup_aborted'
@@ -23,6 +25,8 @@ export const STEP_ERROR_REASONS = new Set<StepErrorReason>([
23
25
  'checkout_failed',
24
26
  'checkout_auth_failed',
25
27
  'checkout_unavailable',
28
+ 'checkout_path_invalid',
29
+ 'checkout_destination_occupied',
26
30
  'git_unavailable',
27
31
  'workspace_prep_failed',
28
32
  'setup_aborted',
@@ -1,9 +1,10 @@
1
- import {type Job, WORKFLOW_JOB_STATUSES} from './job.js';
1
+ import {type Job, type JobStatus, WORKFLOW_JOB_STATUSES} from './job.js';
2
2
  import type {WorkflowRunAttempt, WorkflowRunAttemptSummary} from './workflow-run-attempt.js';
3
3
 
4
4
  export type WorkflowRunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
5
5
  export type WorkflowRunRerunMode = 'all' | 'failed';
6
6
  export type WorkflowStatus = WorkflowRunStatus | (typeof WORKFLOW_JOB_STATUSES)[number];
7
+ export type WorkflowDisplayStatus = WorkflowStatus | 'listening';
7
8
 
8
9
  export const WORKFLOW_RUN_STATUSES = [
9
10
  'pending',
@@ -30,11 +31,51 @@ export interface WorkflowSourceSnapshot {
30
31
  format: 'yaml';
31
32
  }
32
33
 
34
+ /**
35
+ * Provider-neutral trigger facts. Every field is nullable: only source-control triggers
36
+ * resolve a reference at all, and a payload can name a ref without naming an actor.
37
+ */
38
+ export interface WorkflowRunTriggerReference {
39
+ repository: string | null;
40
+ ref: string | null;
41
+ commit: string | null;
42
+ actor: string | null;
43
+ }
44
+
45
+ /** One glyph in a run row's job status strip: enough to draw and label it, nothing more. */
46
+ export interface WorkflowRunJobSummary {
47
+ id: string;
48
+ key: string;
49
+ name: string | null;
50
+ status: JobStatus;
51
+ position: number;
52
+ }
53
+
54
+ export interface WorkflowRunJobStatusCount {
55
+ status: JobStatus;
56
+ count: number;
57
+ }
58
+
59
+ /**
60
+ * A run's jobs as the list receives them: a bounded slice to draw, plus totals covering all
61
+ * of them.
62
+ *
63
+ * `preview` is capped by the API, so `preview.length` is not the job count and the strip
64
+ * reads `total` and `statusCounts` for anything it says rather than anything it draws.
65
+ */
66
+ export interface WorkflowRunJobs {
67
+ preview: WorkflowRunJobSummary[];
68
+ statusCounts: WorkflowRunJobStatusCount[];
69
+ total: number;
70
+ }
71
+
33
72
  export interface WorkflowRun {
34
73
  id: string;
35
74
  projectId: string;
36
75
  definitionId: string;
76
+ number: number | null;
37
77
  name: string;
78
+ workflowName: string;
38
79
  currentAttempt: number;
39
80
  triggerProvider: string | null;
40
81
  triggerSource: string;
@@ -42,20 +83,25 @@ export interface WorkflowRun {
42
83
  triggerDisplayLabel: string;
43
84
  triggerLabel: string;
44
85
  triggerPayload: Record<string, unknown>;
86
+ triggerReference: WorkflowRunTriggerReference | null;
45
87
  inputs: Record<string, unknown> | null;
46
88
  sourceSnapshot: WorkflowSourceSnapshot | null;
47
89
  createdAt: string;
48
90
  updatedAt: string;
49
- shortId: string;
50
91
  isTemporary: boolean;
51
92
  }
52
93
 
53
- export interface WorkflowRunListItem extends WorkflowRun {
94
+ /** A run as the API returns it outside the list: no job strip, because none was fetched. */
95
+ export interface WorkflowRunRecord extends WorkflowRun {
54
96
  status: WorkflowRunStatus;
55
97
  latestAttempt: number;
56
98
  runAttempt: WorkflowRunAttemptSummary;
57
99
  }
58
100
 
101
+ export interface WorkflowRunListItem extends WorkflowRunRecord {
102
+ jobs: WorkflowRunJobs;
103
+ }
104
+
59
105
  export interface WorkflowRunDetail extends WorkflowRun {
60
106
  latestAttempt: number;
61
107
  runAttempt: WorkflowRunAttempt;
@@ -72,10 +118,6 @@ export interface ManualWorkflowLaunch {
72
118
  workflowRunId: string;
73
119
  }
74
120
 
75
- export function workflowRunShortId(id: string): string {
76
- return id.length <= 8 ? id : id.slice(0, 8);
77
- }
78
-
79
121
  export function workflowRunTriggerLabel({
80
122
  triggerSource,
81
123
  triggerEvent,
@@ -96,6 +138,33 @@ export function workflowRunTriggerDisplayLabel({
96
138
  return triggerEvent || triggerSource;
97
139
  }
98
140
 
141
+ const SHORT_COMMIT_LENGTH = 7;
142
+ const PULL_REQUEST_REF_PATTERN = /^refs\/pull\/(\d+)\/head$/u;
143
+
144
+ /**
145
+ * The ref as a person names it: `main` for a branch, `#42` for a pull request, the tag for a
146
+ * tag. An unrecognized ref is shown verbatim rather than hidden, since a ref nobody can read
147
+ * is still better evidence than a blank cell.
148
+ */
149
+ export function workflowRunBranchLabel(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
150
+ const ref = run.triggerReference?.ref;
151
+ if (!ref) return null;
152
+ const pullRequest = PULL_REQUEST_REF_PATTERN.exec(ref);
153
+ if (pullRequest) return `#${pullRequest[1]}`;
154
+ if (ref.startsWith('refs/heads/')) return ref.slice('refs/heads/'.length);
155
+ if (ref.startsWith('refs/tags/')) return ref.slice('refs/tags/'.length);
156
+ return ref;
157
+ }
158
+
159
+ export function workflowRunCommitLabel(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
160
+ const commit = run.triggerReference?.commit;
161
+ return commit ? commit.slice(0, SHORT_COMMIT_LENGTH) : null;
162
+ }
163
+
164
+ export function workflowRunActor(run: Pick<WorkflowRun, 'triggerReference'>): string | null {
165
+ return run.triggerReference?.actor ?? null;
166
+ }
167
+
99
168
  export function isWorkflowRunTerminal(status: WorkflowRunStatus): boolean {
100
169
  return TERMINAL_WORKFLOW_RUN_STATUS_SET.has(status);
101
170
  }
@@ -0,0 +1,8 @@
1
+ /** Counts used by the run detail tab strip before the annotations query owns the data. */
2
+ export interface RunAnnotationSummary {
3
+ total: number;
4
+ error: number;
5
+ warning: number;
6
+ info: number;
7
+ success: number;
8
+ }
@@ -6,6 +6,7 @@ import {
6
6
  toWorkflowRunListPage,
7
7
  } from '#hooks/api/workflow-run-mapper.js';
8
8
  import {
9
+ workflowJob,
9
10
  workflowJobDto,
10
11
  workflowJobExecutionDto,
11
12
  workflowRunAttemptDto,
@@ -18,7 +19,6 @@ import {
18
19
  import {
19
20
  isWorkflowRunTerminal,
20
21
  isWorkflowStatus,
21
- workflowRunShortId,
22
22
  workflowRunTriggerDisplayLabel,
23
23
  workflowRunTriggerLabel,
24
24
  } from './workflow-run.js';
@@ -51,7 +51,9 @@ describe('workflow run model mapping', () => {
51
51
  id: '66666666-6666-4666-8666-666666666666',
52
52
  projectId: '44444444-4444-4444-8444-444444444444',
53
53
  definitionId: '55555555-5555-4555-8555-555555555555',
54
+ number: 1,
54
55
  name: 'deploy-web',
56
+ workflowName: 'deploy-web',
55
57
  currentAttempt: 3,
56
58
  triggerProvider: 'github',
57
59
  triggerSource: 'github_acme',
@@ -63,7 +65,6 @@ describe('workflow run model mapping', () => {
63
65
  sourceSnapshot: {format: 'yaml', content: 'jobs: {}'},
64
66
  createdAt: '2026-05-07T01:01:00.000Z',
65
67
  updatedAt: '2026-05-07T01:02:00.000Z',
66
- shortId: '66666666',
67
68
  isTemporary: false,
68
69
  });
69
70
  expect(run).not.toHaveProperty('status');
@@ -91,7 +92,6 @@ describe('workflow run model mapping', () => {
91
92
  triggerLabel: '',
92
93
  inputs: null,
93
94
  sourceSnapshot: null,
94
- shortId: 'temp-123',
95
95
  isTemporary: true,
96
96
  });
97
97
  });
@@ -299,6 +299,10 @@ describe('workflow run model mapping', () => {
299
299
  event: 'deployment_status',
300
300
  delivery_id: 'delivery-1',
301
301
  received_at: '2026-05-07T01:00:00.000Z',
302
+ project: {id: '44444444-4444-4444-8444-444444444444'},
303
+ repository: 'acme/api',
304
+ ref: 'refs/heads/main',
305
+ commit: 'a'.repeat(40),
302
306
  data: {state: 'success'},
303
307
  },
304
308
  ],
@@ -332,6 +336,10 @@ describe('workflow run model mapping', () => {
332
336
  event: 'deployment_status',
333
337
  deliveryId: 'delivery-1',
334
338
  receivedAt: '2026-05-07T01:00:00.000Z',
339
+ project: {id: '44444444-4444-4444-8444-444444444444'},
340
+ repository: 'acme/api',
341
+ ref: 'refs/heads/main',
342
+ commit: 'a'.repeat(40),
335
343
  data: {state: 'success'},
336
344
  },
337
345
  ],
@@ -376,6 +384,18 @@ describe('workflow run model mapping', () => {
376
384
  });
377
385
  });
378
386
 
387
+ test('exposes display names for jobs and job executions', () => {
388
+ const job = workflowJob({
389
+ name: 'Deploy',
390
+ key: 'deploy',
391
+ job_executions: [workflowJobExecutionDto({name: 'Deploy production'})],
392
+ });
393
+
394
+ expect(job.displayName).toBe('Deploy');
395
+ expect(job.jobExecutions[0]?.displayName).toBe('Deploy production');
396
+ expect(workflowJob({name: null, key: 'deploy-prod'}).displayName).toBe('deploy-prod');
397
+ });
398
+
379
399
  test('returns no job display duration when a job has multiple executions', () => {
380
400
  const job = workflowJobDto({
381
401
  job_executions: [
@@ -628,12 +648,7 @@ describe('workflow run helpers', () => {
628
648
  expect(neither).toBe('');
629
649
  });
630
650
 
631
- test('formats short ids and classifies workflow statuses', () => {
632
- const short = workflowRunShortId('abc123');
633
- const long = workflowRunShortId('66666666-6666-4666-8666-666666666666');
634
-
635
- expect(short).toBe('abc123');
636
- expect(long).toBe('66666666');
651
+ test('classifies workflow statuses', () => {
637
652
  expect(isWorkflowRunTerminal('succeeded')).toBe(true);
638
653
  expect(isWorkflowRunTerminal('running')).toBe(false);
639
654
  expect(isWorkflowStatus('pending')).toBe(true);
@@ -1,5 +1,6 @@
1
1
  export type {
2
2
  JobDisplayDuration,
3
+ JobDisplayStatus,
3
4
  JobListening,
4
5
  JobMode,
5
6
  JobStatus,
@@ -9,6 +10,7 @@ export type {
9
10
  } from './entities/job.js';
10
11
  export {
11
12
  defaultJobExecution,
13
+ deriveJobDisplayStatus,
12
14
  isTerminalJobStatus,
13
15
  Job,
14
16
  resolveJobExecution,
@@ -17,11 +19,16 @@ export {
17
19
  } from './entities/job.js';
18
20
  export type {
19
21
  JobExecutionDisplayDuration,
22
+ JobExecutionDisplayStatus,
20
23
  JobExecutionStatus,
21
24
  JobExecutionTime,
22
25
  WorkflowExecutionEvent,
23
26
  } from './entities/job-execution.js';
24
- export {JobExecution} from './entities/job-execution.js';
27
+ export {
28
+ deriveJobExecutionDisplayStatus,
29
+ isTerminalJobExecutionStatus,
30
+ JobExecution,
31
+ } from './entities/job-execution.js';
25
32
  export type {
26
33
  AgentConfigIssue,
27
34
  AgentStepConfig,
@@ -39,12 +46,18 @@ export type {
39
46
  export {StepAttempt} from './entities/step-attempt.js';
40
47
  export type {
41
48
  ManualWorkflowLaunch,
49
+ WorkflowDisplayStatus,
42
50
  WorkflowRun,
43
51
  WorkflowRunDetail,
52
+ WorkflowRunJobStatusCount,
53
+ WorkflowRunJobSummary,
54
+ WorkflowRunJobs,
44
55
  WorkflowRunListItem,
45
56
  WorkflowRunListPage,
57
+ WorkflowRunRecord,
46
58
  WorkflowRunRerunMode,
47
59
  WorkflowRunStatus,
60
+ WorkflowRunTriggerReference,
48
61
  WorkflowSourceSnapshot,
49
62
  WorkflowStatus,
50
63
  } from './entities/workflow-run.js';
@@ -53,7 +66,9 @@ export {
53
66
  isWorkflowStatus,
54
67
  TERMINAL_WORKFLOW_RUN_STATUSES,
55
68
  WORKFLOW_RUN_STATUSES,
56
- workflowRunShortId,
69
+ workflowRunActor,
70
+ workflowRunBranchLabel,
71
+ workflowRunCommitLabel,
57
72
  workflowRunTriggerDisplayLabel,
58
73
  workflowRunTriggerLabel,
59
74
  } from './entities/workflow-run.js';