@shipfox/client-workflows 16.0.0 → 18.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 (182) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +32 -0
  3. package/dist/components/identifier/identifier.js +2 -2
  4. package/dist/components/identifier/identifier.js.map +1 -1
  5. package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
  6. package/dist/components/job-detail/agent-config-failure-callout.js +1 -1
  7. package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -1
  8. package/dist/components/job-detail/job-context-panel.d.ts +6 -0
  9. package/dist/components/job-detail/job-context-panel.d.ts.map +1 -0
  10. package/dist/components/job-detail/job-context-panel.js +228 -0
  11. package/dist/components/job-detail/job-context-panel.js.map +1 -0
  12. package/dist/components/job-detail/job-detail-header.d.ts +3 -1
  13. package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
  14. package/dist/components/job-detail/job-detail-header.js +54 -48
  15. package/dist/components/job-detail/job-detail-header.js.map +1 -1
  16. package/dist/components/job-detail/job-detail-view.d.ts +1 -1
  17. package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
  18. package/dist/components/job-detail/job-detail-view.js +100 -57
  19. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  20. package/dist/components/job-detail/job-empty-states.d.ts +4 -0
  21. package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
  22. package/dist/components/job-detail/job-empty-states.js +60 -11
  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 +497 -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 +6 -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.d.ts.map +1 -1
  85. package/dist/components/workflow-run-view/run-workspace-nav.js +11 -10
  86. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  87. package/dist/components/workflow-run-view/workflow-run-states.js +6 -6
  88. package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
  89. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  90. package/dist/components/workflow-run-view/workflow-run-view.js +72 -12
  91. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  92. package/dist/core/entities/job-execution.d.ts +9 -0
  93. package/dist/core/entities/job-execution.d.ts.map +1 -1
  94. package/dist/core/entities/job-execution.js.map +1 -1
  95. package/dist/core/entities/job.d.ts +10 -1
  96. package/dist/core/entities/job.d.ts.map +1 -1
  97. package/dist/core/entities/job.js.map +1 -1
  98. package/dist/core/entities/step-attempt.d.ts +29 -0
  99. package/dist/core/entities/step-attempt.d.ts.map +1 -1
  100. package/dist/core/entities/step-attempt.js.map +1 -1
  101. package/dist/core/entities/step.d.ts +3 -1
  102. package/dist/core/entities/step.d.ts.map +1 -1
  103. package/dist/core/entities/step.js.map +1 -1
  104. package/dist/core/run-annotation.d.ts +6 -0
  105. package/dist/core/run-annotation.d.ts.map +1 -1
  106. package/dist/core/run-annotation.js.map +1 -1
  107. package/dist/core/workflow-run.d.ts +1 -1
  108. package/dist/core/workflow-run.d.ts.map +1 -1
  109. package/dist/core/workflow-run.js.map +1 -1
  110. package/dist/hooks/api/annotations.d.ts +63 -0
  111. package/dist/hooks/api/annotations.d.ts.map +1 -0
  112. package/dist/hooks/api/annotations.js +145 -0
  113. package/dist/hooks/api/annotations.js.map +1 -0
  114. package/dist/hooks/api/step-attempt-detail.d.ts +14 -0
  115. package/dist/hooks/api/step-attempt-detail.d.ts.map +1 -0
  116. package/dist/hooks/api/step-attempt-detail.js +43 -0
  117. package/dist/hooks/api/step-attempt-detail.js.map +1 -0
  118. package/dist/hooks/api/workflow-run-mapper.d.ts +9 -2
  119. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  120. package/dist/hooks/api/workflow-run-mapper.js +48 -0
  121. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  122. package/dist/pages/project-workflows-page.js +19 -19
  123. package/dist/pages/project-workflows-page.js.map +1 -1
  124. package/dist/pages/workflow-run-list-page.js +1 -1
  125. package/dist/pages/workflow-run-list-page.js.map +1 -1
  126. package/dist/tsconfig.test.tsbuildinfo +1 -1
  127. package/package.json +10 -10
  128. package/src/components/identifier/identifier.tsx +2 -2
  129. package/src/components/job-detail/agent-config-failure-callout.tsx +5 -1
  130. package/src/components/job-detail/job-context-panel.test.tsx +72 -0
  131. package/src/components/job-detail/job-context-panel.tsx +241 -0
  132. package/src/components/job-detail/job-detail-header.tsx +52 -46
  133. package/src/components/job-detail/job-detail-view.stories.tsx +555 -53
  134. package/src/components/job-detail/job-detail-view.tsx +105 -59
  135. package/src/components/job-detail/job-empty-states.test.ts +105 -1
  136. package/src/components/job-detail/job-empty-states.tsx +77 -10
  137. package/src/components/job-detail/job-execution-switcher.tsx +5 -5
  138. package/src/components/job-detail/json-code.tsx +120 -0
  139. package/src/components/job-detail/step-attempt-log-panel.test.tsx +1 -0
  140. package/src/components/job-detail/step-attempt-log-panel.tsx +17 -6
  141. package/src/components/job-detail/step-troubleshooting.stories.tsx +120 -0
  142. package/src/components/job-detail/step-troubleshooting.test.tsx +337 -0
  143. package/src/components/job-detail/step-troubleshooting.tsx +541 -0
  144. package/src/components/job-graph/job-graph-content.tsx +4 -3
  145. package/src/components/job-graph/job-node.tsx +3 -3
  146. package/src/components/step-list/index.ts +1 -0
  147. package/src/components/step-list/step-list-model.ts +6 -0
  148. package/src/components/step-list/step-list.test.tsx +75 -2
  149. package/src/components/step-list/step-list.tsx +73 -20
  150. package/src/components/workflow-run-duration-label.tsx +1 -1
  151. package/src/components/workflow-run-list/job-status-strip.tsx +6 -6
  152. package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +1 -1
  153. package/src/components/workflow-run-list/workflow-run-filters.tsx +4 -4
  154. package/src/components/workflow-run-list/workflow-run-list-states.tsx +6 -6
  155. package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
  156. package/src/components/workflow-run-list/workflow-run-row.tsx +7 -7
  157. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +1 -1
  158. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +1 -1
  159. package/src/components/workflow-run-summary/workflow-run-summary.tsx +11 -11
  160. package/src/components/workflow-run-tabs/index.ts +5 -1
  161. package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +2 -2
  162. package/src/components/workflow-run-tabs/run-annotation-list.tsx +25 -10
  163. package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +5 -5
  164. package/src/components/workflow-run-view/run-workspace-nav.tsx +18 -11
  165. package/src/components/workflow-run-view/workflow-run-states.tsx +6 -6
  166. package/src/components/workflow-run-view/workflow-run-view.tsx +114 -14
  167. package/src/core/entities/job-execution.ts +9 -0
  168. package/src/core/entities/job.ts +12 -1
  169. package/src/core/entities/step-attempt.ts +33 -0
  170. package/src/core/entities/step.ts +3 -1
  171. package/src/core/run-annotation.ts +6 -0
  172. package/src/core/workflow-run.ts +4 -0
  173. package/src/hooks/api/annotations.test.ts +84 -0
  174. package/src/hooks/api/annotations.ts +240 -0
  175. package/src/hooks/api/step-attempt-detail.ts +67 -0
  176. package/src/hooks/api/workflow-run-mapper.ts +47 -0
  177. package/src/hooks/api/workflow-runs.test.tsx +61 -1
  178. package/src/pages/project-workflows-page.tsx +19 -19
  179. package/src/pages/workflow-job-detail-page.test.tsx +52 -1
  180. package/src/pages/workflow-run-list-page.tsx +1 -1
  181. package/test/fixtures/workflow-run.ts +7 -0
  182. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-detail/job-detail-header.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {formatTimestamp} from '@shipfox/react-ui/utils';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n deriveJobExecutionDisplayStatus,\n type Job,\n type JobExecution,\n} from '#core/workflow-run.js';\nimport {RunAnnotationCountChip} from '../workflow-run-tabs/index.js';\nimport {JobExecutionSwitcher} from './job-execution-switcher.js';\nimport {JobExecutionTimeText} from './job-execution-time-text.js';\n\nexport interface JobDetailHeaderProps {\n job: Job;\n selectedJobExecution: JobExecution | undefined;\n onSelectedJobExecutionChange: (jobExecutionId: string) => void;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt?: number | undefined;\n /** Counts for this job only. Renders a link into the run's Annotations section, never a body. */\n annotationSummary?: RunAnnotationSummary | undefined;\n}\n\nexport function JobDetailHeader({\n job,\n selectedJobExecution,\n onSelectedJobExecutionChange,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n annotationSummary,\n}: JobDetailHeaderProps) {\n const selectedStatus = selectedExecutionStatus(job, selectedJobExecution);\n const jobStatus = getWorkflowStatusVisual(selectedStatus);\n\n return (\n <header className=\"border-b border-border-neutral-base px-16 py-12\">\n <div className=\"flex min-w-0 flex-col gap-8\">\n <div className=\"flex min-w-0 items-center gap-8\">\n <WorkflowStatusIcon\n status={selectedStatus}\n size={14}\n tooltip\n ariaLabel={`Job status: ${jobStatus.label}`}\n />\n <Code\n as=\"h2\"\n variant=\"paragraph\"\n bold\n tabIndex={-1}\n className=\"min-w-0 truncate text-lg leading-24 text-foreground-neutral-base outline-none\"\n data-job-heading\n >\n {job.displayName}\n </Code>\n </div>\n\n {selectedJobExecution || annotationSummary?.total ? (\n <div className=\"flex min-w-0 flex-wrap items-center gap-10 text-foreground-neutral-muted\">\n {selectedJobExecution && job.executionCountVisible ? (\n <JobExecutionSwitcher\n job={job}\n selectedJobExecution={selectedJobExecution.id}\n onSelectedJobExecutionChange={onSelectedJobExecutionChange}\n variant=\"title\"\n />\n ) : null}\n {selectedJobExecution ? (\n <>\n <JobDurationMeta execution={selectedJobExecution} kind=\"queue\" />\n <JobDurationMeta execution={selectedJobExecution} kind=\"run\" />\n </>\n ) : null}\n <RunAnnotationCountChip\n summary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n jobId={job.id}\n />\n </div>\n ) : null}\n </div>\n </header>\n );\n}\n\nfunction selectedExecutionStatus(job: Job, execution: JobExecution | undefined) {\n if (!execution) return deriveJobDisplayStatus(job);\n const defaultExecution = defaultJobExecution(job);\n return execution.id === defaultExecution?.id\n ? deriveJobDisplayStatus(job)\n : deriveJobExecutionDisplayStatus(execution);\n}\n\nfunction JobDurationMeta({execution, kind}: {execution: JobExecution; kind: 'queue' | 'run'}) {\n const time = kind === 'queue' ? execution.queueTime : execution.runTime;\n const from = kind === 'queue' ? execution.queuedAt : execution.startedAt;\n if (!time || !from) return null;\n\n const to = kind === 'queue' ? execution.startedAt : execution.finishedAt;\n const live = time.state === 'live';\n const label = kind === 'queue' ? 'queued' : live ? 'running' : 'ran';\n const tooltipLabel = kind === 'queue' ? 'Queued' : live ? 'Running' : 'Ran';\n const tooltip = `${tooltipLabel} ${formatTimestamp(from)}${to ? ` – ${formatTimestamp(to)}` : ' – now'}`;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex items-center gap-4 whitespace-nowrap font-code text-xs leading-20 tabular-nums\">\n <Icon\n name={kind === 'queue' ? 'hourglassLine' : 'timerLine'}\n size={12}\n aria-hidden=\"true\"\n />\n <span>{label} </span>\n <JobExecutionTimeText time={time} />\n </span>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n"],"names":["Icon","Tooltip","TooltipContent","TooltipTrigger","Code","Text","formatTimestamp","getWorkflowStatusVisual","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","deriveJobExecutionDisplayStatus","RunAnnotationCountChip","JobExecutionSwitcher","JobExecutionTimeText","JobDetailHeader","job","selectedJobExecution","onSelectedJobExecutionChange","workspaceSlug","projectSlug","workflowRunId","runAttempt","annotationSummary","selectedStatus","selectedExecutionStatus","jobStatus","header","className","div","status","size","tooltip","ariaLabel","label","as","variant","bold","tabIndex","data-job-heading","displayName","total","executionCountVisible","id","JobDurationMeta","execution","kind","summary","jobId","defaultExecution","time","queueTime","runTime","from","queuedAt","startedAt","to","finishedAt","live","state","tooltipLabel","asChild","span","name","aria-hidden"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/job-detail/job-detail-header.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {formatTimestamp} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n deriveJobExecutionDisplayStatus,\n type Job,\n type JobExecution,\n} from '#core/workflow-run.js';\nimport {RunAnnotationCountChip} from '../workflow-run-tabs/index.js';\nimport {JobExecutionSwitcher} from './job-execution-switcher.js';\nimport {JobExecutionTimeText} from './job-execution-time-text.js';\n\nexport interface JobDetailHeaderProps {\n job: Job;\n selectedJobExecution: JobExecution | undefined;\n onSelectedJobExecutionChange: (jobExecutionId: string) => void;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt?: number | undefined;\n /** Counts for this job only. Renders a link into the run's Annotations section, never a body. */\n annotationSummary?: RunAnnotationSummary | undefined;\n jobContext?: ReactNode;\n}\n\nexport function JobDetailHeader({\n job,\n selectedJobExecution,\n onSelectedJobExecutionChange,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n annotationSummary,\n jobContext,\n}: JobDetailHeaderProps) {\n const selectedStatus = selectedExecutionStatus(job, selectedJobExecution);\n const jobStatus = getWorkflowStatusVisual(selectedStatus);\n\n return (\n <header className=\"border-b border-border-neutral-base px-row py-row\">\n <div className=\"flex min-w-0 items-start justify-between gap-cluster\">\n <div className=\"flex min-w-0 flex-col gap-inline\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <WorkflowStatusIcon\n status={selectedStatus}\n size={14}\n tooltip\n ariaLabel={`Job status: ${jobStatus.label}`}\n />\n <Code\n as=\"h1\"\n variant=\"paragraph\"\n bold\n tabIndex={-1}\n className=\"min-w-0 truncate text-lg leading-24 text-foreground-neutral-base outline-none\"\n data-job-heading\n >\n {job.displayName}\n </Code>\n </div>\n\n {selectedJobExecution || annotationSummary?.total ? (\n <div className=\"flex min-w-0 flex-wrap items-center gap-inline text-foreground-neutral-muted\">\n {selectedJobExecution && job.executionCountVisible ? (\n <JobExecutionSwitcher\n job={job}\n selectedJobExecution={selectedJobExecution.id}\n onSelectedJobExecutionChange={onSelectedJobExecutionChange}\n variant=\"title\"\n />\n ) : null}\n {selectedJobExecution ? (\n <>\n <JobDurationMeta execution={selectedJobExecution} kind=\"queue\" />\n <JobDurationMeta execution={selectedJobExecution} kind=\"run\" />\n </>\n ) : null}\n <RunAnnotationCountChip\n summary={annotationSummary}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n jobId={job.id}\n />\n </div>\n ) : null}\n </div>\n {jobContext}\n </div>\n </header>\n );\n}\n\nfunction selectedExecutionStatus(job: Job, execution: JobExecution | undefined) {\n if (!execution) return deriveJobDisplayStatus(job);\n const defaultExecution = defaultJobExecution(job);\n return execution.id === defaultExecution?.id\n ? deriveJobDisplayStatus(job)\n : deriveJobExecutionDisplayStatus(execution);\n}\n\nfunction JobDurationMeta({execution, kind}: {execution: JobExecution; kind: 'queue' | 'run'}) {\n const time = kind === 'queue' ? execution.queueTime : execution.runTime;\n const from = kind === 'queue' ? execution.queuedAt : execution.startedAt;\n if (!time || !from) return null;\n\n const to = kind === 'queue' ? execution.startedAt : execution.finishedAt;\n const live = time.state === 'live';\n const label = kind === 'queue' ? 'queued' : live ? 'running' : 'ran';\n const tooltipLabel = kind === 'queue' ? 'Queued' : live ? 'Running' : 'Ran';\n const tooltip = `${tooltipLabel} ${formatTimestamp(from)}${to ? ` – ${formatTimestamp(to)}` : ' – now'}`;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex items-center gap-tight whitespace-nowrap font-code text-xs leading-20 tabular-nums\">\n <Icon\n name={kind === 'queue' ? 'hourglassLine' : 'timerLine'}\n size={12}\n aria-hidden=\"true\"\n />\n <span>{label} </span>\n <JobExecutionTimeText time={time} />\n </span>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n"],"names":["Icon","Tooltip","TooltipContent","TooltipTrigger","Code","Text","formatTimestamp","getWorkflowStatusVisual","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","deriveJobExecutionDisplayStatus","RunAnnotationCountChip","JobExecutionSwitcher","JobExecutionTimeText","JobDetailHeader","job","selectedJobExecution","onSelectedJobExecutionChange","workspaceSlug","projectSlug","workflowRunId","runAttempt","annotationSummary","jobContext","selectedStatus","selectedExecutionStatus","jobStatus","header","className","div","status","size","tooltip","ariaLabel","label","as","variant","bold","tabIndex","data-job-heading","displayName","total","executionCountVisible","id","JobDurationMeta","execution","kind","summary","jobId","defaultExecution","time","queueTime","runTime","from","queuedAt","startedAt","to","finishedAt","live","state","tooltipLabel","asChild","span","name","aria-hidden"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Job } from '#core/workflow-run.js';
1
+ import { type Job } from '#core/workflow-run.js';
2
2
  import type { useWorkflowRunAttemptQuery } from '#hooks/api/workflow-runs.js';
3
3
  import { type WorkflowJobSearch } from '#routes/inputs.js';
4
4
  export interface JobDetailViewProps {
@@ -1 +1 @@
1
- {"version":3,"file":"job-detail-view.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-detail-view.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,GAAG,EAAe,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAuB3B,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;IAC3B,iBAAiB,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,aAAa,CAAC,EAC5B,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,EACL,MAAM,EACN,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,iBAAiB,GAClB,EAAE,kBAAkB,+BA2NpB"}
1
+ {"version":3,"file":"job-detail-view.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-detail-view.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAwB,KAAK,GAAG,EAAoB,MAAM,uBAAuB,CAAC;AAGzF,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAyB3B,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;IAC3B,iBAAiB,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,aAAa,CAAC,EAC5B,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,EACL,MAAM,EACN,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,iBAAiB,GAClB,EAAE,kBAAkB,+BAwQpB"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  // biome-ignore-all lint/a11y/noRedundantRoles: the job log region keeps an explicit role for the public accessibility contract.
3
3
  // biome-ignore-all lint/a11y/noNoninteractiveTabindex: the job log region is intentionally keyboard focusable.
4
4
  import { ApiError } from '@shipfox/client-api';
@@ -9,23 +9,27 @@ import { Skeleton } from '@shipfox/react-ui/skeleton';
9
9
  import { TimeTickerProvider } from '@shipfox/react-ui/time-ticker';
10
10
  import { Text } from '@shipfox/react-ui/typography';
11
11
  import { Link } from '@tanstack/react-router';
12
- import { useEffect, useRef } from 'react';
12
+ import { useEffect, useRef, useState } from 'react';
13
13
  import { summarizeJobAnnotations } from '#core/run-annotation.js';
14
+ import { isWorkflowRunTerminal } from '#core/workflow-run.js';
15
+ import { useWorkflowRunAnnotationSummaryQuery } from '#hooks/api/annotations.js';
14
16
  import { useRunAnnotationsQuery } from '#hooks/api/run-annotations.js';
15
17
  import { workflowJobSearchParams, workflowRunSearchParams } from '#routes/inputs.js';
16
18
  import { StepList } from '../step-list/index.js';
17
19
  import { WorkflowRunNotFound, WorkflowRunStaleError } from '../workflow-run-view/workflow-run-states.js';
18
- import { AgentConfigFailureCallout } from './agent-config-failure-callout.js';
20
+ import { JobContextPanel } from './job-context-panel.js';
19
21
  import { JobDetailHeader } from './job-detail-header.js';
20
- import { CarriedOverStepPanel, emptyStateForJob, emptyStateForMissingExecution, isAgentConfigFailure, jobSucceededSummary, toSelectedAttemptError } from './job-empty-states.js';
22
+ import { CarriedOverStepPanel, emptyStateForJob, emptyStateForMissingExecution, jobSucceededSummary, MaterializedOutputFailureNotice } from './job-empty-states.js';
21
23
  import { resolveWorkflowJobSelection, workflowJobLandingSelection } from './job-selection.js';
22
24
  import { StepAttemptLogPanel } from './step-attempt-log-panel.js';
25
+ import { StepInspectorSheet } from './step-troubleshooting.js';
23
26
  export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId, search, query, newerAttempt, newerJob, onSelectionChange }) {
24
27
  const rootRef = useRef(null);
25
28
  const pageScrollRef = useRef(null);
26
29
  const landingSelectionRef = useRef(undefined);
27
30
  const hasLoadedData = query.data !== undefined;
28
- // Same query key as the run workspace, so this reads the cache instead of fetching again.
31
+ // Reuse the run workspace's bounded annotation read for the job header chip. The separate
32
+ // summary query below stays counts-only and is scoped to the inspector's selected execution.
29
33
  const annotations = useRunAnnotationsQuery({
30
34
  workflowRunId,
31
35
  runAttempt: query.data?.runAttempt.attempt
@@ -33,6 +37,21 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
33
37
  const jobAnnotationSummary = annotations.annotations ? summarizeJobAnnotations(annotations.annotations, jobId, {
34
38
  truncated: annotations.summary?.truncated ?? false
35
39
  }) : undefined;
40
+ const inspectorResetKey = `${jobId}:${search.jobExecutionId ?? ''}`;
41
+ const [inspectorState, setInspectorState] = useState(()=>({
42
+ key: inspectorResetKey,
43
+ attemptId: null
44
+ }));
45
+ const inspectorOpenAttemptId = inspectorState.key === inspectorResetKey ? inspectorState.attemptId : null;
46
+ const annotationJob = query.data?.jobs.find((candidate)=>candidate.id === jobId);
47
+ const annotationExecutionId = annotationJob ? resolveWorkflowJobSelection({
48
+ job: annotationJob,
49
+ selection: search
50
+ }).jobExecution?.id : search.jobExecutionId;
51
+ const annotationPolling = query.data ? !isWorkflowRunTerminal(query.data.runAttempt.status) : true;
52
+ const annotationSummaryQuery = useWorkflowRunAnnotationSummaryQuery(query.data?.id, query.data?.runAttempt.attempt, annotationExecutionId, {
53
+ polling: annotationPolling
54
+ });
36
55
  useEffect(()=>{
37
56
  if (!jobId || !hasLoadedData) return;
38
57
  const heading = rootRef.current?.querySelector('[data-job-heading]');
@@ -128,6 +147,12 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
128
147
  stepAttemptId: match.attemptId
129
148
  });
130
149
  }
150
+ function onInspectorOpenChange(attemptId) {
151
+ setInspectorState({
152
+ key: inspectorResetKey,
153
+ attemptId
154
+ });
155
+ }
131
156
  function retargetToRunningStep() {
132
157
  if (!runningSelection || !selectedJobExecution) return;
133
158
  onSelectionChange({
@@ -156,10 +181,10 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
156
181
  }) : null,
157
182
  /*#__PURE__*/ _jsx("div", {
158
183
  ref: pageScrollRef,
159
- className: "@container min-h-0 flex-1 overflow-auto pb-24",
184
+ className: "@container min-h-0 flex-1 overflow-auto pb-panel",
160
185
  children: /*#__PURE__*/ _jsxs("section", {
161
186
  "aria-label": `${job.displayName} logs`,
162
- className: "mx-auto flex w-full max-w-[1120px] flex-col gap-8 px-24",
187
+ className: "flex w-full flex-col",
163
188
  children: [
164
189
  /*#__PURE__*/ _jsxs("section", {
165
190
  className: "min-w-0 overflow-hidden",
@@ -170,30 +195,53 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
170
195
  onSelectedJobExecutionChange: selectExecution,
171
196
  workspaceSlug: workspaceSlug,
172
197
  projectSlug: projectSlug,
173
- workflowRunId: workflowRunId,
198
+ workflowRunId: run.id,
174
199
  runAttempt: run.runAttempt.attempt,
175
- annotationSummary: jobAnnotationSummary
200
+ annotationSummary: jobAnnotationSummary,
201
+ jobContext: selectedJobExecution ? /*#__PURE__*/ _jsx(JobContextPanel, {
202
+ job: job,
203
+ execution: selectedJobExecution
204
+ }) : undefined
176
205
  }),
177
206
  /*#__PURE__*/ _jsx(Text, {
178
- as: "h3",
207
+ as: "h2",
179
208
  className: "sr-only",
180
209
  children: "Logs"
181
210
  }),
182
- selectedJobExecution ? /*#__PURE__*/ _jsx(StepList, {
183
- job: job,
184
- jobExecution: selectedJobExecution,
185
- selectedAttemptId: selectedAttemptId,
186
- defaultSelectedAttemptId: landingSelection?.attemptId,
187
- onSelectedAttemptChange: selectAttempt,
188
- autoSelectActiveAttempt: true,
189
- emptyState: emptyStateForJob(job, selectedJobExecution),
190
- showHeader: false,
191
- className: "rounded-none border-0",
192
- renderExpandedStep: (context)=>/*#__PURE__*/ _jsx(ExpandedStep, {
193
- context: context,
194
- workspaceSlug: workspaceSlug,
195
- pageScrollRef: pageScrollRef
211
+ selectedJobExecution ? /*#__PURE__*/ _jsxs(_Fragment, {
212
+ children: [
213
+ /*#__PURE__*/ _jsx(MaterializedOutputFailureNotice, {
214
+ jobExecution: selectedJobExecution
215
+ }),
216
+ /*#__PURE__*/ _jsx(StepList, {
217
+ job: job,
218
+ jobExecution: selectedJobExecution,
219
+ selectedAttemptId: selectedAttemptId,
220
+ defaultSelectedAttemptId: landingSelection?.attemptId,
221
+ onSelectedAttemptChange: selectAttempt,
222
+ inspectorOpenAttemptId: inspectorOpenAttemptId,
223
+ onInspectorOpenChange: onInspectorOpenChange,
224
+ autoSelectActiveAttempt: true,
225
+ emptyState: emptyStateForJob(job, selectedJobExecution),
226
+ showHeader: false,
227
+ className: "rounded-none border-0 bg-transparent",
228
+ renderExpandedStep: (context)=>/*#__PURE__*/ _jsx(ExpandedStep, {
229
+ context: context,
230
+ pageScrollRef: pageScrollRef
231
+ }),
232
+ renderInspector: (entry)=>/*#__PURE__*/ _jsx(StepInspectorSheet, {
233
+ entry: entry,
234
+ open: true,
235
+ onOpenChange: (open)=>onInspectorOpenChange(open ? entry.id : null),
236
+ workspaceSlug: workspaceSlug,
237
+ projectSlug: projectSlug,
238
+ workflowRunId: run.id,
239
+ runAttempt: run.runAttempt.attempt,
240
+ jobId: job.id,
241
+ annotationCount: annotationCountForStep(annotationSummaryQuery.data, entry.step.id, entry.attempt)
242
+ })
196
243
  })
244
+ ]
197
245
  }) : /*#__PURE__*/ _jsx(EmptyStateForMissingExecution, {
198
246
  job: job
199
247
  })
@@ -202,7 +250,7 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
202
250
  showRetargetNotice && runningSelection ? /*#__PURE__*/ _jsxs("div", {
203
251
  role: "status",
204
252
  "aria-live": "polite",
205
- className: "flex min-w-0 items-center justify-between gap-8 rounded-8 border border-border-neutral-base bg-background-components-base px-10 py-8",
253
+ className: "flex min-w-0 items-center justify-between gap-inline border-t border-border-neutral-base px-row py-row",
206
254
  children: [
207
255
  /*#__PURE__*/ _jsxs(Text, {
208
256
  size: "xs",
@@ -219,7 +267,7 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
219
267
  }),
220
268
  /*#__PURE__*/ _jsx("button", {
221
269
  type: "button",
222
- className: "shrink-0 rounded-4 px-6 py-4 text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
270
+ className: "shrink-0 rounded-4 px-tight py-[4px] text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
223
271
  onClick: retargetToRunningStep,
224
272
  children: "Jump to it"
225
273
  })
@@ -227,7 +275,7 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
227
275
  }) : null,
228
276
  succeededSummary ? /*#__PURE__*/ _jsx(Text, {
229
277
  size: "xs",
230
- className: "px-8 text-foreground-neutral-muted",
278
+ className: "px-row py-row text-foreground-neutral-muted",
231
279
  children: succeededSummary
232
280
  }) : null
233
281
  ]
@@ -237,35 +285,27 @@ export function JobDetailView({ workspaceSlug, projectSlug, workflowRunId, jobId
237
285
  })
238
286
  });
239
287
  }
240
- function ExpandedStep({ context, workspaceSlug, pageScrollRef }) {
288
+ function ExpandedStep({ context, pageScrollRef }) {
241
289
  if (context.carriedOver) return /*#__PURE__*/ _jsx(CarriedOverStepPanel, {});
242
- const selectedAttemptError = toSelectedAttemptError(context.step, context.attemptError) ?? context.step.error;
243
- return /*#__PURE__*/ _jsxs("section", {
290
+ return /*#__PURE__*/ _jsx("section", {
244
291
  role: "region",
245
292
  tabIndex: 0,
246
293
  "aria-label": `${context.stepLabel} output, attempt ${context.attempt}`,
247
- className: "flex min-w-0 flex-col gap-10 border-t border-border-neutral-base bg-background-neutral-subtle px-16 py-12 outline-none focus-visible:shadow-border-interactive-with-active",
248
- children: [
249
- isAgentConfigFailure(context.step, selectedAttemptError) ? /*#__PURE__*/ _jsx(AgentConfigFailureCallout, {
250
- workspaceSlug: workspaceSlug,
251
- config: context.step.agentConfig,
252
- error: selectedAttemptError
253
- }) : null,
254
- /*#__PURE__*/ _jsx(StepAttemptLogPanel, {
255
- stepId: context.stepId,
256
- attempt: context.attempt,
257
- attemptStatus: context.attemptStatus,
258
- attemptStartedAt: context.attemptStartedAt,
259
- pageScrollRef: pageScrollRef,
260
- surfaceClassName: "rounded-8"
261
- })
262
- ]
294
+ className: "flex min-w-0 flex-col border-t border-border-neutral-base bg-background-neutral-base outline-none focus-visible:shadow-border-interactive-with-active dark:bg-background-contrast-subtle",
295
+ children: /*#__PURE__*/ _jsx(StepAttemptLogPanel, {
296
+ stepId: context.stepId,
297
+ attempt: context.attempt,
298
+ attemptStatus: context.attemptStatus,
299
+ attemptStartedAt: context.attemptStartedAt,
300
+ pageScrollRef: pageScrollRef,
301
+ surfaceClassName: "rounded-none border-0 bg-transparent shadow-none"
302
+ })
263
303
  });
264
304
  }
265
305
  function EmptyStateForMissingExecution({ job }) {
266
306
  const emptyState = emptyStateForMissingExecution(job);
267
307
  return /*#__PURE__*/ _jsx(EmptyState, {
268
- className: "min-h-120 px-16 py-20",
308
+ className: "min-h-120 p-panel",
269
309
  icon: "componentLine",
270
310
  title: emptyState.title,
271
311
  description: emptyState.description,
@@ -274,7 +314,7 @@ function EmptyStateForMissingExecution({ job }) {
274
314
  }
275
315
  function JobNotFoundState({ workspaceSlug, projectSlug, workflowRunId, search }) {
276
316
  return /*#__PURE__*/ _jsxs("div", {
277
- className: "flex min-h-0 min-w-0 flex-1 flex-col items-center justify-center gap-12 p-24",
317
+ className: "flex min-h-0 min-w-0 flex-1 flex-col items-center justify-center gap-cluster p-panel",
278
318
  children: [
279
319
  /*#__PURE__*/ _jsx(EmptyState, {
280
320
  icon: "componentLine",
@@ -293,7 +333,7 @@ function JobNotFoundState({ workspaceSlug, projectSlug, workflowRunId, search })
293
333
  }, {
294
334
  runAttempt: search.runAttempt
295
335
  }),
296
- className: "inline-flex items-center gap-6 rounded-6 px-8 py-6 text-sm text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
336
+ className: "inline-flex items-center gap-inline rounded-6 px-tight py-[6px] text-sm text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
297
337
  children: [
298
338
  /*#__PURE__*/ _jsx(Icon, {
299
339
  name: "arrowLeftLine",
@@ -309,9 +349,9 @@ function JobNotFoundState({ workspaceSlug, projectSlug, workflowRunId, search })
309
349
  function NewerAttemptNotice({ workspaceSlug, projectSlug, runId, jobId, attempt }) {
310
350
  return /*#__PURE__*/ _jsx("div", {
311
351
  role: "status",
312
- className: "border-b border-border-neutral-base px-16 py-8",
352
+ className: "border-b border-border-neutral-base px-row py-row",
313
353
  children: /*#__PURE__*/ _jsxs("div", {
314
- className: "mx-auto flex max-w-[1120px] items-center justify-between gap-8 rounded-8 border border-border-neutral-base bg-background-components-base px-10 py-8",
354
+ className: "flex items-center justify-between gap-inline",
315
355
  children: [
316
356
  /*#__PURE__*/ _jsx(Text, {
317
357
  size: "xs",
@@ -329,7 +369,7 @@ function NewerAttemptNotice({ workspaceSlug, projectSlug, runId, jobId, attempt
329
369
  search: workflowJobSearchParams({
330
370
  runAttempt: attempt
331
371
  }),
332
- className: "shrink-0 rounded-4 px-6 py-4 text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
372
+ className: "shrink-0 rounded-4 px-tight py-[4px] text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active",
333
373
  children: [
334
374
  "View attempt #",
335
375
  attempt
@@ -368,14 +408,17 @@ function findAttempt(jobExecution, attemptId) {
368
408
  }
369
409
  return undefined;
370
410
  }
411
+ function annotationCountForStep(summary, stepId, attempt) {
412
+ return summary?.stepCounts?.find((entry)=>entry.stepId === stepId && entry.attempt === attempt)?.total;
413
+ }
371
414
  function JobDetailSkeleton() {
372
415
  return /*#__PURE__*/ _jsx("div", {
373
- className: "min-h-0 min-w-0 flex-1 overflow-auto px-24 pb-24",
416
+ className: "min-h-0 min-w-0 flex-1 overflow-auto pb-panel",
374
417
  children: /*#__PURE__*/ _jsxs("div", {
375
- className: "mx-auto max-w-[1120px] overflow-hidden",
418
+ className: "w-full",
376
419
  children: [
377
420
  /*#__PURE__*/ _jsxs("header", {
378
- className: "flex items-center gap-12 border-b border-border-neutral-base px-16 py-12",
421
+ className: "flex items-center gap-cluster border-b border-border-neutral-base px-row py-row",
379
422
  children: [
380
423
  /*#__PURE__*/ _jsx(Skeleton, {
381
424
  className: "size-20 rounded-full"
@@ -392,9 +435,9 @@ function JobDetailSkeleton() {
392
435
  ]
393
436
  }),
394
437
  /*#__PURE__*/ _jsx("div", {
395
- className: "p-16",
438
+ className: "p-panel-compact",
396
439
  children: JOB_DETAIL_SKELETON_ROWS.map((row)=>/*#__PURE__*/ _jsxs("div", {
397
- className: "flex min-h-44 items-center gap-8 border-b border-border-neutral-base last:border-b-0",
440
+ className: "flex min-h-44 items-center gap-inline border-b border-border-neutral-base last:border-b-0",
398
441
  children: [
399
442
  /*#__PURE__*/ _jsx(Skeleton, {
400
443
  className: "size-14 rounded-full"
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-detail/job-detail-view.tsx"],"sourcesContent":["// biome-ignore-all lint/a11y/noRedundantRoles: the job log region keeps an explicit role for the public accessibility contract.\n// biome-ignore-all lint/a11y/noNoninteractiveTabindex: the job log region is intentionally keyboard focusable.\n\nimport {ApiError} from '@shipfox/client-api';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {type RefObject, useEffect, useRef} from 'react';\nimport {summarizeJobAnnotations} from '#core/run-annotation.js';\nimport type {Job, JobExecution} from '#core/workflow-run.js';\nimport {useRunAnnotationsQuery} from '#hooks/api/run-annotations.js';\nimport type {useWorkflowRunAttemptQuery} from '#hooks/api/workflow-runs.js';\nimport {\n type WorkflowJobSearch,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {type StepExpandedContext, StepList} from '../step-list/index.js';\nimport {\n WorkflowRunNotFound,\n WorkflowRunStaleError,\n} from '../workflow-run-view/workflow-run-states.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {JobDetailHeader} from './job-detail-header.js';\nimport {\n CarriedOverStepPanel,\n emptyStateForJob,\n emptyStateForMissingExecution,\n isAgentConfigFailure,\n jobSucceededSummary,\n toSelectedAttemptError,\n} from './job-empty-states.js';\nimport {\n resolveWorkflowJobSelection,\n type WorkflowJobLandingSelection,\n workflowJobLandingSelection,\n} from './job-selection.js';\nimport {StepAttemptLogPanel} from './step-attempt-log-panel.js';\n\nexport interface JobDetailViewProps {\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n jobId: string;\n search: WorkflowJobSearch;\n query: ReturnType<typeof useWorkflowRunAttemptQuery>;\n newerAttempt?: number | undefined;\n newerJob?: Job | undefined;\n onSelectionChange: (selection: WorkflowJobSearch) => void;\n}\n\nexport function JobDetailView({\n workspaceSlug,\n projectSlug,\n workflowRunId,\n jobId,\n search,\n query,\n newerAttempt,\n newerJob,\n onSelectionChange,\n}: JobDetailViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const pageScrollRef = useRef<HTMLDivElement>(null);\n const landingSelectionRef = useRef<FrozenLandingSelection | undefined>(undefined);\n const hasLoadedData = query.data !== undefined;\n // Same query key as the run workspace, so this reads the cache instead of fetching again.\n const annotations = useRunAnnotationsQuery({\n workflowRunId,\n runAttempt: query.data?.runAttempt.attempt,\n });\n const jobAnnotationSummary = annotations.annotations\n ? summarizeJobAnnotations(annotations.annotations, jobId, {\n truncated: annotations.summary?.truncated ?? false,\n })\n : undefined;\n\n useEffect(() => {\n if (!jobId || !hasLoadedData) return;\n const heading = rootRef.current?.querySelector<HTMLElement>('[data-job-heading]');\n // The heading is intentionally the route-change focus target: it announces the new job\n // after rail navigation without putting focus on a decorative status element.\n heading?.focus({preventScroll: true});\n }, [hasLoadedData, jobId]);\n\n if (query.isPending) return <JobDetailSkeleton />;\n\n if (query.isError && query.data === undefined) {\n if (query.error instanceof ApiError && query.error.status === 404) {\n return <WorkflowRunNotFound />;\n }\n return <QueryLoadError query={query} subject=\"workflow run\" icon=\"pulseLine\" />;\n }\n\n if (query.data === undefined) return <JobDetailSkeleton />;\n\n const run = query.data;\n const job = run.jobs.find((candidate) => candidate.id === jobId);\n if (!job) {\n return (\n <JobNotFoundState\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n search={search}\n />\n );\n }\n\n const resolvedSelection = resolveWorkflowJobSelection({job, selection: search});\n const selectedJobExecution = resolvedSelection.jobExecution;\n const hasExplicitStep = Boolean(search.stepId && resolvedSelection.step);\n const currentLandingSelection = workflowJobLandingSelection(selectedJobExecution);\n if (selectedJobExecution) {\n const frozenLanding = landingSelectionRef.current;\n if (\n !frozenLanding ||\n frozenLanding.jobId !== job.id ||\n frozenLanding.jobExecutionId !== selectedJobExecution.id\n ) {\n landingSelectionRef.current = {\n jobId: job.id,\n jobExecutionId: selectedJobExecution.id,\n selection: currentLandingSelection,\n hasSelection: currentLandingSelection !== undefined,\n };\n } else if (!frozenLanding.hasSelection && currentLandingSelection) {\n landingSelectionRef.current = {\n ...frozenLanding,\n selection: currentLandingSelection,\n hasSelection: true,\n };\n }\n } else {\n landingSelectionRef.current = undefined;\n }\n const landingSelection = landingSelectionRef.current?.selection;\n const selectedAttemptId = hasExplicitStep ? resolvedSelection.selectedAttemptId : undefined;\n const runningSelection = runningStepSelection(selectedJobExecution);\n const selectedStepId = resolvedSelection.step?.id ?? landingSelection?.stepId;\n const selectedAttemptForNotice = hasExplicitStep\n ? resolvedSelection.selectedAttemptId\n : landingSelection?.attemptId;\n const showRetargetNotice =\n runningSelection !== undefined &&\n (selectedStepId !== runningSelection.stepId ||\n selectedAttemptForNotice !== runningSelection.attemptId);\n const succeededSummary =\n !hasExplicitStep && landingSelection === undefined && selectedJobExecution\n ? jobSucceededSummary(job, selectedJobExecution)\n : undefined;\n\n function selectExecution(jobExecutionId: string) {\n onSelectionChange({\n ...search,\n jobExecutionId,\n stepId: undefined,\n stepAttemptId: undefined,\n });\n }\n\n function selectAttempt(attemptId: string | undefined) {\n if (!selectedJobExecution) return;\n if (!attemptId) {\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: undefined,\n stepAttemptId: undefined,\n });\n return;\n }\n\n const match = findAttempt(selectedJobExecution, attemptId);\n if (!match) return;\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: match.step.id,\n stepAttemptId: match.attemptId,\n });\n }\n\n function retargetToRunningStep() {\n if (!runningSelection || !selectedJobExecution) return;\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: runningSelection.stepId,\n stepAttemptId: runningSelection.attemptId,\n });\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <div ref={rootRef} className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden\">\n {query.isError ? <WorkflowRunStaleError query={query} /> : null}\n {newerJob && newerAttempt && newerAttempt > run.runAttempt.attempt ? (\n <NewerAttemptNotice\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n jobId={newerJob.id}\n attempt={newerAttempt}\n />\n ) : null}\n <div ref={pageScrollRef} className=\"@container min-h-0 flex-1 overflow-auto pb-24\">\n <section\n aria-label={`${job.displayName} logs`}\n className=\"mx-auto flex w-full max-w-[1120px] flex-col gap-8 px-24\"\n >\n <section className=\"min-w-0 overflow-hidden\">\n <JobDetailHeader\n job={job}\n selectedJobExecution={selectedJobExecution}\n onSelectedJobExecutionChange={selectExecution}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={run.runAttempt.attempt}\n annotationSummary={jobAnnotationSummary}\n />\n <Text as=\"h3\" className=\"sr-only\">\n Logs\n </Text>\n {selectedJobExecution ? (\n <StepList\n job={job}\n jobExecution={selectedJobExecution}\n selectedAttemptId={selectedAttemptId}\n defaultSelectedAttemptId={landingSelection?.attemptId}\n onSelectedAttemptChange={selectAttempt}\n autoSelectActiveAttempt\n emptyState={emptyStateForJob(job, selectedJobExecution)}\n showHeader={false}\n className=\"rounded-none border-0\"\n renderExpandedStep={(context) => (\n <ExpandedStep\n context={context}\n workspaceSlug={workspaceSlug}\n pageScrollRef={pageScrollRef}\n />\n )}\n />\n ) : (\n <EmptyStateForMissingExecution job={job} />\n )}\n </section>\n {showRetargetNotice && runningSelection ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"flex min-w-0 items-center justify-between gap-8 rounded-8 border border-border-neutral-base bg-background-components-base px-10 py-8\"\n >\n <Text size=\"xs\" className=\"min-w-0 text-foreground-neutral-muted\">\n Run moved on to{' '}\n <span className=\"font-code text-foreground-neutral-base\">\n {runningSelection.stepLabel}\n </span>\n .\n </Text>\n <button\n type=\"button\"\n className=\"shrink-0 rounded-4 px-6 py-4 text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n onClick={retargetToRunningStep}\n >\n Jump to it\n </button>\n </div>\n ) : null}\n {succeededSummary ? (\n <Text size=\"xs\" className=\"px-8 text-foreground-neutral-muted\">\n {succeededSummary}\n </Text>\n ) : null}\n </section>\n </div>\n </div>\n </TimeTickerProvider>\n );\n}\n\nfunction ExpandedStep({\n context,\n workspaceSlug,\n pageScrollRef,\n}: {\n context: StepExpandedContext;\n workspaceSlug: string;\n pageScrollRef: RefObject<HTMLDivElement | null>;\n}) {\n if (context.carriedOver) return <CarriedOverStepPanel />;\n\n const selectedAttemptError =\n toSelectedAttemptError(context.step, context.attemptError) ?? context.step.error;\n\n return (\n <section\n role=\"region\"\n tabIndex={0}\n aria-label={`${context.stepLabel} output, attempt ${context.attempt}`}\n className=\"flex min-w-0 flex-col gap-10 border-t border-border-neutral-base bg-background-neutral-subtle px-16 py-12 outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n {isAgentConfigFailure(context.step, selectedAttemptError) ? (\n <AgentConfigFailureCallout\n workspaceSlug={workspaceSlug}\n config={context.step.agentConfig}\n error={selectedAttemptError}\n />\n ) : null}\n <StepAttemptLogPanel\n stepId={context.stepId}\n attempt={context.attempt}\n attemptStatus={context.attemptStatus}\n attemptStartedAt={context.attemptStartedAt}\n pageScrollRef={pageScrollRef}\n surfaceClassName=\"rounded-8\"\n />\n </section>\n );\n}\n\nfunction EmptyStateForMissingExecution({job}: {job: Job}) {\n const emptyState = emptyStateForMissingExecution(job);\n return (\n <EmptyState\n className=\"min-h-120 px-16 py-20\"\n icon=\"componentLine\"\n title={emptyState.title}\n description={emptyState.description}\n variant=\"compact\"\n />\n );\n}\n\nfunction JobNotFoundState({\n workspaceSlug,\n projectSlug,\n workflowRunId,\n search,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n search: WorkflowJobSearch;\n}) {\n return (\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col items-center justify-center gap-12 p-24\">\n <EmptyState\n icon=\"componentLine\"\n title=\"Job not found\"\n description=\"This job is not part of the selected workflow run.\"\n />\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n workflowRunSearchParams(\n {runAttempt: search.runAttempt},\n {runAttempt: search.runAttempt},\n ) as never\n }\n className=\"inline-flex items-center gap-6 rounded-6 px-8 py-6 text-sm text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name=\"arrowLeftLine\" size={14} aria-hidden=\"true\" />\n Back to run summary\n </Link>\n </div>\n );\n}\n\nfunction NewerAttemptNotice({\n workspaceSlug,\n projectSlug,\n runId,\n jobId,\n attempt,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n jobId: string;\n attempt: number;\n}) {\n return (\n <div role=\"status\" className=\"border-b border-border-neutral-base px-16 py-8\">\n <div className=\"mx-auto flex max-w-[1120px] items-center justify-between gap-8 rounded-8 border border-border-neutral-base bg-background-components-base px-10 py-8\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n A newer run attempt is available.\n </Text>\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId, jobId}}\n search={workflowJobSearchParams({runAttempt: attempt}) as never}\n className=\"shrink-0 rounded-4 px-6 py-4 text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n View attempt #{attempt}\n </Link>\n </div>\n </div>\n );\n}\n\nfunction runningStepSelection(jobExecution: JobExecution | undefined) {\n if (!jobExecution) return undefined;\n const steps = [...jobExecution.steps].sort(\n (left, right) => left.position - right.position || left.id.localeCompare(right.id),\n );\n for (let stepIndex = steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n const step = steps[stepIndex];\n if (!step) continue;\n const attempt = [...step.attempts]\n .sort((left, right) => left.attempt - right.attempt || left.id.localeCompare(right.id))\n .reverse()\n .find((candidate) => candidate.status === 'running');\n if (attempt)\n return {stepId: step.id, attemptId: attempt.id, stepLabel: step.name || step.key || step.id};\n }\n return undefined;\n}\n\nfunction findAttempt(jobExecution: JobExecution, attemptId: string) {\n for (const step of jobExecution.steps) {\n const attempt = step.attempts.find((candidate) => candidate.id === attemptId);\n if (attempt) return {step, attemptId: attempt.id};\n }\n return undefined;\n}\n\nfunction JobDetailSkeleton() {\n return (\n <div className=\"min-h-0 min-w-0 flex-1 overflow-auto px-24 pb-24\">\n <div className=\"mx-auto max-w-[1120px] overflow-hidden\">\n <header className=\"flex items-center gap-12 border-b border-border-neutral-base px-16 py-12\">\n <Skeleton className=\"size-20 rounded-full\" />\n <Skeleton className=\"h-20 w-160 rounded-4\" />\n <Skeleton className=\"h-24 w-72 rounded-6\" />\n <Skeleton className=\"h-24 w-180 rounded-4\" />\n </header>\n <div className=\"p-16\">\n {JOB_DETAIL_SKELETON_ROWS.map((row) => (\n <div\n key={row}\n className=\"flex min-h-44 items-center gap-8 border-b border-border-neutral-base last:border-b-0\"\n >\n <Skeleton className=\"size-14 rounded-full\" />\n <Skeleton className=\"h-16 w-180 rounded-4\" />\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nconst JOB_DETAIL_SKELETON_ROWS = ['step-1', 'step-2', 'step-3', 'step-4', 'step-5'];\n\ninterface FrozenLandingSelection {\n jobId: string;\n jobExecutionId: string;\n selection: WorkflowJobLandingSelection | undefined;\n hasSelection: boolean;\n}\n"],"names":["ApiError","QueryLoadError","EmptyState","Icon","Skeleton","TimeTickerProvider","Text","Link","useEffect","useRef","summarizeJobAnnotations","useRunAnnotationsQuery","workflowJobSearchParams","workflowRunSearchParams","StepList","WorkflowRunNotFound","WorkflowRunStaleError","AgentConfigFailureCallout","JobDetailHeader","CarriedOverStepPanel","emptyStateForJob","emptyStateForMissingExecution","isAgentConfigFailure","jobSucceededSummary","toSelectedAttemptError","resolveWorkflowJobSelection","workflowJobLandingSelection","StepAttemptLogPanel","JobDetailView","workspaceSlug","projectSlug","workflowRunId","jobId","search","query","newerAttempt","newerJob","onSelectionChange","rootRef","pageScrollRef","landingSelectionRef","undefined","hasLoadedData","data","annotations","runAttempt","attempt","jobAnnotationSummary","truncated","summary","heading","current","querySelector","focus","preventScroll","isPending","JobDetailSkeleton","isError","error","status","subject","icon","run","job","jobs","find","candidate","id","JobNotFoundState","resolvedSelection","selection","selectedJobExecution","jobExecution","hasExplicitStep","Boolean","stepId","step","currentLandingSelection","frozenLanding","jobExecutionId","hasSelection","landingSelection","selectedAttemptId","runningSelection","runningStepSelection","selectedStepId","selectedAttemptForNotice","attemptId","showRetargetNotice","succeededSummary","selectExecution","stepAttemptId","selectAttempt","match","findAttempt","retargetToRunningStep","intervalMs","reducedMotionIntervalMs","div","ref","className","NewerAttemptNotice","runId","section","aria-label","displayName","onSelectedJobExecutionChange","annotationSummary","as","defaultSelectedAttemptId","onSelectedAttemptChange","autoSelectActiveAttempt","emptyState","showHeader","renderExpandedStep","context","ExpandedStep","EmptyStateForMissingExecution","role","aria-live","size","span","stepLabel","button","type","onClick","carriedOver","selectedAttemptError","attemptError","tabIndex","config","agentConfig","attemptStatus","attemptStartedAt","surfaceClassName","title","description","variant","to","params","name","aria-hidden","steps","sort","left","right","position","localeCompare","stepIndex","length","attempts","reverse","key","header","JOB_DETAIL_SKELETON_ROWS","map","row"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/job-detail/job-detail-view.tsx"],"sourcesContent":["// biome-ignore-all lint/a11y/noRedundantRoles: the job log region keeps an explicit role for the public accessibility contract.\n// biome-ignore-all lint/a11y/noNoninteractiveTabindex: the job log region is intentionally keyboard focusable.\n\nimport {ApiError} from '@shipfox/client-api';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\nimport {type RefObject, useEffect, useRef, useState} from 'react';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {summarizeJobAnnotations} from '#core/run-annotation.js';\nimport {isWorkflowRunTerminal, type Job, type JobExecution} from '#core/workflow-run.js';\nimport {useWorkflowRunAnnotationSummaryQuery} from '#hooks/api/annotations.js';\nimport {useRunAnnotationsQuery} from '#hooks/api/run-annotations.js';\nimport type {useWorkflowRunAttemptQuery} from '#hooks/api/workflow-runs.js';\nimport {\n type WorkflowJobSearch,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {type StepExpandedContext, StepList} from '../step-list/index.js';\nimport {\n WorkflowRunNotFound,\n WorkflowRunStaleError,\n} from '../workflow-run-view/workflow-run-states.js';\nimport {JobContextPanel} from './job-context-panel.js';\nimport {JobDetailHeader} from './job-detail-header.js';\nimport {\n CarriedOverStepPanel,\n emptyStateForJob,\n emptyStateForMissingExecution,\n jobSucceededSummary,\n MaterializedOutputFailureNotice,\n} from './job-empty-states.js';\nimport {\n resolveWorkflowJobSelection,\n type WorkflowJobLandingSelection,\n workflowJobLandingSelection,\n} from './job-selection.js';\nimport {StepAttemptLogPanel} from './step-attempt-log-panel.js';\nimport {StepInspectorSheet} from './step-troubleshooting.js';\n\ntype InspectorState = {key: string; attemptId: string | null};\n\nexport interface JobDetailViewProps {\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n jobId: string;\n search: WorkflowJobSearch;\n query: ReturnType<typeof useWorkflowRunAttemptQuery>;\n newerAttempt?: number | undefined;\n newerJob?: Job | undefined;\n onSelectionChange: (selection: WorkflowJobSearch) => void;\n}\n\nexport function JobDetailView({\n workspaceSlug,\n projectSlug,\n workflowRunId,\n jobId,\n search,\n query,\n newerAttempt,\n newerJob,\n onSelectionChange,\n}: JobDetailViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const pageScrollRef = useRef<HTMLDivElement>(null);\n const landingSelectionRef = useRef<FrozenLandingSelection | undefined>(undefined);\n const hasLoadedData = query.data !== undefined;\n // Reuse the run workspace's bounded annotation read for the job header chip. The separate\n // summary query below stays counts-only and is scoped to the inspector's selected execution.\n const annotations = useRunAnnotationsQuery({\n workflowRunId,\n runAttempt: query.data?.runAttempt.attempt,\n });\n const jobAnnotationSummary = annotations.annotations\n ? summarizeJobAnnotations(annotations.annotations, jobId, {\n truncated: annotations.summary?.truncated ?? false,\n })\n : undefined;\n const inspectorResetKey = `${jobId}:${search.jobExecutionId ?? ''}`;\n const [inspectorState, setInspectorState] = useState<InspectorState>(() => ({\n key: inspectorResetKey,\n attemptId: null,\n }));\n const inspectorOpenAttemptId =\n inspectorState.key === inspectorResetKey ? inspectorState.attemptId : null;\n const annotationJob = query.data?.jobs.find((candidate) => candidate.id === jobId);\n const annotationExecutionId = annotationJob\n ? resolveWorkflowJobSelection({job: annotationJob, selection: search}).jobExecution?.id\n : search.jobExecutionId;\n const annotationPolling = query.data\n ? !isWorkflowRunTerminal(query.data.runAttempt.status)\n : true;\n const annotationSummaryQuery = useWorkflowRunAnnotationSummaryQuery(\n query.data?.id,\n query.data?.runAttempt.attempt,\n annotationExecutionId,\n {polling: annotationPolling},\n );\n\n useEffect(() => {\n if (!jobId || !hasLoadedData) return;\n const heading = rootRef.current?.querySelector<HTMLElement>('[data-job-heading]');\n // The heading is intentionally the route-change focus target: it announces the new job\n // after rail navigation without putting focus on a decorative status element.\n heading?.focus({preventScroll: true});\n }, [hasLoadedData, jobId]);\n\n if (query.isPending) return <JobDetailSkeleton />;\n\n if (query.isError && query.data === undefined) {\n if (query.error instanceof ApiError && query.error.status === 404) {\n return <WorkflowRunNotFound />;\n }\n return <QueryLoadError query={query} subject=\"workflow run\" icon=\"pulseLine\" />;\n }\n\n if (query.data === undefined) return <JobDetailSkeleton />;\n\n const run = query.data;\n const job = run.jobs.find((candidate) => candidate.id === jobId);\n if (!job) {\n return (\n <JobNotFoundState\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n search={search}\n />\n );\n }\n\n const resolvedSelection = resolveWorkflowJobSelection({job, selection: search});\n const selectedJobExecution = resolvedSelection.jobExecution;\n const hasExplicitStep = Boolean(search.stepId && resolvedSelection.step);\n const currentLandingSelection = workflowJobLandingSelection(selectedJobExecution);\n if (selectedJobExecution) {\n const frozenLanding = landingSelectionRef.current;\n if (\n !frozenLanding ||\n frozenLanding.jobId !== job.id ||\n frozenLanding.jobExecutionId !== selectedJobExecution.id\n ) {\n landingSelectionRef.current = {\n jobId: job.id,\n jobExecutionId: selectedJobExecution.id,\n selection: currentLandingSelection,\n hasSelection: currentLandingSelection !== undefined,\n };\n } else if (!frozenLanding.hasSelection && currentLandingSelection) {\n landingSelectionRef.current = {\n ...frozenLanding,\n selection: currentLandingSelection,\n hasSelection: true,\n };\n }\n } else {\n landingSelectionRef.current = undefined;\n }\n const landingSelection = landingSelectionRef.current?.selection;\n const selectedAttemptId = hasExplicitStep ? resolvedSelection.selectedAttemptId : undefined;\n const runningSelection = runningStepSelection(selectedJobExecution);\n const selectedStepId = resolvedSelection.step?.id ?? landingSelection?.stepId;\n const selectedAttemptForNotice = hasExplicitStep\n ? resolvedSelection.selectedAttemptId\n : landingSelection?.attemptId;\n const showRetargetNotice =\n runningSelection !== undefined &&\n (selectedStepId !== runningSelection.stepId ||\n selectedAttemptForNotice !== runningSelection.attemptId);\n const succeededSummary =\n !hasExplicitStep && landingSelection === undefined && selectedJobExecution\n ? jobSucceededSummary(job, selectedJobExecution)\n : undefined;\n\n function selectExecution(jobExecutionId: string) {\n onSelectionChange({\n ...search,\n jobExecutionId,\n stepId: undefined,\n stepAttemptId: undefined,\n });\n }\n\n function selectAttempt(attemptId: string | undefined) {\n if (!selectedJobExecution) return;\n if (!attemptId) {\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: undefined,\n stepAttemptId: undefined,\n });\n return;\n }\n\n const match = findAttempt(selectedJobExecution, attemptId);\n if (!match) return;\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: match.step.id,\n stepAttemptId: match.attemptId,\n });\n }\n\n function onInspectorOpenChange(attemptId: string | null) {\n setInspectorState({key: inspectorResetKey, attemptId});\n }\n\n function retargetToRunningStep() {\n if (!runningSelection || !selectedJobExecution) return;\n onSelectionChange({\n ...search,\n jobExecutionId: selectedJobExecution.id,\n stepId: runningSelection.stepId,\n stepAttemptId: runningSelection.attemptId,\n });\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <div ref={rootRef} className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden\">\n {query.isError ? <WorkflowRunStaleError query={query} /> : null}\n {newerJob && newerAttempt && newerAttempt > run.runAttempt.attempt ? (\n <NewerAttemptNotice\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n jobId={newerJob.id}\n attempt={newerAttempt}\n />\n ) : null}\n <div ref={pageScrollRef} className=\"@container min-h-0 flex-1 overflow-auto pb-panel\">\n <section aria-label={`${job.displayName} logs`} className=\"flex w-full flex-col\">\n <section className=\"min-w-0 overflow-hidden\">\n <JobDetailHeader\n job={job}\n selectedJobExecution={selectedJobExecution}\n onSelectedJobExecutionChange={selectExecution}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n runAttempt={run.runAttempt.attempt}\n annotationSummary={jobAnnotationSummary}\n jobContext={\n selectedJobExecution ? (\n <JobContextPanel job={job} execution={selectedJobExecution} />\n ) : undefined\n }\n />\n <Text as=\"h2\" className=\"sr-only\">\n Logs\n </Text>\n {selectedJobExecution ? (\n <>\n <MaterializedOutputFailureNotice jobExecution={selectedJobExecution} />\n <StepList\n job={job}\n jobExecution={selectedJobExecution}\n selectedAttemptId={selectedAttemptId}\n defaultSelectedAttemptId={landingSelection?.attemptId}\n onSelectedAttemptChange={selectAttempt}\n inspectorOpenAttemptId={inspectorOpenAttemptId}\n onInspectorOpenChange={onInspectorOpenChange}\n autoSelectActiveAttempt\n emptyState={emptyStateForJob(job, selectedJobExecution)}\n showHeader={false}\n className=\"rounded-none border-0 bg-transparent\"\n renderExpandedStep={(context) => (\n <ExpandedStep context={context} pageScrollRef={pageScrollRef} />\n )}\n renderInspector={(entry) => (\n <StepInspectorSheet\n entry={entry}\n open\n onOpenChange={(open) => onInspectorOpenChange(open ? entry.id : null)}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={run.id}\n runAttempt={run.runAttempt.attempt}\n jobId={job.id}\n annotationCount={annotationCountForStep(\n annotationSummaryQuery.data,\n entry.step.id,\n entry.attempt,\n )}\n />\n )}\n />\n </>\n ) : (\n <EmptyStateForMissingExecution job={job} />\n )}\n </section>\n {showRetargetNotice && runningSelection ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"flex min-w-0 items-center justify-between gap-inline border-t border-border-neutral-base px-row py-row\"\n >\n <Text size=\"xs\" className=\"min-w-0 text-foreground-neutral-muted\">\n Run moved on to{' '}\n <span className=\"font-code text-foreground-neutral-base\">\n {runningSelection.stepLabel}\n </span>\n .\n </Text>\n <button\n type=\"button\"\n className=\"shrink-0 rounded-4 px-tight py-[4px] text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n onClick={retargetToRunningStep}\n >\n Jump to it\n </button>\n </div>\n ) : null}\n {succeededSummary ? (\n <Text size=\"xs\" className=\"px-row py-row text-foreground-neutral-muted\">\n {succeededSummary}\n </Text>\n ) : null}\n </section>\n </div>\n </div>\n </TimeTickerProvider>\n );\n}\n\nfunction ExpandedStep({\n context,\n pageScrollRef,\n}: {\n context: StepExpandedContext;\n pageScrollRef: RefObject<HTMLDivElement | null>;\n}) {\n if (context.carriedOver) return <CarriedOverStepPanel />;\n\n return (\n <section\n role=\"region\"\n tabIndex={0}\n aria-label={`${context.stepLabel} output, attempt ${context.attempt}`}\n className=\"flex min-w-0 flex-col border-t border-border-neutral-base bg-background-neutral-base outline-none focus-visible:shadow-border-interactive-with-active dark:bg-background-contrast-subtle\"\n >\n <StepAttemptLogPanel\n stepId={context.stepId}\n attempt={context.attempt}\n attemptStatus={context.attemptStatus}\n attemptStartedAt={context.attemptStartedAt}\n pageScrollRef={pageScrollRef}\n surfaceClassName=\"rounded-none border-0 bg-transparent shadow-none\"\n />\n </section>\n );\n}\n\nfunction EmptyStateForMissingExecution({job}: {job: Job}) {\n const emptyState = emptyStateForMissingExecution(job);\n return (\n <EmptyState\n className=\"min-h-120 p-panel\"\n icon=\"componentLine\"\n title={emptyState.title}\n description={emptyState.description}\n variant=\"compact\"\n />\n );\n}\n\nfunction JobNotFoundState({\n workspaceSlug,\n projectSlug,\n workflowRunId,\n search,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n search: WorkflowJobSearch;\n}) {\n return (\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col items-center justify-center gap-cluster p-panel\">\n <EmptyState\n icon=\"componentLine\"\n title=\"Job not found\"\n description=\"This job is not part of the selected workflow run.\"\n />\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n workflowRunSearchParams(\n {runAttempt: search.runAttempt},\n {runAttempt: search.runAttempt},\n ) as never\n }\n className=\"inline-flex items-center gap-inline rounded-6 px-tight py-[6px] text-sm text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name=\"arrowLeftLine\" size={14} aria-hidden=\"true\" />\n Back to run summary\n </Link>\n </div>\n );\n}\n\nfunction NewerAttemptNotice({\n workspaceSlug,\n projectSlug,\n runId,\n jobId,\n attempt,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n jobId: string;\n attempt: number;\n}) {\n return (\n <div role=\"status\" className=\"border-b border-border-neutral-base px-row py-row\">\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n A newer run attempt is available.\n </Text>\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId, jobId}}\n search={workflowJobSearchParams({runAttempt: attempt}) as never}\n className=\"shrink-0 rounded-4 px-tight py-[4px] text-xs font-medium text-foreground-highlight-interactive outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n View attempt #{attempt}\n </Link>\n </div>\n </div>\n );\n}\n\nfunction runningStepSelection(jobExecution: JobExecution | undefined) {\n if (!jobExecution) return undefined;\n const steps = [...jobExecution.steps].sort(\n (left, right) => left.position - right.position || left.id.localeCompare(right.id),\n );\n for (let stepIndex = steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n const step = steps[stepIndex];\n if (!step) continue;\n const attempt = [...step.attempts]\n .sort((left, right) => left.attempt - right.attempt || left.id.localeCompare(right.id))\n .reverse()\n .find((candidate) => candidate.status === 'running');\n if (attempt)\n return {stepId: step.id, attemptId: attempt.id, stepLabel: step.name || step.key || step.id};\n }\n return undefined;\n}\n\nfunction findAttempt(jobExecution: JobExecution, attemptId: string) {\n for (const step of jobExecution.steps) {\n const attempt = step.attempts.find((candidate) => candidate.id === attemptId);\n if (attempt) return {step, attemptId: attempt.id};\n }\n return undefined;\n}\n\nfunction annotationCountForStep(\n summary: RunAnnotationSummary | undefined,\n stepId: string,\n attempt: number,\n): number | undefined {\n return summary?.stepCounts?.find((entry) => entry.stepId === stepId && entry.attempt === attempt)\n ?.total;\n}\n\nfunction JobDetailSkeleton() {\n return (\n <div className=\"min-h-0 min-w-0 flex-1 overflow-auto pb-panel\">\n <div className=\"w-full\">\n <header className=\"flex items-center gap-cluster border-b border-border-neutral-base px-row py-row\">\n <Skeleton className=\"size-20 rounded-full\" />\n <Skeleton className=\"h-20 w-160 rounded-4\" />\n <Skeleton className=\"h-24 w-72 rounded-6\" />\n <Skeleton className=\"h-24 w-180 rounded-4\" />\n </header>\n <div className=\"p-panel-compact\">\n {JOB_DETAIL_SKELETON_ROWS.map((row) => (\n <div\n key={row}\n className=\"flex min-h-44 items-center gap-inline border-b border-border-neutral-base last:border-b-0\"\n >\n <Skeleton className=\"size-14 rounded-full\" />\n <Skeleton className=\"h-16 w-180 rounded-4\" />\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nconst JOB_DETAIL_SKELETON_ROWS = ['step-1', 'step-2', 'step-3', 'step-4', 'step-5'];\n\ninterface FrozenLandingSelection {\n jobId: string;\n jobExecutionId: string;\n selection: WorkflowJobLandingSelection | undefined;\n hasSelection: boolean;\n}\n"],"names":["ApiError","QueryLoadError","EmptyState","Icon","Skeleton","TimeTickerProvider","Text","Link","useEffect","useRef","useState","summarizeJobAnnotations","isWorkflowRunTerminal","useWorkflowRunAnnotationSummaryQuery","useRunAnnotationsQuery","workflowJobSearchParams","workflowRunSearchParams","StepList","WorkflowRunNotFound","WorkflowRunStaleError","JobContextPanel","JobDetailHeader","CarriedOverStepPanel","emptyStateForJob","emptyStateForMissingExecution","jobSucceededSummary","MaterializedOutputFailureNotice","resolveWorkflowJobSelection","workflowJobLandingSelection","StepAttemptLogPanel","StepInspectorSheet","JobDetailView","workspaceSlug","projectSlug","workflowRunId","jobId","search","query","newerAttempt","newerJob","onSelectionChange","rootRef","pageScrollRef","landingSelectionRef","undefined","hasLoadedData","data","annotations","runAttempt","attempt","jobAnnotationSummary","truncated","summary","inspectorResetKey","jobExecutionId","inspectorState","setInspectorState","key","attemptId","inspectorOpenAttemptId","annotationJob","jobs","find","candidate","id","annotationExecutionId","job","selection","jobExecution","annotationPolling","status","annotationSummaryQuery","polling","heading","current","querySelector","focus","preventScroll","isPending","JobDetailSkeleton","isError","error","subject","icon","run","JobNotFoundState","resolvedSelection","selectedJobExecution","hasExplicitStep","Boolean","stepId","step","currentLandingSelection","frozenLanding","hasSelection","landingSelection","selectedAttemptId","runningSelection","runningStepSelection","selectedStepId","selectedAttemptForNotice","showRetargetNotice","succeededSummary","selectExecution","stepAttemptId","selectAttempt","match","findAttempt","onInspectorOpenChange","retargetToRunningStep","intervalMs","reducedMotionIntervalMs","div","ref","className","NewerAttemptNotice","runId","section","aria-label","displayName","onSelectedJobExecutionChange","annotationSummary","jobContext","execution","as","defaultSelectedAttemptId","onSelectedAttemptChange","autoSelectActiveAttempt","emptyState","showHeader","renderExpandedStep","context","ExpandedStep","renderInspector","entry","open","onOpenChange","annotationCount","annotationCountForStep","EmptyStateForMissingExecution","role","aria-live","size","span","stepLabel","button","type","onClick","carriedOver","tabIndex","attemptStatus","attemptStartedAt","surfaceClassName","title","description","variant","to","params","name","aria-hidden","steps","sort","left","right","position","localeCompare","stepIndex","length","attempts","reverse","stepCounts","total","header","JOB_DETAIL_SKELETON_ROWS","map","row"],"mappings":"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"}
@@ -1,5 +1,9 @@
1
1
  import type { Job, JobExecution, Step, StepError } from '#core/workflow-run.js';
2
2
  import type { StepListEmptyState } from '../step-list/index.js';
3
+ export declare function outputFailureDescriptionForExecution(jobExecution: JobExecution): string | undefined;
4
+ export declare function MaterializedOutputFailureNotice({ jobExecution }: {
5
+ jobExecution: JobExecution;
6
+ }): import("react").JSX.Element | null;
3
7
  export declare function emptyStateForJob(job: Job, jobExecution: JobExecution): StepListEmptyState | undefined;
4
8
  export declare function emptyStateForMissingExecution(job: Job): StepListEmptyState;
5
9
  export declare function skippedJobDescription(reason: Job['statusReason']): string;
@@ -1 +1 @@
1
- {"version":3,"file":"job-empty-states.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-empty-states.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAO9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAG9D,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,YAAY,GACzB,kBAAkB,GAAG,SAAS,CA+DhC;AAED,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CAsD1E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,MAAM,CAoBzE;AAiCD,wBAAgB,oBAAoB,gCAUnC;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,SAAS,GAAG,IAAI,CAgClB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAEjF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAMzF"}
1
+ {"version":3,"file":"job-empty-states.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-empty-states.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAO9E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAQ9D,wBAAgB,oCAAoC,CAClD,YAAY,EAAE,YAAY,GACzB,MAAM,GAAG,SAAS,CAUpB;AAED,wBAAgB,+BAA+B,CAAC,EAAC,YAAY,EAAC,EAAE;IAAC,YAAY,EAAE,YAAY,CAAA;CAAC,sCAiB3F;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,YAAY,GACzB,kBAAkB,GAAG,SAAS,CAsEhC;AAED,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CA8D1E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,MAAM,CAuBzE;AA2CD,wBAAgB,oBAAoB,gCAUnC;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,SAAS,GAAG,IAAI,CAgClB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAEjF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAMzF"}