@shipfox/client-workflows 16.0.0 → 17.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 (180) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-type.log +1 -0
  3. package/CHANGELOG.md +20 -0
  4. package/dist/components/identifier/identifier.js +2 -2
  5. package/dist/components/identifier/identifier.js.map +1 -1
  6. package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
  7. package/dist/components/job-detail/agent-config-failure-callout.js +1 -1
  8. package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -1
  9. package/dist/components/job-detail/job-context-panel.d.ts +6 -0
  10. package/dist/components/job-detail/job-context-panel.d.ts.map +1 -0
  11. package/dist/components/job-detail/job-context-panel.js +224 -0
  12. package/dist/components/job-detail/job-context-panel.js.map +1 -0
  13. package/dist/components/job-detail/job-detail-header.d.ts +3 -1
  14. package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
  15. package/dist/components/job-detail/job-detail-header.js +54 -48
  16. package/dist/components/job-detail/job-detail-header.js.map +1 -1
  17. package/dist/components/job-detail/job-detail-view.d.ts +1 -1
  18. package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
  19. package/dist/components/job-detail/job-detail-view.js +80 -44
  20. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  21. package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
  22. package/dist/components/job-detail/job-empty-states.js +19 -10
  23. package/dist/components/job-detail/job-empty-states.js.map +1 -1
  24. package/dist/components/job-detail/job-execution-switcher.js +4 -4
  25. package/dist/components/job-detail/job-execution-switcher.js.map +1 -1
  26. package/dist/components/job-detail/json-code.d.ts +14 -0
  27. package/dist/components/job-detail/json-code.d.ts.map +1 -0
  28. package/dist/components/job-detail/json-code.js +93 -0
  29. package/dist/components/job-detail/json-code.js.map +1 -0
  30. package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
  31. package/dist/components/job-detail/step-attempt-log-panel.js +9 -6
  32. package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
  33. package/dist/components/job-detail/step-troubleshooting.d.ts +18 -0
  34. package/dist/components/job-detail/step-troubleshooting.d.ts.map +1 -0
  35. package/dist/components/job-detail/step-troubleshooting.js +493 -0
  36. package/dist/components/job-detail/step-troubleshooting.js.map +1 -0
  37. package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
  38. package/dist/components/job-graph/job-graph-content.js +5 -4
  39. package/dist/components/job-graph/job-graph-content.js.map +1 -1
  40. package/dist/components/job-graph/job-node.js +3 -3
  41. package/dist/components/job-graph/job-node.js.map +1 -1
  42. package/dist/components/step-list/index.d.ts +1 -0
  43. package/dist/components/step-list/index.d.ts.map +1 -1
  44. package/dist/components/step-list/index.js.map +1 -1
  45. package/dist/components/step-list/step-list-model.d.ts.map +1 -1
  46. package/dist/components/step-list/step-list-model.js +5 -0
  47. package/dist/components/step-list/step-list-model.js.map +1 -1
  48. package/dist/components/step-list/step-list.d.ts +5 -1
  49. package/dist/components/step-list/step-list.d.ts.map +1 -1
  50. package/dist/components/step-list/step-list.js +117 -82
  51. package/dist/components/step-list/step-list.js.map +1 -1
  52. package/dist/components/workflow-run-duration-label.js +1 -1
  53. package/dist/components/workflow-run-duration-label.js.map +1 -1
  54. package/dist/components/workflow-run-list/job-status-strip.js +6 -6
  55. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
  56. package/dist/components/workflow-run-list/workflow-run-filter-menu.js +1 -1
  57. package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -1
  58. package/dist/components/workflow-run-list/workflow-run-filters.js +4 -4
  59. package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
  60. package/dist/components/workflow-run-list/workflow-run-list-states.js +6 -6
  61. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  62. package/dist/components/workflow-run-list/workflow-run-list-view.js +1 -1
  63. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  64. package/dist/components/workflow-run-list/workflow-run-row.js +7 -7
  65. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  66. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +1 -1
  67. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
  68. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +0 -1
  69. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  70. package/dist/components/workflow-run-summary/workflow-run-summary.js +8 -13
  71. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  72. package/dist/components/workflow-run-tabs/index.d.ts +1 -1
  73. package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
  74. package/dist/components/workflow-run-tabs/index.js.map +1 -1
  75. package/dist/components/workflow-run-tabs/run-annotation-count-chip.js +2 -2
  76. package/dist/components/workflow-run-tabs/run-annotation-count-chip.js.map +1 -1
  77. package/dist/components/workflow-run-tabs/run-annotation-list.d.ts +9 -2
  78. package/dist/components/workflow-run-tabs/run-annotation-list.d.ts.map +1 -1
  79. package/dist/components/workflow-run-tabs/run-annotation-list.js +28 -19
  80. package/dist/components/workflow-run-tabs/run-annotation-list.js.map +1 -1
  81. package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -1
  82. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +5 -5
  83. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -1
  84. package/dist/components/workflow-run-view/run-workspace-nav.js +7 -7
  85. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  86. package/dist/components/workflow-run-view/workflow-run-states.js +6 -6
  87. package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
  88. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  89. package/dist/components/workflow-run-view/workflow-run-view.js +72 -12
  90. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  91. package/dist/core/entities/job-execution.d.ts +7 -0
  92. package/dist/core/entities/job-execution.d.ts.map +1 -1
  93. package/dist/core/entities/job-execution.js.map +1 -1
  94. package/dist/core/entities/job.d.ts +9 -0
  95. package/dist/core/entities/job.d.ts.map +1 -1
  96. package/dist/core/entities/job.js.map +1 -1
  97. package/dist/core/entities/step-attempt.d.ts +29 -0
  98. package/dist/core/entities/step-attempt.d.ts.map +1 -1
  99. package/dist/core/entities/step-attempt.js.map +1 -1
  100. package/dist/core/entities/step.d.ts +3 -1
  101. package/dist/core/entities/step.d.ts.map +1 -1
  102. package/dist/core/entities/step.js.map +1 -1
  103. package/dist/core/run-annotation.d.ts +6 -0
  104. package/dist/core/run-annotation.d.ts.map +1 -1
  105. package/dist/core/run-annotation.js.map +1 -1
  106. package/dist/core/workflow-run.d.ts +1 -1
  107. package/dist/core/workflow-run.d.ts.map +1 -1
  108. package/dist/core/workflow-run.js.map +1 -1
  109. package/dist/hooks/api/annotations.d.ts +63 -0
  110. package/dist/hooks/api/annotations.d.ts.map +1 -0
  111. package/dist/hooks/api/annotations.js +145 -0
  112. package/dist/hooks/api/annotations.js.map +1 -0
  113. package/dist/hooks/api/step-attempt-detail.d.ts +14 -0
  114. package/dist/hooks/api/step-attempt-detail.d.ts.map +1 -0
  115. package/dist/hooks/api/step-attempt-detail.js +43 -0
  116. package/dist/hooks/api/step-attempt-detail.js.map +1 -0
  117. package/dist/hooks/api/workflow-run-mapper.d.ts +9 -2
  118. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  119. package/dist/hooks/api/workflow-run-mapper.js +47 -0
  120. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  121. package/dist/pages/project-workflows-page.js +19 -19
  122. package/dist/pages/project-workflows-page.js.map +1 -1
  123. package/dist/pages/workflow-run-list-page.js +1 -1
  124. package/dist/pages/workflow-run-list-page.js.map +1 -1
  125. package/dist/tsconfig.test.tsbuildinfo +1 -1
  126. package/package.json +10 -10
  127. package/src/components/identifier/identifier.tsx +2 -2
  128. package/src/components/job-detail/agent-config-failure-callout.tsx +5 -1
  129. package/src/components/job-detail/job-context-panel.test.tsx +72 -0
  130. package/src/components/job-detail/job-context-panel.tsx +237 -0
  131. package/src/components/job-detail/job-detail-header.tsx +52 -46
  132. package/src/components/job-detail/job-detail-view.stories.tsx +555 -53
  133. package/src/components/job-detail/job-detail-view.tsx +87 -45
  134. package/src/components/job-detail/job-empty-states.tsx +23 -10
  135. package/src/components/job-detail/job-execution-switcher.tsx +5 -5
  136. package/src/components/job-detail/json-code.tsx +120 -0
  137. package/src/components/job-detail/step-attempt-log-panel.test.tsx +1 -0
  138. package/src/components/job-detail/step-attempt-log-panel.tsx +17 -6
  139. package/src/components/job-detail/step-troubleshooting.stories.tsx +120 -0
  140. package/src/components/job-detail/step-troubleshooting.test.tsx +337 -0
  141. package/src/components/job-detail/step-troubleshooting.tsx +537 -0
  142. package/src/components/job-graph/job-graph-content.tsx +4 -3
  143. package/src/components/job-graph/job-node.tsx +3 -3
  144. package/src/components/step-list/index.ts +1 -0
  145. package/src/components/step-list/step-list-model.ts +5 -0
  146. package/src/components/step-list/step-list.test.tsx +75 -2
  147. package/src/components/step-list/step-list.tsx +73 -20
  148. package/src/components/workflow-run-duration-label.tsx +1 -1
  149. package/src/components/workflow-run-list/job-status-strip.tsx +6 -6
  150. package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +1 -1
  151. package/src/components/workflow-run-list/workflow-run-filters.tsx +4 -4
  152. package/src/components/workflow-run-list/workflow-run-list-states.tsx +6 -6
  153. package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
  154. package/src/components/workflow-run-list/workflow-run-row.tsx +7 -7
  155. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +1 -1
  156. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +1 -1
  157. package/src/components/workflow-run-summary/workflow-run-summary.tsx +11 -11
  158. package/src/components/workflow-run-tabs/index.ts +5 -1
  159. package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +2 -2
  160. package/src/components/workflow-run-tabs/run-annotation-list.tsx +25 -10
  161. package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +5 -5
  162. package/src/components/workflow-run-view/run-workspace-nav.tsx +7 -7
  163. package/src/components/workflow-run-view/workflow-run-states.tsx +6 -6
  164. package/src/components/workflow-run-view/workflow-run-view.tsx +114 -14
  165. package/src/core/entities/job-execution.ts +7 -0
  166. package/src/core/entities/job.ts +9 -0
  167. package/src/core/entities/step-attempt.ts +33 -0
  168. package/src/core/entities/step.ts +3 -1
  169. package/src/core/run-annotation.ts +6 -0
  170. package/src/core/workflow-run.ts +4 -0
  171. package/src/hooks/api/annotations.test.ts +84 -0
  172. package/src/hooks/api/annotations.ts +240 -0
  173. package/src/hooks/api/step-attempt-detail.ts +67 -0
  174. package/src/hooks/api/workflow-run-mapper.ts +46 -0
  175. package/src/hooks/api/workflow-runs.test.tsx +61 -1
  176. package/src/pages/project-workflows-page.tsx +19 -19
  177. package/src/pages/workflow-job-detail-page.test.tsx +52 -1
  178. package/src/pages/workflow-run-list-page.tsx +1 -1
  179. package/test/fixtures/workflow-run.ts +7 -0
  180. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-graph/job-graph-content.tsx"],"sourcesContent":["import {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {KeyboardEvent} from 'react';\nimport {useRef, useState} from 'react';\nimport type {WorkflowRunDetail} from '#core/workflow-run.js';\nimport type {JobGraphModel, JobGraphNavigationKey} from './graph-model.js';\nimport {nextJobGraphNodeId} from './graph-model.js';\nimport {JobNode, TriggerNode} from './job-node.js';\nimport type {JobGraphSelectionSource} from './types.js';\n\nconst NODE_WIDTH = 208;\nconst NODE_HEIGHT = 48;\nconst COLUMN_GAP = 64;\nconst ROW_GAP = 20;\nconst TRIGGER_WIDTH = 36;\nconst PADDING = 16;\n\nexport function JobGraphContent({\n model,\n trigger,\n selectedJobId,\n onSelectJob,\n}: {\n model: JobGraphModel;\n trigger: Pick<\n WorkflowRunDetail,\n 'triggerDisplayLabel' | 'triggerLabel' | 'triggerProvider' | 'triggerSource'\n >;\n selectedJobId?: string | undefined;\n onSelectJob: (jobId: string | undefined, source?: JobGraphSelectionSource) => void;\n}) {\n const nodeRefs = useRef(new Map<string, HTMLButtonElement>());\n const [hoveredJobId, setHoveredJobId] = useState<string | undefined>();\n\n if (model.nodes.length === 0) {\n return (\n <EmptyState\n className=\"min-h-160 px-16 py-24\"\n icon=\"componentLine\"\n title=\"No jobs yet\"\n description=\"This run has not materialized jobs.\"\n variant=\"compact\"\n />\n );\n }\n\n const maxRows = Math.max(1, ...model.columns.map((column) => column.length));\n const contentWidth =\n PADDING * 2 +\n TRIGGER_WIDTH +\n COLUMN_GAP +\n model.columns.length * NODE_WIDTH +\n Math.max(0, model.columns.length - 1) * COLUMN_GAP;\n const contentHeight = PADDING * 2 + maxRows * NODE_HEIGHT + Math.max(0, maxRows - 1) * ROW_GAP;\n\n function setNodeRef(jobId: string) {\n return (element: HTMLButtonElement | null) => {\n if (element) {\n nodeRefs.current.set(jobId, element);\n } else {\n nodeRefs.current.delete(jobId);\n }\n };\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLButtonElement>) {\n const key = navigationKey(event.key);\n if (!key) return;\n\n const currentNodeId = event.currentTarget.dataset.jobId;\n if (!currentNodeId) return;\n\n const nextNodeId = nextJobGraphNodeId({model, currentNodeId, key});\n if (!nextNodeId) return;\n\n event.preventDefault();\n onSelectJob(nextNodeId, 'keyboard');\n nodeRefs.current.get(nextNodeId)?.focus();\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <div className=\"min-h-0 overflow-auto bg-transparent\">\n <div className=\"relative\" style={{width: contentWidth, minHeight: contentHeight}}>\n <GraphEdges model={model} hoveredJobId={hoveredJobId} />\n <div\n className=\"absolute\"\n style={{left: PADDING, top: PADDING + (NODE_HEIGHT - TRIGGER_WIDTH) / 2}}\n >\n <TriggerNode trigger={trigger} />\n </div>\n {model.columns.map((column, columnIndex) => (\n <div\n key={column.map((node) => node.id).join(':')}\n className=\"absolute flex flex-col gap-20\"\n style={{left: jobLeft(columnIndex), top: PADDING}}\n >\n {column.map((node) => (\n <JobNode\n key={node.id}\n node={node}\n selected={node.id === selectedJobId}\n ref={setNodeRef(node.id)}\n onSelect={() =>\n onSelectJob(node.id === selectedJobId ? undefined : node.id, 'pointer')\n }\n onKeyDown={handleKeyDown}\n onHoverStart={() => setHoveredJobId(node.id)}\n onHoverEnd={() =>\n setHoveredJobId((current) => (current === node.id ? undefined : current))\n }\n />\n ))}\n </div>\n ))}\n </div>\n </div>\n </TimeTickerProvider>\n );\n}\n\nfunction navigationKey(key: string): JobGraphNavigationKey | undefined {\n if (\n key === 'ArrowRight' ||\n key === 'ArrowLeft' ||\n key === 'ArrowDown' ||\n key === 'ArrowUp' ||\n key === 'j' ||\n key === 'k'\n ) {\n return key;\n }\n return undefined;\n}\n\nfunction GraphEdges({\n model,\n hoveredJobId,\n}: {\n model: JobGraphModel;\n hoveredJobId?: string | undefined;\n}) {\n const byId = new Map(model.nodes.map((node) => [node.id, node]));\n const edgeViews = model.edges\n .map((edge) => {\n const fromNode = byId.get(edge.from);\n const toNode = byId.get(edge.to);\n const from = edge.from === 'trigger' ? triggerPoint() : jobRightPoint(fromNode);\n const to = jobLeftPoint(toNode);\n if (!from || !to) return undefined;\n\n return {\n id: edge.id,\n highlighted: edge.from === hoveredJobId || edge.to === hoveredJobId,\n path: edgePath({from, fromNode, to, toNode}),\n };\n })\n .filter((edgeView): edgeView is NonNullable<typeof edgeView> => edgeView !== undefined)\n .sort((left, right) => Number(left.highlighted) - Number(right.highlighted));\n\n return (\n <svg className=\"pointer-events-none absolute inset-0 size-full\" aria-hidden=\"true\">\n {edgeViews.map((edge) => {\n return (\n <g\n key={edge.id}\n className={cn(\n 'text-foreground-neutral-muted transition-colors',\n edge.highlighted && 'text-foreground-neutral-base',\n )}\n >\n <path\n data-edge-id={edge.id}\n d={edge.path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={edge.highlighted ? 1.5 : 1}\n />\n </g>\n );\n })}\n </svg>\n );\n}\n\nfunction edgePath({\n from,\n fromNode,\n to,\n toNode,\n}: {\n from: {x: number; y: number};\n fromNode: {column: number} | undefined;\n to: {x: number; y: number};\n toNode: {column: number} | undefined;\n}) {\n if (fromNode && toNode && toNode.column - fromNode.column > 1 && from.y !== to.y) {\n const targetLaneX = to.x - COLUMN_GAP / 2;\n return `M ${from.x} ${from.y} H ${targetLaneX} V ${to.y} H ${to.x}`;\n }\n\n const midX = from.x + (to.x - from.x) / 2;\n return `M ${from.x} ${from.y} H ${midX} V ${to.y} H ${to.x}`;\n}\n\nfunction triggerPoint() {\n return {x: PADDING + TRIGGER_WIDTH, y: PADDING + NODE_HEIGHT / 2};\n}\n\nfunction jobLeft(column: number): number {\n // Dependency depths are contiguous, so a node's depth matches its rendered column index.\n return PADDING + TRIGGER_WIDTH + COLUMN_GAP + column * (NODE_WIDTH + COLUMN_GAP);\n}\n\nfunction jobTop(row: number): number {\n return PADDING + row * (NODE_HEIGHT + ROW_GAP);\n}\n\nfunction jobLeftPoint(node: {column: number; row: number} | undefined) {\n if (!node) return undefined;\n return {x: jobLeft(node.column), y: jobTop(node.row) + NODE_HEIGHT / 2};\n}\n\nfunction jobRightPoint(node: {column: number; row: number} | undefined) {\n if (!node) return undefined;\n return {x: jobLeft(node.column) + NODE_WIDTH, y: jobTop(node.row) + NODE_HEIGHT / 2};\n}\n"],"names":["EmptyState","TimeTickerProvider","cn","useRef","useState","nextJobGraphNodeId","JobNode","TriggerNode","NODE_WIDTH","NODE_HEIGHT","COLUMN_GAP","ROW_GAP","TRIGGER_WIDTH","PADDING","JobGraphContent","model","trigger","selectedJobId","onSelectJob","nodeRefs","Map","hoveredJobId","setHoveredJobId","nodes","length","className","icon","title","description","variant","maxRows","Math","max","columns","map","column","contentWidth","contentHeight","setNodeRef","jobId","element","current","set","delete","handleKeyDown","event","key","navigationKey","currentNodeId","currentTarget","dataset","nextNodeId","preventDefault","get","focus","intervalMs","reducedMotionIntervalMs","div","style","width","minHeight","GraphEdges","left","top","columnIndex","jobLeft","node","selected","id","ref","onSelect","undefined","onKeyDown","onHoverStart","onHoverEnd","join","byId","edgeViews","edges","edge","fromNode","from","toNode","to","triggerPoint","jobRightPoint","jobLeftPoint","highlighted","path","edgePath","filter","edgeView","sort","right","Number","svg","aria-hidden","g","data-edge-id","d","fill","stroke","strokeWidth","y","targetLaneX","x","midX","jobTop","row"],"mappings":";AAAA,SAAQA,UAAU,QAAO,gCAAgC;AACzD,SAAQC,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,SAAQC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAGvC,SAAQC,kBAAkB,QAAO,mBAAmB;AACpD,SAAQC,OAAO,EAAEC,WAAW,QAAO,gBAAgB;AAGnD,MAAMC,aAAa;AACnB,MAAMC,cAAc;AACpB,MAAMC,aAAa;AACnB,MAAMC,UAAU;AAChB,MAAMC,gBAAgB;AACtB,MAAMC,UAAU;AAEhB,OAAO,SAASC,gBAAgB,EAC9BC,KAAK,EACLC,OAAO,EACPC,aAAa,EACbC,WAAW,EASZ;IACC,MAAMC,WAAWhB,OAAO,IAAIiB;IAC5B,MAAM,CAACC,cAAcC,gBAAgB,GAAGlB;IAExC,IAAIW,MAAMQ,KAAK,CAACC,MAAM,KAAK,GAAG;QAC5B,qBACE,KAACxB;YACCyB,WAAU;YACVC,MAAK;YACLC,OAAM;YACNC,aAAY;YACZC,SAAQ;;IAGd;IAEA,MAAMC,UAAUC,KAAKC,GAAG,CAAC,MAAMjB,MAAMkB,OAAO,CAACC,GAAG,CAAC,CAACC,SAAWA,OAAOX,MAAM;IAC1E,MAAMY,eACJvB,UAAU,IACVD,gBACAF,aACAK,MAAMkB,OAAO,CAACT,MAAM,GAAGhB,aACvBuB,KAAKC,GAAG,CAAC,GAAGjB,MAAMkB,OAAO,CAACT,MAAM,GAAG,KAAKd;IAC1C,MAAM2B,gBAAgBxB,UAAU,IAAIiB,UAAUrB,cAAcsB,KAAKC,GAAG,CAAC,GAAGF,UAAU,KAAKnB;IAEvF,SAAS2B,WAAWC,KAAa;QAC/B,OAAO,CAACC;YACN,IAAIA,SAAS;gBACXrB,SAASsB,OAAO,CAACC,GAAG,CAACH,OAAOC;YAC9B,OAAO;gBACLrB,SAASsB,OAAO,CAACE,MAAM,CAACJ;YAC1B;QACF;IACF;IAEA,SAASK,cAAcC,KAAuC;QAC5D,MAAMC,MAAMC,cAAcF,MAAMC,GAAG;QACnC,IAAI,CAACA,KAAK;QAEV,MAAME,gBAAgBH,MAAMI,aAAa,CAACC,OAAO,CAACX,KAAK;QACvD,IAAI,CAACS,eAAe;QAEpB,MAAMG,aAAa9C,mBAAmB;YAACU;YAAOiC;YAAeF;QAAG;QAChE,IAAI,CAACK,YAAY;QAEjBN,MAAMO,cAAc;QACpBlC,YAAYiC,YAAY;QACxBhC,SAASsB,OAAO,CAACY,GAAG,CAACF,aAAaG;IACpC;IAEA,qBACE,KAACrD;QAAmBsD,YAAY;QAAMC,yBAAyB;kBAC7D,cAAA,KAACC;YAAIhC,WAAU;sBACb,cAAA,MAACgC;gBAAIhC,WAAU;gBAAWiC,OAAO;oBAACC,OAAOvB;oBAAcwB,WAAWvB;gBAAa;;kCAC7E,KAACwB;wBAAW9C,OAAOA;wBAAOM,cAAcA;;kCACxC,KAACoC;wBACChC,WAAU;wBACViC,OAAO;4BAACI,MAAMjD;4BAASkD,KAAKlD,UAAU,AAACJ,CAAAA,cAAcG,aAAY,IAAK;wBAAC;kCAEvE,cAAA,KAACL;4BAAYS,SAASA;;;oBAEvBD,MAAMkB,OAAO,CAACC,GAAG,CAAC,CAACC,QAAQ6B,4BAC1B,KAACP;4BAEChC,WAAU;4BACViC,OAAO;gCAACI,MAAMG,QAAQD;gCAAcD,KAAKlD;4BAAO;sCAE/CsB,OAAOD,GAAG,CAAC,CAACgC,qBACX,KAAC5D;oCAEC4D,MAAMA;oCACNC,UAAUD,KAAKE,EAAE,KAAKnD;oCACtBoD,KAAK/B,WAAW4B,KAAKE,EAAE;oCACvBE,UAAU,IACRpD,YAAYgD,KAAKE,EAAE,KAAKnD,gBAAgBsD,YAAYL,KAAKE,EAAE,EAAE;oCAE/DI,WAAW5B;oCACX6B,cAAc,IAAMnD,gBAAgB4C,KAAKE,EAAE;oCAC3CM,YAAY,IACVpD,gBAAgB,CAACmB,UAAaA,YAAYyB,KAAKE,EAAE,GAAGG,YAAY9B;mCAV7DyB,KAAKE,EAAE;2BANXjC,OAAOD,GAAG,CAAC,CAACgC,OAASA,KAAKE,EAAE,EAAEO,IAAI,CAAC;;;;;AA0BtD;AAEA,SAAS5B,cAAcD,GAAW;IAChC,IACEA,QAAQ,gBACRA,QAAQ,eACRA,QAAQ,eACRA,QAAQ,aACRA,QAAQ,OACRA,QAAQ,KACR;QACA,OAAOA;IACT;IACA,OAAOyB;AACT;AAEA,SAASV,WAAW,EAClB9C,KAAK,EACLM,YAAY,EAIb;IACC,MAAMuD,OAAO,IAAIxD,IAAIL,MAAMQ,KAAK,CAACW,GAAG,CAAC,CAACgC,OAAS;YAACA,KAAKE,EAAE;YAAEF;SAAK;IAC9D,MAAMW,YAAY9D,MAAM+D,KAAK,CAC1B5C,GAAG,CAAC,CAAC6C;QACJ,MAAMC,WAAWJ,KAAKvB,GAAG,CAAC0B,KAAKE,IAAI;QACnC,MAAMC,SAASN,KAAKvB,GAAG,CAAC0B,KAAKI,EAAE;QAC/B,MAAMF,OAAOF,KAAKE,IAAI,KAAK,YAAYG,iBAAiBC,cAAcL;QACtE,MAAMG,KAAKG,aAAaJ;QACxB,IAAI,CAACD,QAAQ,CAACE,IAAI,OAAOZ;QAEzB,OAAO;YACLH,IAAIW,KAAKX,EAAE;YACXmB,aAAaR,KAAKE,IAAI,KAAK5D,gBAAgB0D,KAAKI,EAAE,KAAK9D;YACvDmE,MAAMC,SAAS;gBAACR;gBAAMD;gBAAUG;gBAAID;YAAM;QAC5C;IACF,GACCQ,MAAM,CAAC,CAACC,WAAuDA,aAAapB,WAC5EqB,IAAI,CAAC,CAAC9B,MAAM+B,QAAUC,OAAOhC,KAAKyB,WAAW,IAAIO,OAAOD,MAAMN,WAAW;IAE5E,qBACE,KAACQ;QAAItE,WAAU;QAAiDuE,eAAY;kBACzEnB,UAAU3C,GAAG,CAAC,CAAC6C;YACd,qBACE,KAACkB;gBAECxE,WAAWvB,GACT,mDACA6E,KAAKQ,WAAW,IAAI;0BAGtB,cAAA,KAACC;oBACCU,gBAAcnB,KAAKX,EAAE;oBACrB+B,GAAGpB,KAAKS,IAAI;oBACZY,MAAK;oBACLC,QAAO;oBACPC,aAAavB,KAAKQ,WAAW,GAAG,MAAM;;eAXnCR,KAAKX,EAAE;QAelB;;AAGN;AAEA,SAASqB,SAAS,EAChBR,IAAI,EACJD,QAAQ,EACRG,EAAE,EACFD,MAAM,EAMP;IACC,IAAIF,YAAYE,UAAUA,OAAO/C,MAAM,GAAG6C,SAAS7C,MAAM,GAAG,KAAK8C,KAAKsB,CAAC,KAAKpB,GAAGoB,CAAC,EAAE;QAChF,MAAMC,cAAcrB,GAAGsB,CAAC,GAAG/F,aAAa;QACxC,OAAO,CAAC,EAAE,EAAEuE,KAAKwB,CAAC,CAAC,CAAC,EAAExB,KAAKsB,CAAC,CAAC,GAAG,EAAEC,YAAY,GAAG,EAAErB,GAAGoB,CAAC,CAAC,GAAG,EAAEpB,GAAGsB,CAAC,EAAE;IACrE;IAEA,MAAMC,OAAOzB,KAAKwB,CAAC,GAAG,AAACtB,CAAAA,GAAGsB,CAAC,GAAGxB,KAAKwB,CAAC,AAADA,IAAK;IACxC,OAAO,CAAC,EAAE,EAAExB,KAAKwB,CAAC,CAAC,CAAC,EAAExB,KAAKsB,CAAC,CAAC,GAAG,EAAEG,KAAK,GAAG,EAAEvB,GAAGoB,CAAC,CAAC,GAAG,EAAEpB,GAAGsB,CAAC,EAAE;AAC9D;AAEA,SAASrB;IACP,OAAO;QAACqB,GAAG5F,UAAUD;QAAe2F,GAAG1F,UAAUJ,cAAc;IAAC;AAClE;AAEA,SAASwD,QAAQ9B,MAAc;IAC7B,yFAAyF;IACzF,OAAOtB,UAAUD,gBAAgBF,aAAayB,SAAU3B,CAAAA,aAAaE,UAAS;AAChF;AAEA,SAASiG,OAAOC,GAAW;IACzB,OAAO/F,UAAU+F,MAAOnG,CAAAA,cAAcE,OAAM;AAC9C;AAEA,SAAS2E,aAAapB,IAA+C;IACnE,IAAI,CAACA,MAAM,OAAOK;IAClB,OAAO;QAACkC,GAAGxC,QAAQC,KAAK/B,MAAM;QAAGoE,GAAGI,OAAOzC,KAAK0C,GAAG,IAAInG,cAAc;IAAC;AACxE;AAEA,SAAS4E,cAAcnB,IAA+C;IACpE,IAAI,CAACA,MAAM,OAAOK;IAClB,OAAO;QAACkC,GAAGxC,QAAQC,KAAK/B,MAAM,IAAI3B;QAAY+F,GAAGI,OAAOzC,KAAK0C,GAAG,IAAInG,cAAc;IAAC;AACrF"}
1
+ {"version":3,"sources":["../../../src/components/job-graph/job-graph-content.tsx"],"sourcesContent":["import {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {KeyboardEvent} from 'react';\nimport {useRef, useState} from 'react';\nimport type {WorkflowRunDetail} from '#core/workflow-run.js';\nimport type {JobGraphModel, JobGraphNavigationKey} from './graph-model.js';\nimport {nextJobGraphNodeId} from './graph-model.js';\nimport {JobNode, TriggerNode} from './job-node.js';\nimport type {JobGraphSelectionSource} from './types.js';\n\nconst NODE_WIDTH = 208;\nconst NODE_HEIGHT = 48;\nconst COLUMN_GAP = 64;\n/** Fixed graph spacing shared by the DOM rows and the edge geometry below. */\nconst ROW_GAP = 20;\nconst TRIGGER_WIDTH = 36;\nconst PADDING = 16;\n\nexport function JobGraphContent({\n model,\n trigger,\n selectedJobId,\n onSelectJob,\n}: {\n model: JobGraphModel;\n trigger: Pick<\n WorkflowRunDetail,\n 'triggerDisplayLabel' | 'triggerLabel' | 'triggerProvider' | 'triggerSource'\n >;\n selectedJobId?: string | undefined;\n onSelectJob: (jobId: string | undefined, source?: JobGraphSelectionSource) => void;\n}) {\n const nodeRefs = useRef(new Map<string, HTMLButtonElement>());\n const [hoveredJobId, setHoveredJobId] = useState<string | undefined>();\n\n if (model.nodes.length === 0) {\n return (\n <EmptyState\n className=\"min-h-160 p-panel\"\n icon=\"componentLine\"\n title=\"No jobs yet\"\n description=\"This run has not materialized jobs.\"\n variant=\"compact\"\n />\n );\n }\n\n const maxRows = Math.max(1, ...model.columns.map((column) => column.length));\n const contentWidth =\n PADDING * 2 +\n TRIGGER_WIDTH +\n COLUMN_GAP +\n model.columns.length * NODE_WIDTH +\n Math.max(0, model.columns.length - 1) * COLUMN_GAP;\n const contentHeight = PADDING * 2 + maxRows * NODE_HEIGHT + Math.max(0, maxRows - 1) * ROW_GAP;\n\n function setNodeRef(jobId: string) {\n return (element: HTMLButtonElement | null) => {\n if (element) {\n nodeRefs.current.set(jobId, element);\n } else {\n nodeRefs.current.delete(jobId);\n }\n };\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLButtonElement>) {\n const key = navigationKey(event.key);\n if (!key) return;\n\n const currentNodeId = event.currentTarget.dataset.jobId;\n if (!currentNodeId) return;\n\n const nextNodeId = nextJobGraphNodeId({model, currentNodeId, key});\n if (!nextNodeId) return;\n\n event.preventDefault();\n onSelectJob(nextNodeId, 'keyboard');\n nodeRefs.current.get(nextNodeId)?.focus();\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <div className=\"min-h-0 overflow-auto bg-transparent\">\n <div className=\"relative\" style={{width: contentWidth, minHeight: contentHeight}}>\n <GraphEdges model={model} hoveredJobId={hoveredJobId} />\n <div\n className=\"absolute\"\n style={{left: PADDING, top: PADDING + (NODE_HEIGHT - TRIGGER_WIDTH) / 2}}\n >\n <TriggerNode trigger={trigger} />\n </div>\n {model.columns.map((column, columnIndex) => (\n <div\n key={column.map((node) => node.id).join(':')}\n className=\"absolute flex flex-col\"\n style={{left: jobLeft(columnIndex), top: PADDING, rowGap: ROW_GAP}}\n >\n {column.map((node) => (\n <JobNode\n key={node.id}\n node={node}\n selected={node.id === selectedJobId}\n ref={setNodeRef(node.id)}\n onSelect={() =>\n onSelectJob(node.id === selectedJobId ? undefined : node.id, 'pointer')\n }\n onKeyDown={handleKeyDown}\n onHoverStart={() => setHoveredJobId(node.id)}\n onHoverEnd={() =>\n setHoveredJobId((current) => (current === node.id ? undefined : current))\n }\n />\n ))}\n </div>\n ))}\n </div>\n </div>\n </TimeTickerProvider>\n );\n}\n\nfunction navigationKey(key: string): JobGraphNavigationKey | undefined {\n if (\n key === 'ArrowRight' ||\n key === 'ArrowLeft' ||\n key === 'ArrowDown' ||\n key === 'ArrowUp' ||\n key === 'j' ||\n key === 'k'\n ) {\n return key;\n }\n return undefined;\n}\n\nfunction GraphEdges({\n model,\n hoveredJobId,\n}: {\n model: JobGraphModel;\n hoveredJobId?: string | undefined;\n}) {\n const byId = new Map(model.nodes.map((node) => [node.id, node]));\n const edgeViews = model.edges\n .map((edge) => {\n const fromNode = byId.get(edge.from);\n const toNode = byId.get(edge.to);\n const from = edge.from === 'trigger' ? triggerPoint() : jobRightPoint(fromNode);\n const to = jobLeftPoint(toNode);\n if (!from || !to) return undefined;\n\n return {\n id: edge.id,\n highlighted: edge.from === hoveredJobId || edge.to === hoveredJobId,\n path: edgePath({from, fromNode, to, toNode}),\n };\n })\n .filter((edgeView): edgeView is NonNullable<typeof edgeView> => edgeView !== undefined)\n .sort((left, right) => Number(left.highlighted) - Number(right.highlighted));\n\n return (\n <svg className=\"pointer-events-none absolute inset-0 size-full\" aria-hidden=\"true\">\n {edgeViews.map((edge) => {\n return (\n <g\n key={edge.id}\n className={cn(\n 'text-foreground-neutral-muted transition-colors',\n edge.highlighted && 'text-foreground-neutral-base',\n )}\n >\n <path\n data-edge-id={edge.id}\n d={edge.path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={edge.highlighted ? 1.5 : 1}\n />\n </g>\n );\n })}\n </svg>\n );\n}\n\nfunction edgePath({\n from,\n fromNode,\n to,\n toNode,\n}: {\n from: {x: number; y: number};\n fromNode: {column: number} | undefined;\n to: {x: number; y: number};\n toNode: {column: number} | undefined;\n}) {\n if (fromNode && toNode && toNode.column - fromNode.column > 1 && from.y !== to.y) {\n const targetLaneX = to.x - COLUMN_GAP / 2;\n return `M ${from.x} ${from.y} H ${targetLaneX} V ${to.y} H ${to.x}`;\n }\n\n const midX = from.x + (to.x - from.x) / 2;\n return `M ${from.x} ${from.y} H ${midX} V ${to.y} H ${to.x}`;\n}\n\nfunction triggerPoint() {\n return {x: PADDING + TRIGGER_WIDTH, y: PADDING + NODE_HEIGHT / 2};\n}\n\nfunction jobLeft(column: number): number {\n // Dependency depths are contiguous, so a node's depth matches its rendered column index.\n return PADDING + TRIGGER_WIDTH + COLUMN_GAP + column * (NODE_WIDTH + COLUMN_GAP);\n}\n\nfunction jobTop(row: number): number {\n return PADDING + row * (NODE_HEIGHT + ROW_GAP);\n}\n\nfunction jobLeftPoint(node: {column: number; row: number} | undefined) {\n if (!node) return undefined;\n return {x: jobLeft(node.column), y: jobTop(node.row) + NODE_HEIGHT / 2};\n}\n\nfunction jobRightPoint(node: {column: number; row: number} | undefined) {\n if (!node) return undefined;\n return {x: jobLeft(node.column) + NODE_WIDTH, y: jobTop(node.row) + NODE_HEIGHT / 2};\n}\n"],"names":["EmptyState","TimeTickerProvider","cn","useRef","useState","nextJobGraphNodeId","JobNode","TriggerNode","NODE_WIDTH","NODE_HEIGHT","COLUMN_GAP","ROW_GAP","TRIGGER_WIDTH","PADDING","JobGraphContent","model","trigger","selectedJobId","onSelectJob","nodeRefs","Map","hoveredJobId","setHoveredJobId","nodes","length","className","icon","title","description","variant","maxRows","Math","max","columns","map","column","contentWidth","contentHeight","setNodeRef","jobId","element","current","set","delete","handleKeyDown","event","key","navigationKey","currentNodeId","currentTarget","dataset","nextNodeId","preventDefault","get","focus","intervalMs","reducedMotionIntervalMs","div","style","width","minHeight","GraphEdges","left","top","columnIndex","jobLeft","rowGap","node","selected","id","ref","onSelect","undefined","onKeyDown","onHoverStart","onHoverEnd","join","byId","edgeViews","edges","edge","fromNode","from","toNode","to","triggerPoint","jobRightPoint","jobLeftPoint","highlighted","path","edgePath","filter","edgeView","sort","right","Number","svg","aria-hidden","g","data-edge-id","d","fill","stroke","strokeWidth","y","targetLaneX","x","midX","jobTop","row"],"mappings":"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"}
@@ -66,14 +66,14 @@ export function JobNode({ node, selected, onSelect, onKeyDown, onHoverStart, onH
66
66
  onKeyDown: onKeyDown,
67
67
  onPointerEnter: onHoverStart,
68
68
  onPointerLeave: onHoverEnd,
69
- className: cn('group relative flex h-48 w-208 cursor-pointer items-center gap-8 rounded-8 bg-background-neutral-base px-10 text-left shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none', selected && 'bg-background-components-hover hover:bg-background-components-pressed', node.carriedOver && 'opacity-[0.55]'),
69
+ className: cn('group relative flex h-48 w-208 cursor-pointer items-center gap-inline rounded-8 bg-background-neutral-base px-[10px] text-left shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none', selected && 'bg-background-components-hover hover:bg-background-components-pressed', node.carriedOver && 'opacity-[0.55]'),
70
70
  children: [
71
71
  selected ? /*#__PURE__*/ _jsx("span", {
72
72
  "aria-hidden": "true",
73
73
  className: "absolute inset-y-6 left-0 w-px rounded-full bg-border-highlights-interactive"
74
74
  }) : null,
75
75
  /*#__PURE__*/ _jsxs("div", {
76
- className: "flex min-w-0 flex-1 items-center gap-8",
76
+ className: "flex min-w-0 flex-1 items-center gap-inline",
77
77
  children: [
78
78
  /*#__PURE__*/ _jsx(WorkflowStatusIcon, {
79
79
  status: status,
@@ -102,7 +102,7 @@ function ExecutionCountText({ executions }) {
102
102
  asChild: true,
103
103
  children: /*#__PURE__*/ _jsxs("span", {
104
104
  "aria-hidden": "true",
105
- className: "inline-flex h-20 min-w-28 shrink-0 items-center justify-end gap-4 text-foreground-neutral-subtle",
105
+ className: "inline-flex h-20 min-w-28 shrink-0 items-center justify-end gap-tight text-foreground-neutral-subtle",
106
106
  children: [
107
107
  /*#__PURE__*/ _jsx(Icon, {
108
108
  name: "loopRightLine",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-graph/job-node.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {KeyboardEventHandler, Ref} from 'react';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n deriveJobExecutionDisplayStatus,\n type JobExecution,\n type JobExecutionStatus,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport type {JobGraphNode} from './graph-model.js';\nimport {formatJobDurationAccessibleLabel} from './job-duration-format.js';\nimport {JobDurationLabel} from './job-duration-label.js';\n\nconst TRIGGER_SIZE = 36;\n\nexport function TriggerNode({\n trigger,\n}: {\n trigger: Pick<\n WorkflowRunDetail,\n 'triggerDisplayLabel' | 'triggerLabel' | 'triggerProvider' | 'triggerSource'\n >;\n}) {\n const label = trigger.triggerDisplayLabel || 'trigger';\n const tooltip = trigger.triggerLabel || label;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className=\"flex cursor-help items-center justify-center rounded-full bg-background-neutral-base shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none\"\n style={{width: TRIGGER_SIZE, height: TRIGGER_SIZE}}\n >\n <TriggerSourceIcon\n provider={trigger.triggerProvider}\n source={trigger.triggerSource}\n aria-hidden\n className=\"size-14 shrink-0 text-foreground-neutral-subtle\"\n />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <span>{tooltip}</span>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nexport function JobNode({\n node,\n selected,\n onSelect,\n onKeyDown,\n onHoverStart,\n onHoverEnd,\n ref,\n}: {\n node: JobGraphNode;\n selected: boolean;\n onSelect: () => void;\n onKeyDown: KeyboardEventHandler<HTMLButtonElement>;\n onHoverStart: () => void;\n onHoverEnd: () => void;\n ref?: Ref<HTMLButtonElement>;\n}) {\n useTimeTick();\n const status = deriveJobDisplayStatus(node);\n const execution = defaultJobExecution(node);\n const visual = getWorkflowStatusVisual(status);\n const accessibleLabel = [\n node.displayName,\n visual.label,\n formatJobDurationAccessibleLabel(\n node.displayDuration,\n execution ? deriveJobExecutionDisplayStatus(execution) : undefined,\n ),\n node.executionCountVisible\n ? executionCountAccessibleLabel(node.jobExecutions.length)\n : undefined,\n node.carriedOver ? 'reused' : undefined,\n ]\n .filter((part): part is string => Boolean(part))\n .join(', ');\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-pressed={selected}\n aria-label={accessibleLabel}\n data-job-id={node.id}\n onClick={onSelect}\n onKeyDown={onKeyDown}\n onPointerEnter={onHoverStart}\n onPointerLeave={onHoverEnd}\n className={cn(\n 'group relative flex h-48 w-208 cursor-pointer items-center gap-8 rounded-8 bg-background-neutral-base px-10 text-left shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none',\n selected && 'bg-background-components-hover hover:bg-background-components-pressed',\n node.carriedOver && 'opacity-[0.55]',\n )}\n >\n {selected ? (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-y-6 left-0 w-px rounded-full bg-border-highlights-interactive\"\n />\n ) : null}\n <div className=\"flex min-w-0 flex-1 items-center gap-8\">\n <WorkflowStatusIcon status={status} size={14} />\n <JobLabel label={node.displayName} />\n </div>\n <JobDurationLabel duration={node.displayDuration} />\n {node.executionCountVisible ? <ExecutionCountText executions={node.jobExecutions} /> : null}\n {node.carriedOver ? <CarriedOverBadge /> : null}\n </button>\n );\n}\n\nfunction ExecutionCountText({executions}: {executions: JobExecution[]}) {\n const count = executions.length;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-20 min-w-28 shrink-0 items-center justify-end gap-4 text-foreground-neutral-subtle\"\n >\n <Icon name=\"loopRightLine\" className=\"size-12\" />\n <Code as=\"span\" variant=\"label\" className=\"text-current\">\n {count}\n </Code>\n </span>\n </TooltipTrigger>\n <TooltipContent>{executionCountTooltip(executions)}</TooltipContent>\n </Tooltip>\n );\n}\n\nfunction CarriedOverBadge() {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <Badge variant=\"neutral\" size=\"2xs\">\n reused\n </Badge>\n </span>\n </TooltipTrigger>\n <TooltipContent>\n Carried over from a previous attempt; did not run in this attempt\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction JobLabel({label}: {label: string}) {\n const {ref: labelRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(label);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={labelRef} className=\"block min-w-0 truncate\">\n <Code as=\"span\" variant=\"label\" bold className=\"text-foreground-neutral-base\">\n {label}\n </Code>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{label}</TooltipContent> : null}\n </Tooltip>\n );\n}\n\nfunction executionCountAccessibleLabel(count: number): string {\n return `${count} ${count === 1 ? 'execution' : 'executions'}`;\n}\n\nfunction executionCountTooltip(executions: JobExecution[]): string {\n const counts = executionStatusCounts(executions);\n const parts = EXECUTION_STATUSES.map((status) =>\n counts[status] > 0 ? `${counts[status]} ${status}` : undefined,\n ).filter((part): part is string => part !== undefined);\n return parts.length > 0 ? parts.join(', ') : 'No executions';\n}\n\nconst EXECUTION_STATUSES = [\n 'pending',\n 'running',\n 'succeeded',\n 'failed',\n 'cancelled',\n] as const satisfies readonly JobExecutionStatus[];\n\nfunction executionStatusCounts(executions: JobExecution[]) {\n return executions.reduce(\n (counts, execution) => {\n counts[deriveJobExecutionDisplayStatus(execution)] += 1;\n return counts;\n },\n {pending: 0, running: 0, succeeded: 0, failed: 0, cancelled: 0},\n );\n}\n"],"names":["TriggerSourceIcon","Badge","useIsTextTruncated","Icon","useTimeTick","Tooltip","TooltipContent","TooltipTrigger","Code","cn","getWorkflowStatusVisual","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","deriveJobExecutionDisplayStatus","formatJobDurationAccessibleLabel","JobDurationLabel","TRIGGER_SIZE","TriggerNode","trigger","label","triggerDisplayLabel","tooltip","triggerLabel","asChild","button","type","aria-label","className","style","width","height","provider","triggerProvider","source","triggerSource","aria-hidden","span","JobNode","node","selected","onSelect","onKeyDown","onHoverStart","onHoverEnd","ref","status","execution","visual","accessibleLabel","displayName","displayDuration","undefined","executionCountVisible","executionCountAccessibleLabel","jobExecutions","length","carriedOver","filter","part","Boolean","join","aria-pressed","data-job-id","id","onClick","onPointerEnter","onPointerLeave","div","size","JobLabel","duration","ExecutionCountText","executions","CarriedOverBadge","count","name","as","variant","executionCountTooltip","labelRef","isTruncated","bold","counts","executionStatusCounts","parts","EXECUTION_STATUSES","map","reduce","pending","running","succeeded","failed","cancelled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/job-graph/job-node.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {KeyboardEventHandler, Ref} from 'react';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n deriveJobExecutionDisplayStatus,\n type JobExecution,\n type JobExecutionStatus,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport type {JobGraphNode} from './graph-model.js';\nimport {formatJobDurationAccessibleLabel} from './job-duration-format.js';\nimport {JobDurationLabel} from './job-duration-label.js';\n\nconst TRIGGER_SIZE = 36;\n\nexport function TriggerNode({\n trigger,\n}: {\n trigger: Pick<\n WorkflowRunDetail,\n 'triggerDisplayLabel' | 'triggerLabel' | 'triggerProvider' | 'triggerSource'\n >;\n}) {\n const label = trigger.triggerDisplayLabel || 'trigger';\n const tooltip = trigger.triggerLabel || label;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className=\"flex cursor-help items-center justify-center rounded-full bg-background-neutral-base shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none\"\n style={{width: TRIGGER_SIZE, height: TRIGGER_SIZE}}\n >\n <TriggerSourceIcon\n provider={trigger.triggerProvider}\n source={trigger.triggerSource}\n aria-hidden\n className=\"size-14 shrink-0 text-foreground-neutral-subtle\"\n />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <span>{tooltip}</span>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nexport function JobNode({\n node,\n selected,\n onSelect,\n onKeyDown,\n onHoverStart,\n onHoverEnd,\n ref,\n}: {\n node: JobGraphNode;\n selected: boolean;\n onSelect: () => void;\n onKeyDown: KeyboardEventHandler<HTMLButtonElement>;\n onHoverStart: () => void;\n onHoverEnd: () => void;\n ref?: Ref<HTMLButtonElement>;\n}) {\n useTimeTick();\n const status = deriveJobDisplayStatus(node);\n const execution = defaultJobExecution(node);\n const visual = getWorkflowStatusVisual(status);\n const accessibleLabel = [\n node.displayName,\n visual.label,\n formatJobDurationAccessibleLabel(\n node.displayDuration,\n execution ? deriveJobExecutionDisplayStatus(execution) : undefined,\n ),\n node.executionCountVisible\n ? executionCountAccessibleLabel(node.jobExecutions.length)\n : undefined,\n node.carriedOver ? 'reused' : undefined,\n ]\n .filter((part): part is string => Boolean(part))\n .join(', ');\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-pressed={selected}\n aria-label={accessibleLabel}\n data-job-id={node.id}\n onClick={onSelect}\n onKeyDown={onKeyDown}\n onPointerEnter={onHoverStart}\n onPointerLeave={onHoverEnd}\n className={cn(\n 'group relative flex h-48 w-208 cursor-pointer items-center gap-inline rounded-8 bg-background-neutral-base px-[10px] text-left shadow-button-neutral transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus focus-visible:outline-none',\n selected && 'bg-background-components-hover hover:bg-background-components-pressed',\n node.carriedOver && 'opacity-[0.55]',\n )}\n >\n {selected ? (\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-y-6 left-0 w-px rounded-full bg-border-highlights-interactive\"\n />\n ) : null}\n <div className=\"flex min-w-0 flex-1 items-center gap-inline\">\n <WorkflowStatusIcon status={status} size={14} />\n <JobLabel label={node.displayName} />\n </div>\n <JobDurationLabel duration={node.displayDuration} />\n {node.executionCountVisible ? <ExecutionCountText executions={node.jobExecutions} /> : null}\n {node.carriedOver ? <CarriedOverBadge /> : null}\n </button>\n );\n}\n\nfunction ExecutionCountText({executions}: {executions: JobExecution[]}) {\n const count = executions.length;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-20 min-w-28 shrink-0 items-center justify-end gap-tight text-foreground-neutral-subtle\"\n >\n <Icon name=\"loopRightLine\" className=\"size-12\" />\n <Code as=\"span\" variant=\"label\" className=\"text-current\">\n {count}\n </Code>\n </span>\n </TooltipTrigger>\n <TooltipContent>{executionCountTooltip(executions)}</TooltipContent>\n </Tooltip>\n );\n}\n\nfunction CarriedOverBadge() {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <Badge variant=\"neutral\" size=\"2xs\">\n reused\n </Badge>\n </span>\n </TooltipTrigger>\n <TooltipContent>\n Carried over from a previous attempt; did not run in this attempt\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction JobLabel({label}: {label: string}) {\n const {ref: labelRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(label);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={labelRef} className=\"block min-w-0 truncate\">\n <Code as=\"span\" variant=\"label\" bold className=\"text-foreground-neutral-base\">\n {label}\n </Code>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{label}</TooltipContent> : null}\n </Tooltip>\n );\n}\n\nfunction executionCountAccessibleLabel(count: number): string {\n return `${count} ${count === 1 ? 'execution' : 'executions'}`;\n}\n\nfunction executionCountTooltip(executions: JobExecution[]): string {\n const counts = executionStatusCounts(executions);\n const parts = EXECUTION_STATUSES.map((status) =>\n counts[status] > 0 ? `${counts[status]} ${status}` : undefined,\n ).filter((part): part is string => part !== undefined);\n return parts.length > 0 ? parts.join(', ') : 'No executions';\n}\n\nconst EXECUTION_STATUSES = [\n 'pending',\n 'running',\n 'succeeded',\n 'failed',\n 'cancelled',\n] as const satisfies readonly JobExecutionStatus[];\n\nfunction executionStatusCounts(executions: JobExecution[]) {\n return executions.reduce(\n (counts, execution) => {\n counts[deriveJobExecutionDisplayStatus(execution)] += 1;\n return counts;\n },\n {pending: 0, running: 0, succeeded: 0, failed: 0, cancelled: 0},\n );\n}\n"],"names":["TriggerSourceIcon","Badge","useIsTextTruncated","Icon","useTimeTick","Tooltip","TooltipContent","TooltipTrigger","Code","cn","getWorkflowStatusVisual","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","deriveJobExecutionDisplayStatus","formatJobDurationAccessibleLabel","JobDurationLabel","TRIGGER_SIZE","TriggerNode","trigger","label","triggerDisplayLabel","tooltip","triggerLabel","asChild","button","type","aria-label","className","style","width","height","provider","triggerProvider","source","triggerSource","aria-hidden","span","JobNode","node","selected","onSelect","onKeyDown","onHoverStart","onHoverEnd","ref","status","execution","visual","accessibleLabel","displayName","displayDuration","undefined","executionCountVisible","executionCountAccessibleLabel","jobExecutions","length","carriedOver","filter","part","Boolean","join","aria-pressed","data-job-id","id","onClick","onPointerEnter","onPointerLeave","div","size","JobLabel","duration","ExecutionCountText","executions","CarriedOverBadge","count","name","as","variant","executionCountTooltip","labelRef","isTruncated","bold","counts","executionStatusCounts","parts","EXECUTION_STATUSES","map","reduce","pending","running","succeeded","failed","cancelled"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export type { StepExpandedContext, StepListEmptyState, StepListProps, } from './step-list.js';
2
2
  export { StepList } from './step-list.js';
3
+ export type { StepListEntryModel } from './step-list-model.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,YAAY,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/step-list/index.ts"],"sourcesContent":["export type {\n StepExpandedContext,\n StepListEmptyState,\n StepListProps,\n} from './step-list.js';\nexport {StepList} from './step-list.js';\n"],"names":["StepList"],"mappings":"AAKA,SAAQA,QAAQ,QAAO,iBAAiB"}
1
+ {"version":3,"sources":["../../../src/components/step-list/index.ts"],"sourcesContent":["export type {\n StepExpandedContext,\n StepListEmptyState,\n StepListProps,\n} from './step-list.js';\nexport {StepList} from './step-list.js';\nexport type {StepListEntryModel} from './step-list-model.js';\n"],"names":["StepList"],"mappings":"AAKA,SAAQA,QAAQ,QAAO,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"step-list-model.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,KAAK,GAAG,EACR,YAAY,EACZ,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,eAAe,EAAE,0BAA0B,GAAG,IAAI,CAAC;IACnD,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC,GAAG,aAAa,CAehB;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAElE;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAiB9D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAepE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD"}
1
+ {"version":3,"file":"step-list-model.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,KAAK,GAAG,EACR,YAAY,EACZ,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,eAAe,EAAE,0BAA0B,GAAG,IAAI,CAAC;IACnD,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC,GAAG,aAAa,CAehB;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAElE;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAoB9D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAepE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD"}
@@ -26,11 +26,14 @@ export function emptyJobExecutionForJob(job) {
26
26
  name: job.name ?? job.key,
27
27
  status: job.status === 'skipped' ? 'cancelled' : job.status,
28
28
  statusReason: job.statusReason,
29
+ runner: job.runner,
30
+ outputs: job.outputs,
29
31
  triggerEvents: [],
30
32
  queuedAt: null,
31
33
  startedAt: null,
32
34
  finishedAt: null,
33
35
  timedOutAt: null,
36
+ evaluationTrace: job.evaluationTrace,
34
37
  createdAt: job.createdAt,
35
38
  updatedAt: job.updatedAt,
36
39
  steps: []
@@ -100,6 +103,8 @@ function toStepEntries(step, carriedOverJob) {
100
103
  status: step.status,
101
104
  exitCode: null,
102
105
  output: null,
106
+ outputs: null,
107
+ response: null,
103
108
  error: null,
104
109
  gateResult: null,
105
110
  restartFeedback: null,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/step-list/step-list-model.ts"],"sourcesContent":["import {\n getWorkflowStatusVisual,\n type WorkflowStatusVisual,\n} from '#components/workflow-status/status-visuals.js';\nimport {\n defaultJobExecution,\n isWorkflowStatus as isKnownWorkflowStatus,\n type Job,\n JobExecution,\n type Step,\n type StepAttempt,\n type StepAttemptDisplayDuration,\n} from '#core/workflow-run.js';\n\nexport interface StepStatusVisual extends Omit<WorkflowStatusVisual, 'kind'> {\n kind: string;\n ripple: boolean;\n}\n\nexport interface StepAttemptModel extends StepAttempt {\n displayDuration: StepAttemptDisplayDuration | null;\n statusVisual: StepStatusVisual;\n carriedOver: boolean;\n}\n\nexport interface StepModel extends Omit<Step, 'attempts'> {\n index: number;\n label: string;\n attempts: StepAttemptModel[];\n}\n\nexport interface StepListEntryModel extends StepAttemptModel {\n step: StepModel;\n}\n\nexport interface StepListModel {\n jobId: string;\n jobName: string;\n jobExecutionId: string;\n stepCount: number;\n activeEntryId: string | undefined;\n entries: StepListEntryModel[];\n}\n\nexport function buildStepListModel({\n job,\n jobExecution,\n}: {\n job: Job;\n jobExecution?: JobExecution | undefined;\n}): StepListModel {\n const selectedJobExecution = jobExecution ?? defaultStepListJobExecution(job);\n const steps = [...selectedJobExecution.steps].sort(compareSteps).map(toStepModel);\n const entries = steps\n .flatMap((step) => toStepEntries(step, job.carriedOver))\n .sort(compareEntries);\n\n return {\n jobId: job.id,\n jobName: job.name ?? job.key,\n jobExecutionId: selectedJobExecution.id,\n stepCount: steps.length,\n activeEntryId: landingEntryId(entries),\n entries,\n };\n}\n\nexport function defaultStepListJobExecution(job: Job): JobExecution {\n return defaultJobExecution(job) ?? emptyJobExecutionForJob(job);\n}\n\nexport function emptyJobExecutionForJob(job: Job): JobExecution {\n return new JobExecution({\n id: `missing:${job.id}`,\n jobId: job.id,\n sequence: 1,\n name: job.name ?? job.key,\n status: job.status === 'skipped' ? 'cancelled' : job.status,\n statusReason: job.statusReason,\n triggerEvents: [],\n queuedAt: null,\n startedAt: null,\n finishedAt: null,\n timedOutAt: null,\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n steps: [],\n });\n}\n\nexport function getStepStatusVisual(status: string): StepStatusVisual {\n const normalized = normalizeStatus(status);\n\n if (isKnownWorkflowStatus(normalized)) {\n const visual = getWorkflowStatusVisual(normalized);\n return {...visual, ripple: normalized === 'running'};\n }\n\n return {\n kind: status,\n label: humanizeStatus(status),\n dot: 'neutral',\n badge: 'neutral',\n ripple: false,\n };\n}\n\nexport function humanizeStatus(status: string): string {\n const words = status.trim().replace(/[_-]+/g, ' ').replace(/\\s+/g, ' ').toLowerCase();\n if (!words) return 'Unknown';\n const firstLetter = words.at(0);\n return firstLetter === undefined ? 'Unknown' : firstLetter.toUpperCase() + words.slice(1);\n}\n\nfunction toStepModel(step: Step, index: number): StepModel {\n const attempts = [...step.attempts].sort(compareAttempts).map((attempt) => ({\n ...attempt,\n displayDuration: attempt.displayDuration,\n statusVisual: getStepStatusVisual(attempt.status),\n carriedOver: false,\n }));\n\n return {\n ...step,\n index: index + 1,\n label: stepLabel(step, index),\n attempts,\n };\n}\n\nfunction stepLabel(step: Step, index: number): string {\n const name = step.name.trim();\n if (name) return name;\n\n const key = step.key?.trim();\n if (key) return key;\n\n return `Step ${index + 1}`;\n}\n\nfunction toStepEntries(step: StepModel, carriedOverJob: boolean): StepListEntryModel[] {\n if (step.attempts.length > 0) {\n return step.attempts.map((attempt) => ({\n ...attempt,\n step,\n }));\n }\n\n if (!carriedOverJob) return [];\n\n return [\n {\n id: `carried-over:${step.id}`,\n stepId: step.id,\n jobExecutionId: step.jobExecutionId,\n attempt: step.currentAttempt,\n executionOrder: step.position,\n status: step.status,\n exitCode: null,\n output: null,\n error: null,\n gateResult: null,\n restartFeedback: null,\n startedAt: step.createdAt,\n finishedAt: null,\n displayDuration: null,\n statusVisual: getStepStatusVisual(step.status),\n carriedOver: true,\n step,\n },\n ];\n}\n\nfunction compareSteps(left: Step, right: Step): number {\n return (\n left.position - right.position ||\n (left.name ?? '').localeCompare(right.name ?? '') ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction compareAttempts(left: Step['attempts'][number], right: Step['attempts'][number]) {\n return left.attempt - right.attempt || left.id.localeCompare(right.id);\n}\n\nfunction compareEntries(left: StepListEntryModel, right: StepListEntryModel): number {\n return (\n left.executionOrder - right.executionOrder ||\n left.step.index - right.step.index ||\n left.attempt - right.attempt ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction landingEntryId(entries: readonly StepListEntryModel[]): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.statusVisual.kind === 'running') return entry.id;\n }\n return undefined;\n}\n\nfunction normalizeStatus(status: string): string {\n return status.trim().toLowerCase().replace(/-/g, '_');\n}\n"],"names":["getWorkflowStatusVisual","defaultJobExecution","isWorkflowStatus","isKnownWorkflowStatus","JobExecution","buildStepListModel","job","jobExecution","selectedJobExecution","defaultStepListJobExecution","steps","sort","compareSteps","map","toStepModel","entries","flatMap","step","toStepEntries","carriedOver","compareEntries","jobId","id","jobName","name","key","jobExecutionId","stepCount","length","activeEntryId","landingEntryId","emptyJobExecutionForJob","sequence","status","statusReason","triggerEvents","queuedAt","startedAt","finishedAt","timedOutAt","createdAt","updatedAt","getStepStatusVisual","normalized","normalizeStatus","visual","ripple","kind","label","humanizeStatus","dot","badge","words","trim","replace","toLowerCase","firstLetter","at","undefined","toUpperCase","slice","index","attempts","compareAttempts","attempt","displayDuration","statusVisual","stepLabel","carriedOverJob","stepId","currentAttempt","executionOrder","position","exitCode","output","error","gateResult","restartFeedback","left","right","localeCompare","entry"],"mappings":"AAAA,SACEA,uBAAuB,QAElB,gDAAgD;AACvD,SACEC,mBAAmB,EACnBC,oBAAoBC,qBAAqB,EAEzCC,YAAY,QAIP,wBAAwB;AAgC/B,OAAO,SAASC,mBAAmB,EACjCC,GAAG,EACHC,YAAY,EAIb;IACC,MAAMC,uBAAuBD,gBAAgBE,4BAA4BH;IACzE,MAAMI,QAAQ;WAAIF,qBAAqBE,KAAK;KAAC,CAACC,IAAI,CAACC,cAAcC,GAAG,CAACC;IACrE,MAAMC,UAAUL,MACbM,OAAO,CAAC,CAACC,OAASC,cAAcD,MAAMX,IAAIa,WAAW,GACrDR,IAAI,CAACS;IAER,OAAO;QACLC,OAAOf,IAAIgB,EAAE;QACbC,SAASjB,IAAIkB,IAAI,IAAIlB,IAAImB,GAAG;QAC5BC,gBAAgBlB,qBAAqBc,EAAE;QACvCK,WAAWjB,MAAMkB,MAAM;QACvBC,eAAeC,eAAef;QAC9BA;IACF;AACF;AAEA,OAAO,SAASN,4BAA4BH,GAAQ;IAClD,OAAOL,oBAAoBK,QAAQyB,wBAAwBzB;AAC7D;AAEA,OAAO,SAASyB,wBAAwBzB,GAAQ;IAC9C,OAAO,IAAIF,aAAa;QACtBkB,IAAI,CAAC,QAAQ,EAAEhB,IAAIgB,EAAE,EAAE;QACvBD,OAAOf,IAAIgB,EAAE;QACbU,UAAU;QACVR,MAAMlB,IAAIkB,IAAI,IAAIlB,IAAImB,GAAG;QACzBQ,QAAQ3B,IAAI2B,MAAM,KAAK,YAAY,cAAc3B,IAAI2B,MAAM;QAC3DC,cAAc5B,IAAI4B,YAAY;QAC9BC,eAAe,EAAE;QACjBC,UAAU;QACVC,WAAW;QACXC,YAAY;QACZC,YAAY;QACZC,WAAWlC,IAAIkC,SAAS;QACxBC,WAAWnC,IAAImC,SAAS;QACxB/B,OAAO,EAAE;IACX;AACF;AAEA,OAAO,SAASgC,oBAAoBT,MAAc;IAChD,MAAMU,aAAaC,gBAAgBX;IAEnC,IAAI9B,sBAAsBwC,aAAa;QACrC,MAAME,SAAS7C,wBAAwB2C;QACvC,OAAO;YAAC,GAAGE,MAAM;YAAEC,QAAQH,eAAe;QAAS;IACrD;IAEA,OAAO;QACLI,MAAMd;QACNe,OAAOC,eAAehB;QACtBiB,KAAK;QACLC,OAAO;QACPL,QAAQ;IACV;AACF;AAEA,OAAO,SAASG,eAAehB,MAAc;IAC3C,MAAMmB,QAAQnB,OAAOoB,IAAI,GAAGC,OAAO,CAAC,UAAU,KAAKA,OAAO,CAAC,QAAQ,KAAKC,WAAW;IACnF,IAAI,CAACH,OAAO,OAAO;IACnB,MAAMI,cAAcJ,MAAMK,EAAE,CAAC;IAC7B,OAAOD,gBAAgBE,YAAY,YAAYF,YAAYG,WAAW,KAAKP,MAAMQ,KAAK,CAAC;AACzF;AAEA,SAAS9C,YAAYG,IAAU,EAAE4C,KAAa;IAC5C,MAAMC,WAAW;WAAI7C,KAAK6C,QAAQ;KAAC,CAACnD,IAAI,CAACoD,iBAAiBlD,GAAG,CAAC,CAACmD,UAAa,CAAA;YAC1E,GAAGA,OAAO;YACVC,iBAAiBD,QAAQC,eAAe;YACxCC,cAAcxB,oBAAoBsB,QAAQ/B,MAAM;YAChDd,aAAa;QACf,CAAA;IAEA,OAAO;QACL,GAAGF,IAAI;QACP4C,OAAOA,QAAQ;QACfb,OAAOmB,UAAUlD,MAAM4C;QACvBC;IACF;AACF;AAEA,SAASK,UAAUlD,IAAU,EAAE4C,KAAa;IAC1C,MAAMrC,OAAOP,KAAKO,IAAI,CAAC6B,IAAI;IAC3B,IAAI7B,MAAM,OAAOA;IAEjB,MAAMC,MAAMR,KAAKQ,GAAG,EAAE4B;IACtB,IAAI5B,KAAK,OAAOA;IAEhB,OAAO,CAAC,KAAK,EAAEoC,QAAQ,GAAG;AAC5B;AAEA,SAAS3C,cAAcD,IAAe,EAAEmD,cAAuB;IAC7D,IAAInD,KAAK6C,QAAQ,CAAClC,MAAM,GAAG,GAAG;QAC5B,OAAOX,KAAK6C,QAAQ,CAACjD,GAAG,CAAC,CAACmD,UAAa,CAAA;gBACrC,GAAGA,OAAO;gBACV/C;YACF,CAAA;IACF;IAEA,IAAI,CAACmD,gBAAgB,OAAO,EAAE;IAE9B,OAAO;QACL;YACE9C,IAAI,CAAC,aAAa,EAAEL,KAAKK,EAAE,EAAE;YAC7B+C,QAAQpD,KAAKK,EAAE;YACfI,gBAAgBT,KAAKS,cAAc;YACnCsC,SAAS/C,KAAKqD,cAAc;YAC5BC,gBAAgBtD,KAAKuD,QAAQ;YAC7BvC,QAAQhB,KAAKgB,MAAM;YACnBwC,UAAU;YACVC,QAAQ;YACRC,OAAO;YACPC,YAAY;YACZC,iBAAiB;YACjBxC,WAAWpB,KAAKuB,SAAS;YACzBF,YAAY;YACZ2B,iBAAiB;YACjBC,cAAcxB,oBAAoBzB,KAAKgB,MAAM;YAC7Cd,aAAa;YACbF;QACF;KACD;AACH;AAEA,SAASL,aAAakE,IAAU,EAAEC,KAAW;IAC3C,OACED,KAAKN,QAAQ,GAAGO,MAAMP,QAAQ,IAC9B,AAACM,CAAAA,KAAKtD,IAAI,IAAI,EAAC,EAAGwD,aAAa,CAACD,MAAMvD,IAAI,IAAI,OAC9CsD,KAAKxD,EAAE,CAAC0D,aAAa,CAACD,MAAMzD,EAAE;AAElC;AAEA,SAASyC,gBAAgBe,IAA8B,EAAEC,KAA+B;IACtF,OAAOD,KAAKd,OAAO,GAAGe,MAAMf,OAAO,IAAIc,KAAKxD,EAAE,CAAC0D,aAAa,CAACD,MAAMzD,EAAE;AACvE;AAEA,SAASF,eAAe0D,IAAwB,EAAEC,KAAyB;IACzE,OACED,KAAKP,cAAc,GAAGQ,MAAMR,cAAc,IAC1CO,KAAK7D,IAAI,CAAC4C,KAAK,GAAGkB,MAAM9D,IAAI,CAAC4C,KAAK,IAClCiB,KAAKd,OAAO,GAAGe,MAAMf,OAAO,IAC5Bc,KAAKxD,EAAE,CAAC0D,aAAa,CAACD,MAAMzD,EAAE;AAElC;AAEA,SAASQ,eAAef,OAAsC;IAC5D,IAAK,IAAI8C,QAAQ9C,QAAQa,MAAM,GAAG,GAAGiC,SAAS,GAAGA,SAAS,EAAG;QAC3D,MAAMoB,QAAQlE,OAAO,CAAC8C,MAAM;QAC5B,IAAIoB,OAAOf,aAAanB,SAAS,WAAW,OAAOkC,MAAM3D,EAAE;IAC7D;IACA,OAAOoC;AACT;AAEA,SAASd,gBAAgBX,MAAc;IACrC,OAAOA,OAAOoB,IAAI,GAAGE,WAAW,GAAGD,OAAO,CAAC,MAAM;AACnD"}
1
+ {"version":3,"sources":["../../../src/components/step-list/step-list-model.ts"],"sourcesContent":["import {\n getWorkflowStatusVisual,\n type WorkflowStatusVisual,\n} from '#components/workflow-status/status-visuals.js';\nimport {\n defaultJobExecution,\n isWorkflowStatus as isKnownWorkflowStatus,\n type Job,\n JobExecution,\n type Step,\n type StepAttempt,\n type StepAttemptDisplayDuration,\n} from '#core/workflow-run.js';\n\nexport interface StepStatusVisual extends Omit<WorkflowStatusVisual, 'kind'> {\n kind: string;\n ripple: boolean;\n}\n\nexport interface StepAttemptModel extends StepAttempt {\n displayDuration: StepAttemptDisplayDuration | null;\n statusVisual: StepStatusVisual;\n carriedOver: boolean;\n}\n\nexport interface StepModel extends Omit<Step, 'attempts'> {\n index: number;\n label: string;\n attempts: StepAttemptModel[];\n}\n\nexport interface StepListEntryModel extends StepAttemptModel {\n step: StepModel;\n}\n\nexport interface StepListModel {\n jobId: string;\n jobName: string;\n jobExecutionId: string;\n stepCount: number;\n activeEntryId: string | undefined;\n entries: StepListEntryModel[];\n}\n\nexport function buildStepListModel({\n job,\n jobExecution,\n}: {\n job: Job;\n jobExecution?: JobExecution | undefined;\n}): StepListModel {\n const selectedJobExecution = jobExecution ?? defaultStepListJobExecution(job);\n const steps = [...selectedJobExecution.steps].sort(compareSteps).map(toStepModel);\n const entries = steps\n .flatMap((step) => toStepEntries(step, job.carriedOver))\n .sort(compareEntries);\n\n return {\n jobId: job.id,\n jobName: job.name ?? job.key,\n jobExecutionId: selectedJobExecution.id,\n stepCount: steps.length,\n activeEntryId: landingEntryId(entries),\n entries,\n };\n}\n\nexport function defaultStepListJobExecution(job: Job): JobExecution {\n return defaultJobExecution(job) ?? emptyJobExecutionForJob(job);\n}\n\nexport function emptyJobExecutionForJob(job: Job): JobExecution {\n return new JobExecution({\n id: `missing:${job.id}`,\n jobId: job.id,\n sequence: 1,\n name: job.name ?? job.key,\n status: job.status === 'skipped' ? 'cancelled' : job.status,\n statusReason: job.statusReason,\n runner: job.runner,\n outputs: job.outputs,\n triggerEvents: [],\n queuedAt: null,\n startedAt: null,\n finishedAt: null,\n timedOutAt: null,\n evaluationTrace: job.evaluationTrace,\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n steps: [],\n });\n}\n\nexport function getStepStatusVisual(status: string): StepStatusVisual {\n const normalized = normalizeStatus(status);\n\n if (isKnownWorkflowStatus(normalized)) {\n const visual = getWorkflowStatusVisual(normalized);\n return {...visual, ripple: normalized === 'running'};\n }\n\n return {\n kind: status,\n label: humanizeStatus(status),\n dot: 'neutral',\n badge: 'neutral',\n ripple: false,\n };\n}\n\nexport function humanizeStatus(status: string): string {\n const words = status.trim().replace(/[_-]+/g, ' ').replace(/\\s+/g, ' ').toLowerCase();\n if (!words) return 'Unknown';\n const firstLetter = words.at(0);\n return firstLetter === undefined ? 'Unknown' : firstLetter.toUpperCase() + words.slice(1);\n}\n\nfunction toStepModel(step: Step, index: number): StepModel {\n const attempts = [...step.attempts].sort(compareAttempts).map((attempt) => ({\n ...attempt,\n displayDuration: attempt.displayDuration,\n statusVisual: getStepStatusVisual(attempt.status),\n carriedOver: false,\n }));\n\n return {\n ...step,\n index: index + 1,\n label: stepLabel(step, index),\n attempts,\n };\n}\n\nfunction stepLabel(step: Step, index: number): string {\n const name = step.name.trim();\n if (name) return name;\n\n const key = step.key?.trim();\n if (key) return key;\n\n return `Step ${index + 1}`;\n}\n\nfunction toStepEntries(step: StepModel, carriedOverJob: boolean): StepListEntryModel[] {\n if (step.attempts.length > 0) {\n return step.attempts.map((attempt) => ({\n ...attempt,\n step,\n }));\n }\n\n if (!carriedOverJob) return [];\n\n return [\n {\n id: `carried-over:${step.id}`,\n stepId: step.id,\n jobExecutionId: step.jobExecutionId,\n attempt: step.currentAttempt,\n executionOrder: step.position,\n status: step.status,\n exitCode: null,\n output: null,\n outputs: null,\n response: null,\n error: null,\n gateResult: null,\n restartFeedback: null,\n startedAt: step.createdAt,\n finishedAt: null,\n displayDuration: null,\n statusVisual: getStepStatusVisual(step.status),\n carriedOver: true,\n step,\n },\n ];\n}\n\nfunction compareSteps(left: Step, right: Step): number {\n return (\n left.position - right.position ||\n (left.name ?? '').localeCompare(right.name ?? '') ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction compareAttempts(left: Step['attempts'][number], right: Step['attempts'][number]) {\n return left.attempt - right.attempt || left.id.localeCompare(right.id);\n}\n\nfunction compareEntries(left: StepListEntryModel, right: StepListEntryModel): number {\n return (\n left.executionOrder - right.executionOrder ||\n left.step.index - right.step.index ||\n left.attempt - right.attempt ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction landingEntryId(entries: readonly StepListEntryModel[]): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.statusVisual.kind === 'running') return entry.id;\n }\n return undefined;\n}\n\nfunction normalizeStatus(status: string): string {\n return status.trim().toLowerCase().replace(/-/g, '_');\n}\n"],"names":["getWorkflowStatusVisual","defaultJobExecution","isWorkflowStatus","isKnownWorkflowStatus","JobExecution","buildStepListModel","job","jobExecution","selectedJobExecution","defaultStepListJobExecution","steps","sort","compareSteps","map","toStepModel","entries","flatMap","step","toStepEntries","carriedOver","compareEntries","jobId","id","jobName","name","key","jobExecutionId","stepCount","length","activeEntryId","landingEntryId","emptyJobExecutionForJob","sequence","status","statusReason","runner","outputs","triggerEvents","queuedAt","startedAt","finishedAt","timedOutAt","evaluationTrace","createdAt","updatedAt","getStepStatusVisual","normalized","normalizeStatus","visual","ripple","kind","label","humanizeStatus","dot","badge","words","trim","replace","toLowerCase","firstLetter","at","undefined","toUpperCase","slice","index","attempts","compareAttempts","attempt","displayDuration","statusVisual","stepLabel","carriedOverJob","stepId","currentAttempt","executionOrder","position","exitCode","output","response","error","gateResult","restartFeedback","left","right","localeCompare","entry"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { type Job, type JobDisplayStatus, type JobExecution, type Step, type StepSourceLocation } from '#core/workflow-run.js';
3
+ import { type StepListEntryModel } from './step-list-model.js';
3
4
  export interface StepExpandedContext {
4
5
  step: Step;
5
6
  stepId: string;
@@ -23,11 +24,14 @@ export interface StepListProps {
23
24
  selectedAttemptId?: string | null | undefined;
24
25
  defaultSelectedAttemptId?: string | undefined;
25
26
  onSelectedAttemptChange?: ((attemptId: string | undefined) => void) | undefined;
27
+ inspectorOpenAttemptId?: string | null | undefined;
28
+ onInspectorOpenChange?: ((attemptId: string | null) => void) | undefined;
26
29
  autoSelectActiveAttempt?: boolean | undefined;
27
30
  emptyState?: StepListEmptyState | undefined;
28
31
  renderExpandedStep?: ((context: StepExpandedContext) => ReactNode) | undefined;
32
+ renderInspector?: ((entry: StepListEntryModel) => ReactNode) | undefined;
29
33
  showHeader?: boolean | undefined;
30
34
  className?: string | undefined;
31
35
  }
32
- export declare function StepList({ job, jobExecution, selectedAttemptId, defaultSelectedAttemptId, onSelectedAttemptChange, autoSelectActiveAttempt, emptyState, renderExpandedStep, showHeader, className, }: StepListProps): import("react").JSX.Element;
36
+ export declare function StepList({ job, jobExecution, selectedAttemptId, defaultSelectedAttemptId, onSelectedAttemptChange, inspectorOpenAttemptId, onInspectorOpenChange, autoSelectActiveAttempt, emptyState, renderExpandedStep, renderInspector, showHeader, className, }: StepListProps): import("react").JSX.Element;
33
37
  //# sourceMappingURL=step-list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"step-list.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAW/B,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,uBAAuB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAChF,uBAAuB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C,UAAU,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC5C,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC/E,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,uBAA+B,EAC/B,UAAU,EACV,kBAAkB,EAClB,UAAiB,EACjB,SAAS,GACV,EAAE,aAAa,+BAqBf"}
1
+ {"version":3,"file":"step-list.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAKL,KAAK,kBAAkB,EAExB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,uBAAuB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAChF,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnD,qBAAqB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzE,uBAAuB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C,UAAU,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC5C,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC/E,eAAe,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IACzE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,sBAA6B,EAC7B,qBAAqB,EACrB,uBAA+B,EAC/B,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,UAAiB,EACjB,SAAS,GACV,EAAE,aAAa,+BAwBf"}