@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,73 +1,103 @@
1
1
  import {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';
2
+ import {Header} from '@shipfox/react-ui/typography';
2
3
  import {cn} from '@shipfox/react-ui/utils';
3
- import {useState} from 'react';
4
- import {runMatchesSearch, runMatchesStatusFilter} from './run-display.js';
4
+ import {useId, useMemo, useState} from 'react';
5
+ import {
6
+ applyWorkflowRunFilterPatch,
7
+ clearWorkflowRunFilters,
8
+ hasWorkflowRunFilters,
9
+ type WorkflowRunFilterPatch,
10
+ type WorkflowRunsSearch,
11
+ } from '#routes/inputs.js';
12
+ import {runMatchesFilters, workflowRunFacets} from './run-display.js';
5
13
  import type {WorkflowRunListViewProps} from './types.js';
14
+ import {WorkflowRunFilters} from './workflow-run-filters.js';
6
15
  import {WorkflowRunListContent} from './workflow-run-list-content.js';
7
- import {WorkflowRunListHeader} from './workflow-run-list-header.js';
16
+
17
+ const EMPTY_SEARCH: WorkflowRunsSearch = {};
8
18
 
9
19
  export function WorkflowRunListView({
10
20
  runs,
11
21
  query,
12
- workspaceId,
13
- projectId,
14
- selectedWorkflowRunId,
22
+ workspaceSlug,
23
+ projectSlug,
15
24
  className,
16
- search = '',
17
- statusFilter = 'all',
25
+ search = EMPTY_SEARCH,
18
26
  onFiltersChange,
27
+ onClearFilters,
28
+ hasNextPage = false,
29
+ isFetchingNextPage = false,
30
+ isFetchNextPageError = false,
31
+ onLoadMore,
19
32
  }: WorkflowRunListViewProps) {
20
- const [localSearch, setLocalSearch] = useState(search);
21
- const [localStatusFilter, setLocalStatusFilter] = useState(statusFilter);
33
+ const headingId = useId();
34
+ const [localSearch, setLocalSearch] = useState<WorkflowRunsSearch>(search);
22
35
  const currentSearch = onFiltersChange ? search : localSearch;
23
- const currentStatusFilter = onFiltersChange ? statusFilter : localStatusFilter;
24
36
 
25
- const filteredRuns = runs.filter((run) => {
26
- if (!runMatchesStatusFilter(run.status, currentStatusFilter)) return false;
27
- return runMatchesSearch(run, currentSearch);
28
- });
37
+ const filteredRuns = useMemo(
38
+ () => runs.filter((run) => runMatchesFilters(run, currentSearch)),
39
+ [runs, currentSearch],
40
+ );
41
+ const facets = useMemo(() => workflowRunFacets(runs, currentSearch), [runs, currentSearch]);
42
+ const hasActiveFilters = hasWorkflowRunFilters(currentSearch);
43
+
44
+ function handleFiltersChange(patch: WorkflowRunFilterPatch) {
45
+ if (onFiltersChange) onFiltersChange(patch);
46
+ else setLocalSearch((previous) => applyWorkflowRunFilterPatch(previous, patch));
47
+ }
29
48
 
30
49
  function handleClearFilters() {
31
- if (onFiltersChange) onFiltersChange({});
32
- else {
33
- setLocalSearch('');
34
- setLocalStatusFilter('all');
35
- }
50
+ // Uncontrolled, the view owns the filters, so it clears them itself and still reports the
51
+ // change; a caller that passes only `onClearFilters` would otherwise see nothing happen.
52
+ if (!onFiltersChange) setLocalSearch(clearWorkflowRunFilters);
53
+ else if (!onClearFilters) onFiltersChange(CLEAR_ALL_FILTERS);
54
+ onClearFilters?.();
36
55
  }
37
56
 
38
57
  return (
39
58
  <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>
40
- <aside
41
- className={cn(
42
- 'flex w-304 shrink-0 flex-col border-r border-border-neutral-base bg-background-subtle-base',
43
- className,
44
- )}
45
- aria-label="Workflow runs"
59
+ <section
60
+ aria-labelledby={headingId}
61
+ className={cn('flex min-h-0 min-w-0 flex-1 flex-col gap-12', className)}
46
62
  >
47
- <WorkflowRunListHeader
48
- query={currentSearch}
49
- onQueryChange={(next) => {
50
- if (onFiltersChange)
51
- onFiltersChange({...(next ? {search: next} : {}), status: currentStatusFilter});
52
- else setLocalSearch(next);
53
- }}
54
- statusFilter={currentStatusFilter}
55
- onStatusFilterChange={(next) => {
56
- if (onFiltersChange)
57
- onFiltersChange({...(currentSearch ? {search: currentSearch} : {}), status: next});
58
- else setLocalStatusFilter(next);
59
- }}
63
+ {/* The tab strip above already reads "Runs", so the page heading is for structure and
64
+ assistive tech rather than a second visible title competing with it. */}
65
+ <Header id={headingId} variant="h1" className="sr-only">
66
+ Workflow runs
67
+ </Header>
68
+
69
+ <WorkflowRunFilters
70
+ search={currentSearch}
71
+ facets={facets}
72
+ onChange={handleFiltersChange}
73
+ onClear={handleClearFilters}
74
+ hasActiveFilters={hasActiveFilters}
60
75
  />
76
+
61
77
  <WorkflowRunListContent
62
78
  query={query}
63
79
  totalRuns={runs.length}
64
80
  runs={filteredRuns}
65
- workspaceId={workspaceId}
66
- projectId={projectId}
67
- selectedWorkflowRunId={selectedWorkflowRunId}
81
+ workspaceSlug={workspaceSlug}
82
+ projectSlug={projectSlug}
83
+ hasActiveFilters={hasActiveFilters}
68
84
  onClearFilters={handleClearFilters}
85
+ hasNextPage={hasNextPage}
86
+ isFetchingNextPage={isFetchingNextPage}
87
+ isFetchNextPageError={isFetchNextPageError}
88
+ {...(onLoadMore ? {onLoadMore} : {})}
69
89
  />
70
- </aside>
90
+ </section>
71
91
  </TimeTickerProvider>
72
92
  );
73
93
  }
94
+
95
+ const CLEAR_ALL_FILTERS: WorkflowRunFilterPatch = {
96
+ search: undefined,
97
+ status: undefined,
98
+ branch: undefined,
99
+ actor: undefined,
100
+ event: undefined,
101
+ after: undefined,
102
+ before: undefined,
103
+ };
@@ -1,9 +1,10 @@
1
+ import type {JobStatusDto} from '@shipfox/api-workflows-dto';
1
2
  import {Code} from '@shipfox/react-ui/typography';
2
3
  import type {Meta, StoryObj} from '@storybook/react';
3
4
  import type {ReactNode} from 'react';
4
5
  import {expect, userEvent, within} from 'storybook/test';
5
6
  import type {WorkflowRunListItem, WorkflowRunStatus} from '#core/workflow-run.js';
6
- import {sequencedWorkflowRunListItem} from '#test/fixtures/workflow-run.js';
7
+ import {sequencedWorkflowRunListItem, workflowRunJobsFixture} from '#test/fixtures/workflow-run.js';
7
8
  import type {WorkflowRunListQuery} from './types.js';
8
9
  import {WorkflowRunListView} from './workflow-run-list-view.js';
9
10
 
@@ -21,30 +22,68 @@ function makeQuery(overrides: Partial<WorkflowRunListQuery> = {}): WorkflowRunLi
21
22
  };
