@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,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 81 files with swc (667.96ms)
2
+ Successfully compiled: 86 files with swc (708.85ms)
@@ -1 +1,2 @@
1
1
  $ shipfox-tsc-check
2
+ context canceled
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @shipfox/client-workflows
2
2
 
3
+ ## 17.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4b0731e: Adds workflow troubleshooting details, evaluation traces, failure annotations, runner context, step output metadata, and lazy paginated annotation summaries.
8
+
9
+ ### Patch Changes
10
+
11
+ - 7b2436c: Migrates the workflow client surfaces to semantic spacing roles.
12
+ - Updated dependencies [4b0731e]
13
+ - @shipfox/api-workflows-dto@12.3.0
14
+ - @shipfox/annotations-dto@12.3.0
15
+ - @shipfox/client-logs@17.0.0
16
+ - @shipfox/react-ui@1.2.0
17
+ - @shipfox/client-ui@17.0.0
18
+ - @shipfox/client-projects@17.0.0
19
+ - @shipfox/client-shell@17.0.0
20
+ - @shipfox/client-triggers@17.0.0
21
+ - @shipfox/api-definitions-dto@12.3.0
22
+
3
23
  ## 16.0.0
4
24
 
5
25
  ### Minor Changes
@@ -84,7 +84,7 @@ export function Identifier({ display, value, label = 'identifier' }) {
84
84
  onClick: ()=>{
85
85
  void handleCopy();
86
86
  },
87
- className: "inline-flex h-20 min-w-0 shrink-0 items-center gap-4 rounded-4 px-2 text-foreground-neutral-muted outline-none transition-colors hover:bg-background-components-hover hover:text-foreground-neutral-base focus-visible:shadow-border-interactive-with-active",
87
+ className: "inline-flex h-20 min-w-0 shrink-0 items-center gap-tight rounded-4 px-[var(--pad-menu-surface)] text-foreground-neutral-muted outline-none transition-colors hover:bg-background-components-hover hover:text-foreground-neutral-base focus-visible:shadow-border-interactive-with-active",
88
88
  children: [
89
89
  /*#__PURE__*/ _jsx(Icon, {
90
90
  name: "copy",
@@ -136,7 +136,7 @@ function CopyFeedbackPortal({ anchor, children, kind }) {
136
136
  top: placement === 'top' ? anchor.top : anchor.bottom,
137
137
  transform: placement === 'top' ? `translate(-50%, calc(-100% - ${COPY_FEEDBACK_OFFSET_PX}px))` : `translate(-50%, ${COPY_FEEDBACK_OFFSET_PX}px)`
138
138
  },
139
- className: cn('pointer-events-none fixed z-50 whitespace-nowrap rounded-8 bg-background-components-base px-8 py-4 text-xs font-display font-medium leading-20 shadow-tooltip', kind === 'failed' ? 'text-foreground-highlight-error' : 'text-foreground-neutral-base'),
139
+ className: cn('pointer-events-none fixed z-50 whitespace-nowrap rounded-8 bg-background-components-base px-tight py-[4px] text-xs font-display font-medium leading-20 shadow-tooltip', kind === 'failed' ? 'text-foreground-highlight-error' : 'text-foreground-neutral-base'),
140
140
  children: children
141
141
  }), document.body);
142
142
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/identifier/identifier.tsx"],"sourcesContent":["import {useCopyToClipboard} from '@shipfox/react-ui/hooks';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react';\nimport {createPortal} from 'react-dom';\n\nconst COPY_FEEDBACK_OFFSET_PX = 8;\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\ninterface FeedbackAnchor {\n bottom: number;\n left: number;\n top: number;\n}\n\nexport function Identifier({\n display,\n value,\n label = 'identifier',\n}: {\n display: string;\n value: string;\n label?: string | undefined;\n}) {\n const [copyState, setCopyState] = useState<CopyState>('idle');\n const [tooltipOpen, setTooltipOpen] = useState(false);\n const [feedbackAnchor, setFeedbackAnchor] = useState<FeedbackAnchor | null>(null);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const {copy} = useCopyToClipboard({\n text: value,\n onCopy: () => {\n setTemporaryCopyState('copied', 2500);\n },\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n const resetCopyFeedback = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n setCopyState('idle');\n setTooltipOpen(false);\n setFeedbackAnchor(null);\n }, []);\n\n useEffect(() => {\n if (copyState === 'idle') return;\n\n window.addEventListener('scroll', resetCopyFeedback, true);\n window.addEventListener('resize', resetCopyFeedback);\n\n return () => {\n window.removeEventListener('scroll', resetCopyFeedback, true);\n window.removeEventListener('resize', resetCopyFeedback);\n };\n }, [copyState, resetCopyFeedback]);\n\n function setTemporaryCopyState(state: Exclude<CopyState, 'idle'>, timeout: number) {\n const rect = buttonRef.current?.getBoundingClientRect();\n setCopyState(state);\n setTooltipOpen(false);\n setFeedbackAnchor(\n rect\n ? {\n left: rect.left + rect.width / 2,\n top: rect.top,\n bottom: rect.bottom,\n }\n : null,\n );\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(resetCopyFeedback, timeout);\n }\n\n async function handleCopy() {\n try {\n await copy();\n } catch {\n setTemporaryCopyState('failed', 2500);\n }\n }\n\n const ariaLabel =\n copyState === 'copied'\n ? `Copied ${label} ${value}`\n : copyState === 'failed'\n ? `Could not copy ${label} ${value}`\n : `Copy ${label} ${value}`;\n\n const feedback =\n copyState === 'copied'\n ? {kind: copyState, label: 'Copied'}\n : copyState === 'failed'\n ? {kind: copyState, label: 'Could not copy'}\n : null;\n\n return (\n <>\n <Tooltip open={copyState === 'idle' ? tooltipOpen : false} onOpenChange={setTooltipOpen}>\n <TooltipTrigger asChild>\n <button\n ref={buttonRef}\n type=\"button\"\n aria-label={ariaLabel}\n onClick={() => {\n void handleCopy();\n }}\n className=\"inline-flex h-20 min-w-0 shrink-0 items-center gap-4 rounded-4 px-2 text-foreground-neutral-muted outline-none transition-colors hover:bg-background-components-hover hover:text-foreground-neutral-base focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name=\"copy\" aria-hidden=\"true\" className=\"size-12 shrink-0\" />\n <Code as=\"span\" variant=\"label\" className=\"truncate\">\n {display}\n </Code>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Code as=\"span\" variant=\"label\" className=\"block max-w-[360px] truncate\">\n {value}\n </Code>\n </TooltipContent>\n </Tooltip>\n {feedback && feedbackAnchor ? (\n <CopyFeedbackPortal anchor={feedbackAnchor} kind={feedback.kind}>\n {feedback.label}\n </CopyFeedbackPortal>\n ) : null}\n </>\n );\n}\n\nfunction CopyFeedbackPortal({\n anchor,\n children,\n kind,\n}: {\n anchor: FeedbackAnchor;\n children: string;\n kind: Exclude<CopyState, 'idle'>;\n}) {\n const feedbackRef = useRef<HTMLSpanElement | null>(null);\n const [placement, setPlacement] = useState<'top' | 'bottom'>('bottom');\n\n useLayoutEffect(() => {\n const height = feedbackRef.current?.offsetHeight ?? 0;\n setPlacement(anchor.top >= height + COPY_FEEDBACK_OFFSET_PX ? 'top' : 'bottom');\n }, [anchor.top]);\n\n if (typeof document === 'undefined') return null;\n\n return createPortal(\n <span\n ref={feedbackRef}\n role=\"status\"\n style={{\n left: anchor.left,\n top: placement === 'top' ? anchor.top : anchor.bottom,\n transform:\n placement === 'top'\n ? `translate(-50%, calc(-100% - ${COPY_FEEDBACK_OFFSET_PX}px))`\n : `translate(-50%, ${COPY_FEEDBACK_OFFSET_PX}px)`,\n }}\n className={cn(\n 'pointer-events-none fixed z-50 whitespace-nowrap rounded-8 bg-background-components-base px-8 py-4 text-xs font-display font-medium leading-20 shadow-tooltip',\n kind === 'failed' ? 'text-foreground-highlight-error' : 'text-foreground-neutral-base',\n )}\n >\n {children}\n </span>,\n document.body,\n );\n}\n"],"names":["useCopyToClipboard","Icon","Tooltip","TooltipContent","TooltipTrigger","Code","cn","useCallback","useEffect","useLayoutEffect","useRef","useState","createPortal","COPY_FEEDBACK_OFFSET_PX","Identifier","display","value","label","copyState","setCopyState","tooltipOpen","setTooltipOpen","feedbackAnchor","setFeedbackAnchor","buttonRef","timeoutRef","undefined","copy","text","onCopy","setTemporaryCopyState","current","clearTimeout","resetCopyFeedback","window","addEventListener","removeEventListener","state","timeout","rect","getBoundingClientRect","left","width","top","bottom","setTimeout","handleCopy","ariaLabel","feedback","kind","open","onOpenChange","asChild","button","ref","type","aria-label","onClick","className","name","aria-hidden","as","variant","CopyFeedbackPortal","anchor","children","feedbackRef","placement","setPlacement","height","offsetHeight","document","span","role","style","transform","body"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/identifier/identifier.tsx"],"sourcesContent":["import {useCopyToClipboard} from '@shipfox/react-ui/hooks';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react';\nimport {createPortal} from 'react-dom';\n\nconst COPY_FEEDBACK_OFFSET_PX = 8;\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\ninterface FeedbackAnchor {\n bottom: number;\n left: number;\n top: number;\n}\n\nexport function Identifier({\n display,\n value,\n label = 'identifier',\n}: {\n display: string;\n value: string;\n label?: string | undefined;\n}) {\n const [copyState, setCopyState] = useState<CopyState>('idle');\n const [tooltipOpen, setTooltipOpen] = useState(false);\n const [feedbackAnchor, setFeedbackAnchor] = useState<FeedbackAnchor | null>(null);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const {copy} = useCopyToClipboard({\n text: value,\n onCopy: () => {\n setTemporaryCopyState('copied', 2500);\n },\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n const resetCopyFeedback = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n setCopyState('idle');\n setTooltipOpen(false);\n setFeedbackAnchor(null);\n }, []);\n\n useEffect(() => {\n if (copyState === 'idle') return;\n\n window.addEventListener('scroll', resetCopyFeedback, true);\n window.addEventListener('resize', resetCopyFeedback);\n\n return () => {\n window.removeEventListener('scroll', resetCopyFeedback, true);\n window.removeEventListener('resize', resetCopyFeedback);\n };\n }, [copyState, resetCopyFeedback]);\n\n function setTemporaryCopyState(state: Exclude<CopyState, 'idle'>, timeout: number) {\n const rect = buttonRef.current?.getBoundingClientRect();\n setCopyState(state);\n setTooltipOpen(false);\n setFeedbackAnchor(\n rect\n ? {\n left: rect.left + rect.width / 2,\n top: rect.top,\n bottom: rect.bottom,\n }\n : null,\n );\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(resetCopyFeedback, timeout);\n }\n\n async function handleCopy() {\n try {\n await copy();\n } catch {\n setTemporaryCopyState('failed', 2500);\n }\n }\n\n const ariaLabel =\n copyState === 'copied'\n ? `Copied ${label} ${value}`\n : copyState === 'failed'\n ? `Could not copy ${label} ${value}`\n : `Copy ${label} ${value}`;\n\n const feedback =\n copyState === 'copied'\n ? {kind: copyState, label: 'Copied'}\n : copyState === 'failed'\n ? {kind: copyState, label: 'Could not copy'}\n : null;\n\n return (\n <>\n <Tooltip open={copyState === 'idle' ? tooltipOpen : false} onOpenChange={setTooltipOpen}>\n <TooltipTrigger asChild>\n <button\n ref={buttonRef}\n type=\"button\"\n aria-label={ariaLabel}\n onClick={() => {\n void handleCopy();\n }}\n className=\"inline-flex h-20 min-w-0 shrink-0 items-center gap-tight rounded-4 px-[var(--pad-menu-surface)] text-foreground-neutral-muted outline-none transition-colors hover:bg-background-components-hover hover:text-foreground-neutral-base focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name=\"copy\" aria-hidden=\"true\" className=\"size-12 shrink-0\" />\n <Code as=\"span\" variant=\"label\" className=\"truncate\">\n {display}\n </Code>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Code as=\"span\" variant=\"label\" className=\"block max-w-[360px] truncate\">\n {value}\n </Code>\n </TooltipContent>\n </Tooltip>\n {feedback && feedbackAnchor ? (\n <CopyFeedbackPortal anchor={feedbackAnchor} kind={feedback.kind}>\n {feedback.label}\n </CopyFeedbackPortal>\n ) : null}\n </>\n );\n}\n\nfunction CopyFeedbackPortal({\n anchor,\n children,\n kind,\n}: {\n anchor: FeedbackAnchor;\n children: string;\n kind: Exclude<CopyState, 'idle'>;\n}) {\n const feedbackRef = useRef<HTMLSpanElement | null>(null);\n const [placement, setPlacement] = useState<'top' | 'bottom'>('bottom');\n\n useLayoutEffect(() => {\n const height = feedbackRef.current?.offsetHeight ?? 0;\n setPlacement(anchor.top >= height + COPY_FEEDBACK_OFFSET_PX ? 'top' : 'bottom');\n }, [anchor.top]);\n\n if (typeof document === 'undefined') return null;\n\n return createPortal(\n <span\n ref={feedbackRef}\n role=\"status\"\n style={{\n left: anchor.left,\n top: placement === 'top' ? anchor.top : anchor.bottom,\n transform:\n placement === 'top'\n ? `translate(-50%, calc(-100% - ${COPY_FEEDBACK_OFFSET_PX}px))`\n : `translate(-50%, ${COPY_FEEDBACK_OFFSET_PX}px)`,\n }}\n className={cn(\n 'pointer-events-none fixed z-50 whitespace-nowrap rounded-8 bg-background-components-base px-tight py-[4px] text-xs font-display font-medium leading-20 shadow-tooltip',\n kind === 'failed' ? 'text-foreground-highlight-error' : 'text-foreground-neutral-base',\n )}\n >\n {children}\n </span>,\n document.body,\n );\n}\n"],"names":["useCopyToClipboard","Icon","Tooltip","TooltipContent","TooltipTrigger","Code","cn","useCallback","useEffect","useLayoutEffect","useRef","useState","createPortal","COPY_FEEDBACK_OFFSET_PX","Identifier","display","value","label","copyState","setCopyState","tooltipOpen","setTooltipOpen","feedbackAnchor","setFeedbackAnchor","buttonRef","timeoutRef","undefined","copy","text","onCopy","setTemporaryCopyState","current","clearTimeout","resetCopyFeedback","window","addEventListener","removeEventListener","state","timeout","rect","getBoundingClientRect","left","width","top","bottom","setTimeout","handleCopy","ariaLabel","feedback","kind","open","onOpenChange","asChild","button","ref","type","aria-label","onClick","className","name","aria-hidden","as","variant","CopyFeedbackPortal","anchor","children","feedbackRef","placement","setPlacement","height","offsetHeight","document","span","role","style","transform","body"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-config-failure-callout.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/agent-config-failure-callout.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,eAAe,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAEtE,wBAAgB,yBAAyB,CAAC,EACxC,aAAa,EACb,MAAM,EACN,KAAK,GACN,EAAE;IACD,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB,+BAoBA"}
1
+ {"version":3,"file":"agent-config-failure-callout.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/agent-config-failure-callout.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,eAAe,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAEtE,wBAAgB,yBAAyB,CAAC,EACxC,aAAa,EACb,MAAM,EACN,KAAK,GACN,EAAE;IACD,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB,+BAwBA"}
@@ -7,7 +7,7 @@ export function AgentConfigFailureCallout({ workspaceSlug, config, error }) {
7
7
  return /*#__PURE__*/ _jsx(Alert, {
8
8
  variant: "warning",
9
9
  animated: false,
10
- className: "px-10 py-8",
10
+ className: "rounded-none border-x-0 border-t-0 border-b border-tag-warning-border bg-transparent px-0 py-row",
11
11
  children: /*#__PURE__*/ _jsxs(AlertContent, {
12
12
  children: [
13
13
  /*#__PURE__*/ _jsx(AlertTitle, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-detail/agent-config-failure-callout.tsx"],"sourcesContent":["import {\n Alert,\n AlertActions,\n AlertContent,\n AlertDescription,\n AlertTitle,\n} from '@shipfox/react-ui/alert';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Link} from '@tanstack/react-router';\nimport type {AgentStepConfig, StepError} from '#core/workflow-run.js';\n\nexport function AgentConfigFailureCallout({\n workspaceSlug,\n config,\n error,\n}: {\n workspaceSlug?: string | undefined;\n config: AgentStepConfig | null;\n error: StepError | null;\n}) {\n const copy = agentConfigFailureCopy(config, error);\n\n return (\n <Alert variant=\"warning\" animated={false} className=\"px-10 py-8\">\n <AlertContent>\n <AlertTitle>{copy.title}</AlertTitle>\n <AlertDescription>{copy.description}</AlertDescription>\n {copy.showProviderCta && workspaceSlug ? (\n <AlertActions>\n <Button asChild size=\"2xs\" variant=\"secondary\" iconRight=\"chevronRight\">\n <Link to=\"/w/$workspaceSlug/settings/agents\" params={{workspaceSlug}}>\n Configure Agents\n </Link>\n </Button>\n </AlertActions>\n ) : null}\n </AlertContent>\n </Alert>\n );\n}\n\nfunction agentConfigFailureCopy(\n config: AgentStepConfig | null,\n error: StepError | null,\n): {title: string; description: string; showProviderCta: boolean} {\n const provider = configValue(config?.provider, 'the selected provider');\n const model = configValue(config?.model, 'the selected model');\n\n switch (error?.agentConfigIssue) {\n case 'provider_not_configured':\n return {\n title: `Configure credentials for ${provider}`,\n description: `This step uses ${provider}, but no workspace credentials are configured for that model provider. Configure ${provider} in Agents, then re-run the workflow.`,\n showProviderCta: true,\n };\n case 'credentials_invalid':\n return {\n title: `Update credentials for ${provider}`,\n description: `This step uses ${provider}, but the saved credentials could not be used. Reconfigure ${provider} in Agents, then re-run the workflow.`,\n showProviderCta: true,\n };\n case 'provider_unsupported':\n return {\n title: 'Choose a supported model provider',\n description: `This step references ${provider}, which is not available to the agent runner. Update the workflow to use a supported provider, then re-run it.`,\n showProviderCta: false,\n };\n case 'model_unavailable':\n return {\n title: 'Choose an available model',\n description: `This step uses ${model} with ${provider}, but that model is not available for the provider. Update the model or provider in the workflow, then re-run it.`,\n showProviderCta: false,\n };\n case 'step_config_invalid':\n return {\n title: \"Fix this step's agent settings\",\n description:\n 'Make sure the step has a prompt, provider, model, and thinking value, then re-run the workflow.',\n showProviderCta: false,\n };\n case undefined:\n return {\n title: \"We couldn't load the agent configuration for this step\",\n description:\n 'Make sure the step has a prompt, provider, model, and thinking value. Then configure credentials for the model provider in Agents and re-run the workflow.',\n showProviderCta: true,\n };\n }\n}\n\nfunction configValue(value: string | null | undefined, fallback: string): string {\n return value ?? fallback;\n}\n"],"names":["Alert","AlertActions","AlertContent","AlertDescription","AlertTitle","Button","Link","AgentConfigFailureCallout","workspaceSlug","config","error","copy","agentConfigFailureCopy","variant","animated","className","title","description","showProviderCta","asChild","size","iconRight","to","params","provider","configValue","model","agentConfigIssue","undefined","value","fallback"],"mappings":";AAAA,SACEA,KAAK,EACLC,YAAY,EACZC,YAAY,EACZC,gBAAgB,EAChBC,UAAU,QACL,0BAA0B;AACjC,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,IAAI,QAAO,yBAAyB;AAG5C,OAAO,SAASC,0BAA0B,EACxCC,aAAa,EACbC,MAAM,EACNC,KAAK,EAKN;IACC,MAAMC,OAAOC,uBAAuBH,QAAQC;IAE5C,qBACE,KAACV;QAAMa,SAAQ;QAAUC,UAAU;QAAOC,WAAU;kBAClD,cAAA,MAACb;;8BACC,KAACE;8BAAYO,KAAKK,KAAK;;8BACvB,KAACb;8BAAkBQ,KAAKM,WAAW;;gBAClCN,KAAKO,eAAe,IAAIV,8BACvB,KAACP;8BACC,cAAA,KAACI;wBAAOc,OAAO;wBAACC,MAAK;wBAAMP,SAAQ;wBAAYQ,WAAU;kCACvD,cAAA,KAACf;4BAAKgB,IAAG;4BAAoCC,QAAQ;gCAACf;4BAAa;sCAAG;;;qBAKxE;;;;AAIZ;AAEA,SAASI,uBACPH,MAA8B,EAC9BC,KAAuB;IAEvB,MAAMc,WAAWC,YAAYhB,QAAQe,UAAU;IAC/C,MAAME,QAAQD,YAAYhB,QAAQiB,OAAO;IAEzC,OAAQhB,OAAOiB;QACb,KAAK;YACH,OAAO;gBACLX,OAAO,CAAC,0BAA0B,EAAEQ,UAAU;gBAC9CP,aAAa,CAAC,eAAe,EAAEO,SAAS,iFAAiF,EAAEA,SAAS,qCAAqC,CAAC;gBAC1KN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO,CAAC,uBAAuB,EAAEQ,UAAU;gBAC3CP,aAAa,CAAC,eAAe,EAAEO,SAAS,2DAA2D,EAAEA,SAAS,qCAAqC,CAAC;gBACpJN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aAAa,CAAC,qBAAqB,EAAEO,SAAS,8GAA8G,CAAC;gBAC7JN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aAAa,CAAC,eAAe,EAAES,MAAM,MAAM,EAAEF,SAAS,iHAAiH,CAAC;gBACxKN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aACE;gBACFC,iBAAiB;YACnB;QACF,KAAKU;YACH,OAAO;gBACLZ,OAAO;gBACPC,aACE;gBACFC,iBAAiB;YACnB;IACJ;AACF;AAEA,SAASO,YAAYI,KAAgC,EAAEC,QAAgB;IACrE,OAAOD,SAASC;AAClB"}
1
+ {"version":3,"sources":["../../../src/components/job-detail/agent-config-failure-callout.tsx"],"sourcesContent":["import {\n Alert,\n AlertActions,\n AlertContent,\n AlertDescription,\n AlertTitle,\n} from '@shipfox/react-ui/alert';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Link} from '@tanstack/react-router';\nimport type {AgentStepConfig, StepError} from '#core/workflow-run.js';\n\nexport function AgentConfigFailureCallout({\n workspaceSlug,\n config,\n error,\n}: {\n workspaceSlug?: string | undefined;\n config: AgentStepConfig | null;\n error: StepError | null;\n}) {\n const copy = agentConfigFailureCopy(config, error);\n\n return (\n <Alert\n variant=\"warning\"\n animated={false}\n className=\"rounded-none border-x-0 border-t-0 border-b border-tag-warning-border bg-transparent px-0 py-row\"\n >\n <AlertContent>\n <AlertTitle>{copy.title}</AlertTitle>\n <AlertDescription>{copy.description}</AlertDescription>\n {copy.showProviderCta && workspaceSlug ? (\n <AlertActions>\n <Button asChild size=\"2xs\" variant=\"secondary\" iconRight=\"chevronRight\">\n <Link to=\"/w/$workspaceSlug/settings/agents\" params={{workspaceSlug}}>\n Configure Agents\n </Link>\n </Button>\n </AlertActions>\n ) : null}\n </AlertContent>\n </Alert>\n );\n}\n\nfunction agentConfigFailureCopy(\n config: AgentStepConfig | null,\n error: StepError | null,\n): {title: string; description: string; showProviderCta: boolean} {\n const provider = configValue(config?.provider, 'the selected provider');\n const model = configValue(config?.model, 'the selected model');\n\n switch (error?.agentConfigIssue) {\n case 'provider_not_configured':\n return {\n title: `Configure credentials for ${provider}`,\n description: `This step uses ${provider}, but no workspace credentials are configured for that model provider. Configure ${provider} in Agents, then re-run the workflow.`,\n showProviderCta: true,\n };\n case 'credentials_invalid':\n return {\n title: `Update credentials for ${provider}`,\n description: `This step uses ${provider}, but the saved credentials could not be used. Reconfigure ${provider} in Agents, then re-run the workflow.`,\n showProviderCta: true,\n };\n case 'provider_unsupported':\n return {\n title: 'Choose a supported model provider',\n description: `This step references ${provider}, which is not available to the agent runner. Update the workflow to use a supported provider, then re-run it.`,\n showProviderCta: false,\n };\n case 'model_unavailable':\n return {\n title: 'Choose an available model',\n description: `This step uses ${model} with ${provider}, but that model is not available for the provider. Update the model or provider in the workflow, then re-run it.`,\n showProviderCta: false,\n };\n case 'step_config_invalid':\n return {\n title: \"Fix this step's agent settings\",\n description:\n 'Make sure the step has a prompt, provider, model, and thinking value, then re-run the workflow.',\n showProviderCta: false,\n };\n case undefined:\n return {\n title: \"We couldn't load the agent configuration for this step\",\n description:\n 'Make sure the step has a prompt, provider, model, and thinking value. Then configure credentials for the model provider in Agents and re-run the workflow.',\n showProviderCta: true,\n };\n }\n}\n\nfunction configValue(value: string | null | undefined, fallback: string): string {\n return value ?? fallback;\n}\n"],"names":["Alert","AlertActions","AlertContent","AlertDescription","AlertTitle","Button","Link","AgentConfigFailureCallout","workspaceSlug","config","error","copy","agentConfigFailureCopy","variant","animated","className","title","description","showProviderCta","asChild","size","iconRight","to","params","provider","configValue","model","agentConfigIssue","undefined","value","fallback"],"mappings":";AAAA,SACEA,KAAK,EACLC,YAAY,EACZC,YAAY,EACZC,gBAAgB,EAChBC,UAAU,QACL,0BAA0B;AACjC,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,IAAI,QAAO,yBAAyB;AAG5C,OAAO,SAASC,0BAA0B,EACxCC,aAAa,EACbC,MAAM,EACNC,KAAK,EAKN;IACC,MAAMC,OAAOC,uBAAuBH,QAAQC;IAE5C,qBACE,KAACV;QACCa,SAAQ;QACRC,UAAU;QACVC,WAAU;kBAEV,cAAA,MAACb;;8BACC,KAACE;8BAAYO,KAAKK,KAAK;;8BACvB,KAACb;8BAAkBQ,KAAKM,WAAW;;gBAClCN,KAAKO,eAAe,IAAIV,8BACvB,KAACP;8BACC,cAAA,KAACI;wBAAOc,OAAO;wBAACC,MAAK;wBAAMP,SAAQ;wBAAYQ,WAAU;kCACvD,cAAA,KAACf;4BAAKgB,IAAG;4BAAoCC,QAAQ;gCAACf;4BAAa;sCAAG;;;qBAKxE;;;;AAIZ;AAEA,SAASI,uBACPH,MAA8B,EAC9BC,KAAuB;IAEvB,MAAMc,WAAWC,YAAYhB,QAAQe,UAAU;IAC/C,MAAME,QAAQD,YAAYhB,QAAQiB,OAAO;IAEzC,OAAQhB,OAAOiB;QACb,KAAK;YACH,OAAO;gBACLX,OAAO,CAAC,0BAA0B,EAAEQ,UAAU;gBAC9CP,aAAa,CAAC,eAAe,EAAEO,SAAS,iFAAiF,EAAEA,SAAS,qCAAqC,CAAC;gBAC1KN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO,CAAC,uBAAuB,EAAEQ,UAAU;gBAC3CP,aAAa,CAAC,eAAe,EAAEO,SAAS,2DAA2D,EAAEA,SAAS,qCAAqC,CAAC;gBACpJN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aAAa,CAAC,qBAAqB,EAAEO,SAAS,8GAA8G,CAAC;gBAC7JN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aAAa,CAAC,eAAe,EAAES,MAAM,MAAM,EAAEF,SAAS,iHAAiH,CAAC;gBACxKN,iBAAiB;YACnB;QACF,KAAK;YACH,OAAO;gBACLF,OAAO;gBACPC,aACE;gBACFC,iBAAiB;YACnB;QACF,KAAKU;YACH,OAAO;gBACLZ,OAAO;gBACPC,aACE;gBACFC,iBAAiB;YACnB;IACJ;AACF;AAEA,SAASO,YAAYI,KAAgC,EAAEC,QAAgB;IACrE,OAAOD,SAASC;AAClB"}
@@ -0,0 +1,6 @@
1
+ import type { Job, JobExecution } from '#core/workflow-run.js';
2
+ export declare function JobContextPanel({ job, execution }: {
3
+ job: Job;
4
+ execution: JobExecution;
5
+ }): import("react").JSX.Element | null;
6
+ //# sourceMappingURL=job-context-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-context-panel.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-context-panel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAuB,GAAG,EAAE,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAKnF,wBAAgB,eAAe,CAAC,EAAC,GAAG,EAAE,SAAS,EAAC,EAAE;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAC,sCA4BpF"}
@@ -0,0 +1,224 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '@shipfox/react-ui/icon';
3
+ import { Sheet, SheetBody, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@shipfox/react-ui/sheet';
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
5
+ import { Code, Text } from '@shipfox/react-ui/typography';
6
+ import { useState } from 'react';
7
+ import { formatJobExecutionTime } from './job-execution-time-text.js';
8
+ import { JsonCode } from './json-code.js';
9
+ import { EvaluationTrace } from './step-troubleshooting.js';
10
+ export function JobContextPanel({ job, execution }) {
11
+ const runner = execution.runner?.length ? execution.runner : job.runner;
12
+ const outputs = execution.outputs ?? job.outputs;
13
+ const trace = [
14
+ ...job.evaluationTrace ?? [],
15
+ ...execution.evaluationTrace ?? []
16
+ ];
17
+ const statusReason = execution.statusReason ?? job.statusReason;
18
+ const hasTiming = Boolean(execution.queueTime || execution.runTime);
19
+ const hasContext = Boolean(runner?.length || outputs || execution.triggerEvents.length || job.success || statusReason || trace?.length || hasTiming);
20
+ if (!hasContext) return null;
21
+ return /*#__PURE__*/ _jsx(JobContextSheet, {
22
+ job: job,
23
+ execution: execution,
24
+ runner: runner,
25
+ outputs: outputs,
26
+ trace: trace,
27
+ statusReason: statusReason
28
+ });
29
+ }
30
+ function JobContextSheet({ job, execution, runner, outputs, trace, statusReason }) {
31
+ const [open, setOpen] = useState(false);
32
+ const { conditionTrace, executionNameTrace } = splitJobEvaluationTrace(trace);
33
+ return /*#__PURE__*/ _jsxs(Sheet, {
34
+ open: open,
35
+ onOpenChange: setOpen,
36
+ children: [
37
+ /*#__PURE__*/ _jsxs(Tooltip, {
38
+ children: [
39
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
40
+ asChild: true,
41
+ children: /*#__PURE__*/ _jsx("button", {
42
+ type: "button",
43
+ "aria-label": "Inspect job details",
44
+ onClick: ()=>setOpen(true),
45
+ className: "flex size-28 shrink-0 items-center justify-center rounded-4 bg-transparent text-foreground-neutral-muted outline-none transition-colors hover:bg-transparent hover:text-foreground-neutral-base active:bg-transparent focus-visible:shadow-button-neutral-focus",
46
+ children: /*#__PURE__*/ _jsx(Icon, {
47
+ name: "informationLine",
48
+ size: 14,
49
+ "aria-hidden": "true"
50
+ })
51
+ })
52
+ }),
53
+ /*#__PURE__*/ _jsx(TooltipContent, {
54
+ children: "Inspect job details"
55
+ })
56
+ ]
57
+ }),
58
+ /*#__PURE__*/ _jsxs(SheetContent, {
59
+ side: "right",
60
+ className: "w-full sm:max-w-[560px]",
61
+ children: [
62
+ /*#__PURE__*/ _jsxs(SheetHeader, {
63
+ children: [
64
+ /*#__PURE__*/ _jsx(SheetTitle, {
65
+ children: job.displayName
66
+ }),
67
+ /*#__PURE__*/ _jsxs(SheetDescription, {
68
+ children: [
69
+ "Execution #",
70
+ execution.sequence,
71
+ " · ",
72
+ execution.displayName
73
+ ]
74
+ })
75
+ ]
76
+ }),
77
+ /*#__PURE__*/ _jsx(SheetBody, {
78
+ className: "gap-section",
79
+ children: /*#__PURE__*/ _jsxs("div", {
80
+ className: "grid w-full min-w-0 gap-group min-[640px]:grid-cols-2",
81
+ children: [
82
+ runner?.length ? /*#__PURE__*/ _jsx(ContextList, {
83
+ label: "Runner",
84
+ values: runner,
85
+ mono: true
86
+ }) : null,
87
+ execution.queueTime || execution.runTime ? /*#__PURE__*/ _jsxs("div", {
88
+ className: "flex min-w-0 flex-col gap-tight",
89
+ children: [
90
+ /*#__PURE__*/ _jsx(Text, {
91
+ size: "xs",
92
+ bold: true,
93
+ className: "text-foreground-neutral-base",
94
+ children: "Timing"
95
+ }),
96
+ /*#__PURE__*/ _jsxs("div", {
97
+ className: "flex flex-wrap gap-inline text-xs text-foreground-neutral-muted",
98
+ children: [
99
+ execution.queueTime ? /*#__PURE__*/ _jsxs("span", {
100
+ children: [
101
+ "Queue ",
102
+ formatJobExecutionTime(execution.queueTime)
103
+ ]
104
+ }) : null,
105
+ execution.runTime ? /*#__PURE__*/ _jsxs("span", {
106
+ children: [
107
+ "Run ",
108
+ formatJobExecutionTime(execution.runTime)
109
+ ]
110
+ }) : null
111
+ ]
112
+ })
113
+ ]
114
+ }) : null,
115
+ outputs ? /*#__PURE__*/ _jsx(JsonCode, {
116
+ title: "Outputs",
117
+ value: outputs,
118
+ emptyMessage: "No outputs declared; the `outputs:` mapping is empty."
119
+ }) : null,
120
+ job.success ? /*#__PURE__*/ _jsx(ContextValue, {
121
+ label: "Condition",
122
+ value: job.success,
123
+ mono: true
124
+ }) : null,
125
+ statusReason ? /*#__PURE__*/ _jsx(ContextValue, {
126
+ label: "Status reason",
127
+ value: humanize(statusReason)
128
+ }) : null,
129
+ execution.triggerEvents.length ? /*#__PURE__*/ _jsx(JsonCode, {
130
+ title: `Trigger events (${execution.triggerEvents.length})`,
131
+ value: execution.triggerEvents
132
+ }) : null,
133
+ executionNameTrace.length ? /*#__PURE__*/ _jsx(EvaluationTraceSection, {
134
+ title: `Execution name evaluation (${executionNameTrace.length})`,
135
+ trace: executionNameTrace
136
+ }) : null,
137
+ conditionTrace.length ? /*#__PURE__*/ _jsx(EvaluationTraceSection, {
138
+ title: `Condition evaluation (${conditionTrace.length})`,
139
+ trace: conditionTrace
140
+ }) : null
141
+ ]
142
+ })
143
+ })
144
+ ]
145
+ })
146
+ ]
147
+ });
148
+ }
149
+ function EvaluationTraceSection({ title, trace }) {
150
+ return /*#__PURE__*/ _jsxs("div", {
151
+ className: "flex min-w-0 flex-col gap-tight",
152
+ children: [
153
+ /*#__PURE__*/ _jsx(Text, {
154
+ size: "xs",
155
+ bold: true,
156
+ className: "text-foreground-neutral-base",
157
+ children: title
158
+ }),
159
+ /*#__PURE__*/ _jsx(EvaluationTrace, {
160
+ trace: trace
161
+ })
162
+ ]
163
+ });
164
+ }
165
+ function ContextValue({ label, value, mono = false }) {
166
+ return /*#__PURE__*/ _jsxs("div", {
167
+ className: "flex min-w-0 flex-col gap-tight",
168
+ children: [
169
+ /*#__PURE__*/ _jsx(Text, {
170
+ size: "xs",
171
+ bold: true,
172
+ className: "text-foreground-neutral-base",
173
+ children: label
174
+ }),
175
+ /*#__PURE__*/ _jsx(Text, {
176
+ size: "xs",
177
+ className: mono ? 'break-words font-code text-foreground-neutral-muted' : 'text-foreground-neutral-muted',
178
+ children: value
179
+ })
180
+ ]
181
+ });
182
+ }
183
+ function ContextList({ label, values, mono = false }) {
184
+ return /*#__PURE__*/ _jsxs("div", {
185
+ className: "flex min-w-0 flex-col gap-tight",
186
+ children: [
187
+ /*#__PURE__*/ _jsx(Text, {
188
+ size: "xs",
189
+ bold: true,
190
+ className: "text-foreground-neutral-base",
191
+ children: label
192
+ }),
193
+ /*#__PURE__*/ _jsx("div", {
194
+ className: "flex min-w-0 flex-wrap gap-tight",
195
+ children: values.map((value)=>/*#__PURE__*/ _jsx(Code, {
196
+ as: "span",
197
+ variant: "label",
198
+ className: mono ? 'text-foreground-neutral-muted' : 'text-foreground-neutral-base',
199
+ children: value
200
+ }, value))
201
+ })
202
+ ]
203
+ });
204
+ }
205
+ function humanize(value) {
206
+ return value.replaceAll('_', ' ').replace(/\b\w/g, (letter)=>letter.toUpperCase());
207
+ }
208
+ function splitJobEvaluationTrace(trace) {
209
+ const conditionTrace = [];
210
+ const executionNameTrace = [];
211
+ for (const entry of trace){
212
+ if (!('dropped' in entry) && entry.field === 'job.execution_name') {
213
+ executionNameTrace.push(entry);
214
+ } else {
215
+ conditionTrace.push(entry);
216
+ }
217
+ }
218
+ return {
219
+ conditionTrace,
220
+ executionNameTrace
221
+ };
222
+ }
223
+
224
+ //# sourceMappingURL=job-context-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/job-detail/job-context-panel.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport type {EvaluationTraceEntry, Job, JobExecution} from '#core/workflow-run.js';\nimport {formatJobExecutionTime} from './job-execution-time-text.js';\nimport {JsonCode} from './json-code.js';\nimport {EvaluationTrace} from './step-troubleshooting.js';\n\nexport function JobContextPanel({job, execution}: {job: Job; execution: JobExecution}) {\n const runner = execution.runner?.length ? execution.runner : job.runner;\n const outputs = execution.outputs ?? job.outputs;\n const trace = [...(job.evaluationTrace ?? []), ...(execution.evaluationTrace ?? [])];\n const statusReason = execution.statusReason ?? job.statusReason;\n const hasTiming = Boolean(execution.queueTime || execution.runTime);\n const hasContext = Boolean(\n runner?.length ||\n outputs ||\n execution.triggerEvents.length ||\n job.success ||\n statusReason ||\n trace?.length ||\n hasTiming,\n );\n\n if (!hasContext) return null;\n\n return (\n <JobContextSheet\n job={job}\n execution={execution}\n runner={runner}\n outputs={outputs}\n trace={trace}\n statusReason={statusReason}\n />\n );\n}\n\nfunction JobContextSheet({\n job,\n execution,\n runner,\n outputs,\n trace,\n statusReason,\n}: {\n job: Job;\n execution: JobExecution;\n runner: string[] | null;\n outputs: Record<string, unknown> | null;\n trace: EvaluationTraceEntry[];\n statusReason: JobExecution['statusReason'];\n}) {\n const [open, setOpen] = useState(false);\n const {conditionTrace, executionNameTrace} = splitJobEvaluationTrace(trace);\n\n return (\n <Sheet open={open} onOpenChange={setOpen}>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Inspect job details\"\n onClick={() => setOpen(true)}\n className=\"flex size-28 shrink-0 items-center justify-center rounded-4 bg-transparent text-foreground-neutral-muted outline-none transition-colors hover:bg-transparent hover:text-foreground-neutral-base active:bg-transparent focus-visible:shadow-button-neutral-focus\"\n >\n <Icon name=\"informationLine\" size={14} aria-hidden=\"true\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Inspect job details</TooltipContent>\n </Tooltip>\n <SheetContent side=\"right\" className=\"w-full sm:max-w-[560px]\">\n <SheetHeader>\n <SheetTitle>{job.displayName}</SheetTitle>\n <SheetDescription>\n Execution #{execution.sequence} · {execution.displayName}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-section\">\n <div className=\"grid w-full min-w-0 gap-group min-[640px]:grid-cols-2\">\n {runner?.length ? <ContextList label=\"Runner\" values={runner} mono /> : null}\n {execution.queueTime || execution.runTime ? (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n Timing\n </Text>\n <div className=\"flex flex-wrap gap-inline text-xs text-foreground-neutral-muted\">\n {execution.queueTime ? (\n <span>Queue {formatJobExecutionTime(execution.queueTime)}</span>\n ) : null}\n {execution.runTime ? (\n <span>Run {formatJobExecutionTime(execution.runTime)}</span>\n ) : null}\n </div>\n </div>\n ) : null}\n {outputs ? (\n <JsonCode\n title=\"Outputs\"\n value={outputs}\n emptyMessage=\"No outputs declared; the `outputs:` mapping is empty.\"\n />\n ) : null}\n {job.success ? <ContextValue label=\"Condition\" value={job.success} mono /> : null}\n {statusReason ? (\n <ContextValue label=\"Status reason\" value={humanize(statusReason)} />\n ) : null}\n {execution.triggerEvents.length ? (\n <JsonCode\n title={`Trigger events (${execution.triggerEvents.length})`}\n value={execution.triggerEvents}\n />\n ) : null}\n {executionNameTrace.length ? (\n <EvaluationTraceSection\n title={`Execution name evaluation (${executionNameTrace.length})`}\n trace={executionNameTrace}\n />\n ) : null}\n {conditionTrace.length ? (\n <EvaluationTraceSection\n title={`Condition evaluation (${conditionTrace.length})`}\n trace={conditionTrace}\n />\n ) : null}\n </div>\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction EvaluationTraceSection({\n title,\n trace,\n}: {\n title: string;\n trace: readonly EvaluationTraceEntry[];\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {title}\n </Text>\n <EvaluationTrace trace={trace} />\n </div>\n );\n}\n\nfunction ContextValue({\n label,\n value,\n mono = false,\n}: {\n label: string;\n value: string;\n mono?: boolean;\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {label}\n </Text>\n <Text\n size=\"xs\"\n className={\n mono\n ? 'break-words font-code text-foreground-neutral-muted'\n : 'text-foreground-neutral-muted'\n }\n >\n {value}\n </Text>\n </div>\n );\n}\n\nfunction ContextList({\n label,\n values,\n mono = false,\n}: {\n label: string;\n values: string[];\n mono?: boolean;\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {label}\n </Text>\n <div className=\"flex min-w-0 flex-wrap gap-tight\">\n {values.map((value) => (\n <Code\n key={value}\n as=\"span\"\n variant=\"label\"\n className={mono ? 'text-foreground-neutral-muted' : 'text-foreground-neutral-base'}\n >\n {value}\n </Code>\n ))}\n </div>\n </div>\n );\n}\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction splitJobEvaluationTrace(trace: readonly EvaluationTraceEntry[]): {\n conditionTrace: EvaluationTraceEntry[];\n executionNameTrace: EvaluationTraceEntry[];\n} {\n const conditionTrace: EvaluationTraceEntry[] = [];\n const executionNameTrace: EvaluationTraceEntry[] = [];\n\n for (const entry of trace) {\n if (!('dropped' in entry) && entry.field === 'job.execution_name') {\n executionNameTrace.push(entry);\n } else {\n conditionTrace.push(entry);\n }\n }\n\n return {conditionTrace, executionNameTrace};\n}\n"],"names":["Icon","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Tooltip","TooltipContent","TooltipTrigger","Code","Text","useState","formatJobExecutionTime","JsonCode","EvaluationTrace","JobContextPanel","job","execution","runner","length","outputs","trace","evaluationTrace","statusReason","hasTiming","Boolean","queueTime","runTime","hasContext","triggerEvents","success","JobContextSheet","open","setOpen","conditionTrace","executionNameTrace","splitJobEvaluationTrace","onOpenChange","asChild","button","type","aria-label","onClick","className","name","size","aria-hidden","side","displayName","sequence","div","ContextList","label","values","mono","bold","span","title","value","emptyMessage","ContextValue","humanize","EvaluationTraceSection","map","as","variant","replaceAll","replace","letter","toUpperCase","entry","field","push"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { RunAnnotationSummary } from '#core/run-annotation.js';
2
3
  import { type Job, type JobExecution } from '#core/workflow-run.js';
3
4
  export interface JobDetailHeaderProps {
@@ -10,6 +11,7 @@ export interface JobDetailHeaderProps {
10
11
  runAttempt?: number | undefined;
11
12
  /** Counts for this job only. Renders a link into the run's Annotations section, never a body. */
12
13
  annotationSummary?: RunAnnotationSummary | undefined;
14
+ jobContext?: ReactNode;
13
15
  }
14
- export declare function JobDetailHeader({ job, selectedJobExecution, onSelectedJobExecutionChange, workspaceSlug, projectSlug, workflowRunId, runAttempt, annotationSummary, }: JobDetailHeaderProps): import("react").JSX.Element;
16
+ export declare function JobDetailHeader({ job, selectedJobExecution, onSelectedJobExecutionChange, workspaceSlug, projectSlug, workflowRunId, runAttempt, annotationSummary, jobContext, }: JobDetailHeaderProps): import("react").JSX.Element;
15
17
  //# sourceMappingURL=job-detail-header.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"job-detail-header.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-detail-header.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAIL,KAAK,GAAG,EACR,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,GAAG,CAAC;IACT,oBAAoB,EAAE,YAAY,GAAG,SAAS,CAAC;IAC/C,4BAA4B,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACtD;AAED,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,oBAAoB,EACpB,4BAA4B,EAC5B,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,iBAAiB,GAClB,EAAE,oBAAoB,+BAuDtB"}
1
+ {"version":3,"file":"job-detail-header.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-detail-header.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAIL,KAAK,GAAG,EACR,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,GAAG,CAAC;IACT,oBAAoB,EAAE,YAAY,GAAG,SAAS,CAAC;IAC/C,4BAA4B,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,oBAAoB,EACpB,4BAA4B,EAC5B,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,UAAU,GACX,EAAE,oBAAoB,+BA0DtB"}
@@ -9,65 +9,71 @@ import { defaultJobExecution, deriveJobDisplayStatus, deriveJobExecutionDisplayS
9
9
  import { RunAnnotationCountChip } from '../workflow-run-tabs/index.js';
10
10
  import { JobExecutionSwitcher } from './job-execution-switcher.js';
11
11
  import { JobExecutionTimeText } from './job-execution-time-text.js';
12
- export function JobDetailHeader({ job, selectedJobExecution, onSelectedJobExecutionChange, workspaceSlug, projectSlug, workflowRunId, runAttempt, annotationSummary }) {
12
+ export function JobDetailHeader({ job, selectedJobExecution, onSelectedJobExecutionChange, workspaceSlug, projectSlug, workflowRunId, runAttempt, annotationSummary, jobContext }) {
13
13
  const selectedStatus = selectedExecutionStatus(job, selectedJobExecution);
14
14
  const jobStatus = getWorkflowStatusVisual(selectedStatus);
15
15
  return /*#__PURE__*/ _jsx("header", {
16
- className: "border-b border-border-neutral-base px-16 py-12",
16
+ className: "border-b border-border-neutral-base px-row py-row",
17
17
  children: /*#__PURE__*/ _jsxs("div", {
18
- className: "flex min-w-0 flex-col gap-8",
18
+ className: "flex min-w-0 items-start justify-between gap-cluster",
19
19
  children: [
20
20
  /*#__PURE__*/ _jsxs("div", {
21
- className: "flex min-w-0 items-center gap-8",
21
+ className: "flex min-w-0 flex-col gap-inline",
22
22
  children: [
23
- /*#__PURE__*/ _jsx(WorkflowStatusIcon, {
24
- status: selectedStatus,
25
- size: 14,
26
- tooltip: true,
27
- ariaLabel: `Job status: ${jobStatus.label}`
28
- }),
29
- /*#__PURE__*/ _jsx(Code, {
30
- as: "h2",
31
- variant: "paragraph",
32
- bold: true,
33
- tabIndex: -1,
34
- className: "min-w-0 truncate text-lg leading-24 text-foreground-neutral-base outline-none",
35
- "data-job-heading": true,
36
- children: job.displayName
37
- })
38
- ]
39
- }),
40
- selectedJobExecution || annotationSummary?.total ? /*#__PURE__*/ _jsxs("div", {
41
- className: "flex min-w-0 flex-wrap items-center gap-10 text-foreground-neutral-muted",
42
- children: [
43
- selectedJobExecution && job.executionCountVisible ? /*#__PURE__*/ _jsx(JobExecutionSwitcher, {
44
- job: job,
45
- selectedJobExecution: selectedJobExecution.id,
46
- onSelectedJobExecutionChange: onSelectedJobExecutionChange,
47
- variant: "title"
48
- }) : null,
49
- selectedJobExecution ? /*#__PURE__*/ _jsxs(_Fragment, {
23
+ /*#__PURE__*/ _jsxs("div", {
24
+ className: "flex min-w-0 items-center gap-inline",
50
25
  children: [
51
- /*#__PURE__*/ _jsx(JobDurationMeta, {
52
- execution: selectedJobExecution,
53
- kind: "queue"
26
+ /*#__PURE__*/ _jsx(WorkflowStatusIcon, {
27
+ status: selectedStatus,
28
+ size: 14,
29
+ tooltip: true,
30
+ ariaLabel: `Job status: ${jobStatus.label}`
54
31
  }),
55
- /*#__PURE__*/ _jsx(JobDurationMeta, {
56
- execution: selectedJobExecution,
57
- kind: "run"
32
+ /*#__PURE__*/ _jsx(Code, {
33
+ as: "h1",
34
+ variant: "paragraph",
35
+ bold: true,
36
+ tabIndex: -1,
37
+ className: "min-w-0 truncate text-lg leading-24 text-foreground-neutral-base outline-none",
38
+ "data-job-heading": true,
39
+ children: job.displayName
58
40
  })
59
41
  ]
60
- }) : null,
61
- /*#__PURE__*/ _jsx(RunAnnotationCountChip, {
62
- summary: annotationSummary,
63
- workspaceSlug: workspaceSlug,
64
- projectSlug: projectSlug,
65
- workflowRunId: workflowRunId,
66
- runAttempt: runAttempt,
67
- jobId: job.id
68
- })
42
+ }),
43
+ selectedJobExecution || annotationSummary?.total ? /*#__PURE__*/ _jsxs("div", {
44
+ className: "flex min-w-0 flex-wrap items-center gap-inline text-foreground-neutral-muted",
45
+ children: [
46
+ selectedJobExecution && job.executionCountVisible ? /*#__PURE__*/ _jsx(JobExecutionSwitcher, {
47
+ job: job,
48
+ selectedJobExecution: selectedJobExecution.id,
49
+ onSelectedJobExecutionChange: onSelectedJobExecutionChange,
50
+ variant: "title"
51
+ }) : null,
52
+ selectedJobExecution ? /*#__PURE__*/ _jsxs(_Fragment, {
53
+ children: [
54
+ /*#__PURE__*/ _jsx(JobDurationMeta, {
55
+ execution: selectedJobExecution,
56
+ kind: "queue"
57
+ }),
58
+ /*#__PURE__*/ _jsx(JobDurationMeta, {
59
+ execution: selectedJobExecution,
60
+ kind: "run"
61
+ })
62
+ ]
63
+ }) : null,
64
+ /*#__PURE__*/ _jsx(RunAnnotationCountChip, {
65
+ summary: annotationSummary,
66
+ workspaceSlug: workspaceSlug,
67
+ projectSlug: projectSlug,
68
+ workflowRunId: workflowRunId,
69
+ runAttempt: runAttempt,
70
+ jobId: job.id
71
+ })
72
+ ]
73
+ }) : null
69
74
  ]
70
- }) : null
75
+ }),
76
+ jobContext
71
77
  ]
72
78
  })
73
79
  });
@@ -91,7 +97,7 @@ function JobDurationMeta({ execution, kind }) {
91
97
  /*#__PURE__*/ _jsx(TooltipTrigger, {
92
98
  asChild: true,
93
99
  children: /*#__PURE__*/ _jsxs("span", {
94
- className: "inline-flex items-center gap-4 whitespace-nowrap font-code text-xs leading-20 tabular-nums",
100
+ className: "inline-flex items-center gap-tight whitespace-nowrap font-code text-xs leading-20 tabular-nums",
95
101
  children: [
96
102
  /*#__PURE__*/ _jsx(Icon, {
97
103
  name: kind === 'queue' ? 'hourglassLine' : 'timerLine',