22
23
  }
23
24
 
24
- function makeRun(status: WorkflowRunStatus, name: string, minutesAgo: number): WorkflowRunListItem {
25
- return sequencedWorkflowRunListItem(status, name, minutesAgo);
25
+ const JOB_STRIP_NAME = /jobs:/u;
26
+ const STATUS_FILTER = /^Status\b.*filter$/u;
27
+
28
+ let commitSequence = 0;
29
+
30
+ // Distinct, plausible SHAs: a story that repeats one commit down the list reads as a bug in
31
+ // the row rather than as sample data.
32
+ function nextCommit(): string {
33
+ commitSequence += 1;
34
+ return (commitSequence * 0x9e3779b1).toString(16).padStart(8, '0').repeat(5).slice(0, 40);
35
+ }
36
+
37
+ function makeRun(
38
+ status: WorkflowRunStatus,
39
+ name: string,
40
+ minutesAgo: number,
41
+ {
42
+ ref = 'refs/heads/main',
43
+ actor = 'octocat',
44
+ jobs = [],
45
+ }: {ref?: string; actor?: string; jobs?: JobStatusDto[]} = {},
46
+ ): WorkflowRunListItem {
47
+ return sequencedWorkflowRunListItem(status, name, minutesAgo, {
48
+ workflow_name: name,
49
+ trigger_reference: {repository: 'acme/checkout-api', ref, commit: nextCommit(), actor},
50
+ ...workflowRunJobsFixture(jobs),
51
+ });
26
52
  }
27
53
 
28
54
  const SAMPLE_RUNS: WorkflowRunListItem[] = [
29
- makeRun('running', 'deploy-web', 1),
30
- makeRun('failed', 'integration-tests', 4),
31
- makeRun('succeeded', 'build-image', 12),
32
- makeRun('cancelled', 'lint-and-type', 38),
33
- makeRun('pending', 'release-prod', 0),
34
- makeRun('succeeded', 'release-production-multi-region-with-canary-and-smoke-tests', 95),
55
+ makeRun('running', 'deploy-web', 1, {
56
+ ref: 'refs/pull/482/head',
57
+ jobs: ['succeeded', 'succeeded', 'running', 'pending'],
58
+ }),
59
+ makeRun('failed', 'integration-tests', 4, {
60
+ ref: 'refs/heads/release/v2',
61
+ actor: 'hubot',
62
+ jobs: ['succeeded', 'failed', 'skipped', 'skipped'],
63
+ }),
64
+ makeRun('succeeded', 'build-image', 12, {jobs: ['succeeded', 'succeeded']}),
65
+ makeRun('cancelled', 'lint-and-type', 38, {
66
+ actor: 'dependabot',
67
+ jobs: ['succeeded', 'cancelled'],
68
+ }),
69
+ makeRun('pending', 'release-prod', 2),
70
+ makeRun('succeeded', 'release-production-multi-region-with-canary-and-smoke-tests', 95, {
71
+ ref: 'refs/tags/v2.14.0',
72
+ jobs: ['succeeded', 'succeeded', 'succeeded', 'succeeded', 'succeeded'],
73
+ }),
35
74
  ];
36
75
 
37
- // One story on the full rail. The data states (loading / empty / errors / runs) are
38
- // driven by args; search, status filter, "clear filters" and "no matches" are live in
39
- // the rendered toolbar since the view owns that state. The decorator gives the rail a
40
- // real height so `flex-1` content scrolls the way it does in the app shell.
76
+ // One story on the full-width page. The data states (loading / empty / errors / runs) are
77
+ // driven by args; search, the filter menus, "clear filters" and "no matches" are live in the
78
+ // rendered toolbar since the view owns that state. The decorator gives the list the 1120px
79
+ // content cap and a real height, so `flex-1` scrolls the way it does in the app shell.
41
80
  const meta = {
42
81
  title: 'Workflows/WorkflowRunList',
43
82
  component: WorkflowRunListView,
44
83
  parameters: {layout: 'centered'},
45
84
  decorators: [
46
85
  (Story) => (
47
- <div className="flex h-600">
86
+ <div className="flex h-600 w-[1120px] max-w-full bg-background-neutral-base p-24">
48
87
  <Story />
49
88
  </div>
50
89
  ),
@@ -52,8 +91,8 @@ const meta = {
52
91
  args: {
53
92
  runs: SAMPLE_RUNS,
54
93
  query: makeQuery(),
55
- workspaceId: 'ws-demo',
56
- projectId: 'proj-demo',
94
+ workspaceSlug: 'acme',
95
+ projectSlug: 'checkout-api',
57
96
  },
58
97
  } satisfies Meta<typeof WorkflowRunListView>;
59
98
 
@@ -62,8 +101,69 @@ type Story = StoryObj<typeof meta>;
62
101
 
63
102
  export const Playground: Story = {};
64
103
 
65
- export const Selected: Story = {
66
- args: {selectedWorkflowRunId: SAMPLE_RUNS[1].id},
104
+ /**
105
+ * The row under its one-line threshold, at the 720px a 768px viewport leaves the column.
106
+ *
107
+ * The row's breakpoints are container queries, so narrowing the wrapper is enough to reach
108
+ * this state: identity and numerics hold line one, provenance drops beneath, and the actor
109
+ * and job strip give up their columns. The filter row still renders inline because the sheet
110
+ * it collapses into is keyed to the viewport, not the container.
111
+ */
112
+ export const NarrowLayout: Story = {
113
+ decorators: [
114
+ (Story) => (
115
+ <div className="flex w-[720px] max-w-full">
116
+ <Story />
117
+ </div>
118
+ ),
119
+ ],
120
+ play: async ({canvasElement}) => {
121
+ const canvas = within(canvasElement);
122
+
123
+ await expect(await canvas.findByText('deploy-web')).toBeVisible();
124
+ // The branch stays on the provenance line; the actor is the column that gives way. It is
125
+ // still in the DOM, so visibility is what distinguishes "dropped for width" from
126
+ // "never rendered". `dependabot` is the one actor a single run carries.
127
+ await expect(canvas.getByText('release/v2')).toBeVisible();
128
+ await expect(canvas.getByText('dependabot')).not.toBeVisible();
129
+ await expect(canvas.queryByRole('img', {name: JOB_STRIP_NAME})).not.toBeInTheDocument();
130
+ },
131
+ };
132
+
133
+ /**
134
+ * Row density against the three strip sizes the threshold has to survive: comfortably under
135
+ * it, comfortably over it, and far enough over that the overflow count carries the failure.
136
+ */
137
+ export const JobStripDensity: Story = {
138
+ args: {
139
+ runs: [
140
+ makeRun('succeeded', 'two-jobs', 2, {jobs: ['succeeded', 'succeeded']}),
141
+ makeRun('failed', 'twelve-jobs', 6, {
142
+ jobs: [
143
+ 'succeeded',
144
+ 'succeeded',
145
+ 'succeeded',
146
+ 'failed',
147
+ 'succeeded',
148
+ 'succeeded',
149
+ 'skipped',
150
+ 'skipped',
151
+ 'succeeded',
152
+ 'succeeded',
153
+ 'succeeded',
154
+ 'succeeded',
155
+ ],
156
+ }),
157
+ makeRun('running', 'forty-jobs', 9, {
158
+ jobs: [
159
+ ...(Array.from({length: 8}, () => 'succeeded') as JobStatusDto[]),
160
+ ...(Array.from({length: 4}, () => 'running') as JobStatusDto[]),
161
+ 'failed',
162
+ ...(Array.from({length: 27}, () => 'pending') as JobStatusDto[]),
163
+ ],
164
+ }),
165
+ ],
166
+ },
67
167
  };
68
168
 
69
169
  export const DataStates: Story = {
@@ -94,16 +194,36 @@ export const TestNoMatches: Story = {
94
194
  const canvas = within(canvasElement);
95
195
  await userEvent.type(canvas.getByLabelText('Search runs'), 'no-such-run');
96
196
  await expect(await canvas.findByText('No matching runs')).toBeInTheDocument();
197
+ await expect(canvas.getByRole('button', {name: 'Show all runs'})).toBeInTheDocument();
198
+ },
199
+ };
200
+
201
+ export const TestMultiSelectFilter: Story = {
202
+ play: async ({canvasElement}) => {
203
+ const canvas = within(canvasElement);
204
+ await userEvent.click(canvas.getByRole('button', {name: STATUS_FILTER}));
205
+ const menu = await within(document.body).findByRole('menu');
206
+ await userEvent.click(within(menu).getByRole('menuitemcheckbox', {name: 'Failed'}));
207
+ await userEvent.click(within(menu).getByRole('menuitemcheckbox', {name: 'Cancelled'}));
208
+ await userEvent.keyboard('{Escape}');
209
+
210
+ // Radix keeps the rest of the document `aria-hidden` until the menu finishes closing, so
211
+ // the trigger is queried with a retrying matcher rather than read on the next tick.
212
+ await expect(await canvas.findByRole('button', {name: STATUS_FILTER})).toHaveTextContent(
213
+ 'Status · 2',
214
+ );
215
+ await expect(canvas.getByText('integration-tests')).toBeInTheDocument();
216
+ await expect(canvas.queryByText('build-image')).not.toBeInTheDocument();
97
217
  },
98
218
  };
99
219
 
100
220
  function StateExample({label, children}: {label: string; children: ReactNode}) {
101
221
  return (
102
- <div className="flex w-304 flex-col gap-8">
222
+ <div className="flex min-w-0 flex-col gap-8">
103
223
  <Code variant="label" className="text-foreground-neutral-subtle">
104
224
  {label}
105
225
  </Code>
106
- <div className="flex h-560 rounded-8 border border-border-neutral-base bg-background-neutral-base">
226
+ <div className="flex h-560 rounded-8 border border-border-neutral-base bg-background-neutral-base p-16">
107
227
  {children}
108
228
  </div>
109
229
  </div>
@@ -1,19 +1,26 @@
1
- import {useMemo} from 'react';
1
+ import {useCallback, useMemo} from 'react';
2
2
  import type {WorkflowRunListItem} from '#core/workflow-run.js';
3
3
  import {useWorkflowRunsInfiniteQuery} from '#hooks/api/workflow-runs.js';
4
4
  import type {WorkflowRunListProps} from './types.js';
5
5
  import {WorkflowRunListView} from './workflow-run-list-view.js';
6
6
 
7
7
  export function WorkflowRunList({
8
- workspaceId,
9
8
  projectId,
10
- selectedWorkflowRunId,
9
+ workspaceSlug,
10
+ projectSlug,
11
11
  className,
12
- search = '',
13
- statusFilter = 'all',
12
+ search,
14
13
  onFiltersChange,
14
+ onClearFilters,
15
+ hasNextPage,
16
+ isFetchingNextPage,
17
+ isFetchNextPageError,
18
+ onLoadMore,
15
19
  }: WorkflowRunListProps) {
16
20
  const query = useWorkflowRunsInfiniteQuery(projectId, {});
21
+ const handleLoadMore = useCallback(() => {
22
+ void query.fetchNextPage();
23
+ }, [query.fetchNextPage]);
17
24
  const runs = useMemo<WorkflowRunListItem[]>(
18
25
  () => query.data?.pages.flatMap((page) => page.runs) ?? [],
19
26
  [query.data],
@@ -23,13 +30,16 @@ export function WorkflowRunList({
23
30
  <WorkflowRunListView
24
31
  runs={runs}
25
32
  query={query}
26
- workspaceId={workspaceId}
27
- projectId={projectId}
28
- selectedWorkflowRunId={selectedWorkflowRunId}
33
+ workspaceSlug={workspaceSlug}
34
+ projectSlug={projectSlug}
29
35
  className={className}
30
- search={search}
31
- statusFilter={statusFilter}
36
+ {...(search ? {search} : {})}
32
37
  {...(onFiltersChange ? {onFiltersChange} : {})}
38
+ {...(onClearFilters ? {onClearFilters} : {})}
39
+ hasNextPage={hasNextPage ?? query.hasNextPage}
40
+ isFetchingNextPage={isFetchingNextPage ?? query.isFetchingNextPage}
41
+ isFetchNextPageError={isFetchNextPageError ?? query.isFetchNextPageError}
42
+ onLoadMore={onLoadMore ?? handleLoadMore}
33
43
  />
34
44
  );
35
45
  }