@shipfox/client-workflows 17.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 (43) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-type.log +0 -1
  3. package/CHANGELOG.md +12 -0
  4. package/dist/components/job-detail/job-context-panel.d.ts.map +1 -1
  5. package/dist/components/job-detail/job-context-panel.js +5 -1
  6. package/dist/components/job-detail/job-context-panel.js.map +1 -1
  7. package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
  8. package/dist/components/job-detail/job-detail-view.js +34 -27
  9. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  10. package/dist/components/job-detail/job-empty-states.d.ts +4 -0
  11. package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
  12. package/dist/components/job-detail/job-empty-states.js +43 -3
  13. package/dist/components/job-detail/job-empty-states.js.map +1 -1
  14. package/dist/components/job-detail/step-troubleshooting.js +4 -0
  15. package/dist/components/job-detail/step-troubleshooting.js.map +1 -1
  16. package/dist/components/step-list/step-list-model.d.ts.map +1 -1
  17. package/dist/components/step-list/step-list-model.js +1 -0
  18. package/dist/components/step-list/step-list-model.js.map +1 -1
  19. package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
  20. package/dist/components/workflow-run-view/run-workspace-nav.js +6 -5
  21. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  22. package/dist/core/entities/job-execution.d.ts +2 -0
  23. package/dist/core/entities/job-execution.d.ts.map +1 -1
  24. package/dist/core/entities/job-execution.js.map +1 -1
  25. package/dist/core/entities/job.d.ts +1 -1
  26. package/dist/core/entities/job.d.ts.map +1 -1
  27. package/dist/core/entities/job.js.map +1 -1
  28. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  29. package/dist/hooks/api/workflow-run-mapper.js +1 -0
  30. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  31. package/dist/tsconfig.test.tsbuildinfo +1 -1
  32. package/package.json +2 -2
  33. package/src/components/job-detail/job-context-panel.tsx +4 -0
  34. package/src/components/job-detail/job-detail-view.tsx +37 -33
  35. package/src/components/job-detail/job-empty-states.test.ts +105 -1
  36. package/src/components/job-detail/job-empty-states.tsx +56 -2
  37. package/src/components/job-detail/step-troubleshooting.tsx +4 -0
  38. package/src/components/step-list/step-list-model.ts +1 -0
  39. package/src/components/workflow-run-view/run-workspace-nav.tsx +13 -6
  40. package/src/core/entities/job-execution.ts +2 -0
  41. package/src/core/entities/job.ts +3 -1
  42. package/src/hooks/api/workflow-run-mapper.ts +1 -0
  43. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-detail/step-troubleshooting.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout, CalloutContent, CalloutDescription, CalloutTitle} from '@shipfox/react-ui/callout';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport type {ReactNode} from 'react';\nimport type {\n EvaluationTraceEntry,\n JobStatusReason,\n Step,\n StepAttempt,\n StepError,\n} from '#core/workflow-run.js';\nimport {useStepAttemptDetailQuery} from '#hooks/api/step-attempt-detail.js';\nimport {workflowRunSearchParams} from '#routes/inputs.js';\nimport {humanizeStatus, type StepListEntryModel} from '../step-list/step-list-model.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {toSelectedAttemptError} from './job-empty-states.js';\nimport {JsonCode, type JsonCodeEntry, JsonCodeTabs} from './json-code.js';\n\nexport interface StepInspectorSheetProps {\n entry: StepListEntryModel;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount?: number | undefined;\n}\n\nexport function StepInspectorSheet({\n entry,\n open,\n onOpenChange,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: StepInspectorSheetProps) {\n const error = selectedStepError(entry.step, entry.error);\n const inspectorQuery = useStepAttemptDetailQuery(entry.step.id, entry.attempt, {\n enabled: open,\n });\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"w-full sm:max-w-[560px]\">\n <SheetHeader>\n <SheetTitle>{entry.step.label}</SheetTitle>\n <SheetDescription>\n Attempt #{entry.attempt} · {humanizeStatus(entry.statusVisual.kind)}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-section\">\n <StepInspector\n step={entry.step}\n attempt={entry}\n error={error}\n showFailure={entry.statusVisual.kind === 'failed' || entry.error !== null}\n query={inspectorQuery}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n jobId={jobId}\n annotationCount={annotationCount}\n />\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction StepFailureCallout({\n step,\n attempt,\n error,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n}) {\n const reason = error?.reason ?? step.statusReason ?? 'unknown';\n const title = failureTitle(reason);\n const sourceLink = sourceLinkForFailure(reason) && step.sourceLocation;\n\n if (step.type === 'agent' && reason === 'agent_config_invalid') {\n return (\n <AgentConfigFailureCallout\n workspaceSlug={workspaceSlug}\n config={step.agentConfig}\n error={error}\n />\n );\n }\n\n return (\n <Callout\n role=\"alert\"\n type=\"error\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-error-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>{title}</CalloutTitle>\n <CalloutDescription>\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-inline gap-y-tight\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <span>{failureDescription(reason)}</span>\n {error?.message ? (\n <span className=\"text-foreground-neutral-muted\">{error.message}</span>\n ) : null}\n </div>\n <Code as=\"span\" variant=\"label\" className=\"text-tag-error-text\">\n {reason}\n </Code>\n {sourceLink ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n workflowRunSearchParams(\n {tab: 'source'},\n {stepId: step.id, stepAttemptId: attempt.id, runAttempt},\n ) as never\n }\n className=\"font-medium text-foreground-highlight-interactive underline-offset-2 hover:underline\"\n >\n View in source\n </Link>\n ) : null}\n </div>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n );\n}\n\nfunction StepInspector({\n step,\n attempt,\n error,\n showFailure,\n query,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n showFailure: boolean;\n query: ReturnType<typeof useStepAttemptDetailQuery>;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount: number | undefined;\n}) {\n const detail = query.data;\n const trace = detail?.evaluationTrace ?? null;\n const resolvedConfig = detail?.config ?? null;\n const hasInputs =\n detail !== undefined &&\n (countConfigValues(detail.authoredConfig) > 0 || countConfigValues(resolvedConfig) > 0);\n const hasOutputs =\n attempt.outputs !== null || attempt.output !== null || attempt.response !== null;\n const hasTrace = trace !== null && trace.length > 0;\n const hasAnnotations = annotationCount !== undefined && annotationCount > 0;\n const detailCount = Number(hasInputs) + Number(hasOutputs) + Number(hasTrace);\n\n return (\n <div className=\"flex min-w-0 flex-col gap-section\">\n {showFailure ? (\n <StepFailureCallout\n step={step}\n attempt={attempt}\n error={error}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n />\n ) : null}\n {query.isPending ? <InspectorLoading /> : null}\n {query.isError ? (\n <Callout\n role=\"alert\"\n type=\"warning\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-warning-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>Details unavailable</CalloutTitle>\n <CalloutDescription className=\"flex items-center justify-between gap-inline\">\n <span>We could not load the resolved configuration for this attempt.</span>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n onClick={() => void query.refetch()}\n >\n Retry\n </Button>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n ) : null}\n {detail ? (\n <div className=\"flex min-w-0 flex-col gap-group\">\n {hasInputs ? (\n <InspectorSection title=\"Inputs\">\n <ConfigCode authoredConfig={detail.authoredConfig} resolvedConfig={resolvedConfig} />\n </InspectorSection>\n ) : null}\n {hasOutputs ? (\n <InspectorSection title=\"Outputs\">\n {attempt.outputs !== null || attempt.output !== null ? (\n <JsonCode\n value={attempt.outputs ?? attempt.output ?? {}}\n emptyMessage=\"No outputs declared; the `outputs:` mapping is empty.\"\n />\n ) : null}\n {attempt.response !== null ? (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Response\n </Text>\n <pre className=\"max-h-160 min-w-0 overflow-auto rounded-6 border border-border-neutral-base bg-background-neutral-subtle p-tight font-code text-xs leading-18 text-foreground-neutral-muted scrollbar\">\n {attempt.response}\n </pre>\n </div>\n ) : null}\n </InspectorSection>\n ) : null}\n {hasTrace ? (\n <InspectorSection title=\"Evaluation\">\n <EvaluationTrace trace={trace ?? []} />\n </InspectorSection>\n ) : null}\n {detailCount === 0 && !showFailure && !hasAnnotations ? <EmptyInspector /> : null}\n </div>\n ) : null}\n {hasAnnotations ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={workflowRunSearchParams({tab: 'annotations'}, {jobId, runAttempt}) as never}\n className=\"inline-flex w-fit rounded-4 text-xs text-foreground-highlight-interactive underline-offset-2 hover:underline focus-visible:shadow-button-neutral-focus\"\n >\n View {annotationCount} annotation{annotationCount === 1 ? '' : 's'}\n </Link>\n ) : null}\n {!query.isPending && !query.isError && !detail && !showFailure && !hasAnnotations ? (\n <EmptyInspector />\n ) : null}\n </div>\n );\n}\n\nfunction InspectorSection({title, children}: {title: string; children: ReactNode}) {\n return (\n <section className=\"flex min-w-0 flex-col gap-inline\" aria-label={title}>\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {title}\n </Text>\n {children}\n </section>\n );\n}\n\nfunction ConfigCode({\n authoredConfig,\n resolvedConfig,\n}: {\n authoredConfig: Record<string, unknown> | null;\n resolvedConfig: Record<string, unknown> | null;\n}) {\n const entries: JsonCodeEntry[] = [\n ...(authoredConfig\n ? [\n {\n filename: 'authored.json',\n label: 'Authored configuration',\n value: authoredConfig,\n },\n ]\n : []),\n ...(resolvedConfig\n ? [\n {\n filename: 'resolved.json',\n label: 'Resolved configuration',\n value: resolvedConfig,\n },\n ]\n : []),\n ];\n\n if (entries.length === 0) return null;\n return <JsonCodeTabs entries={entries} />;\n}\n\nexport function EvaluationTrace({trace}: {trace: readonly EvaluationTraceEntry[]}) {\n const keyCounts = new Map<string, number>();\n\n return (\n <dl className=\"flex min-w-0 flex-col divide-y divide-border-neutral-base rounded-6 border border-border-neutral-base\">\n {trace.map((entry) => {\n if ('dropped' in entry) {\n const keyBase = `limit-${entry.dropped}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className=\"px-row py-row text-xs text-foreground-neutral-muted\"\n >\n {entry.dropped} more evaluation{entry.dropped === 1 ? '' : 's'} not recorded\n </div>\n );\n }\n\n const empty = entry.value === undefined || entry.value === '';\n const keyBase = `evaluation-${entry.field}-${entry.expression}-${entry.evaluatedAt}-${entry.fillTarget}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className={cn(\n 'grid min-w-0 grid-cols-1 gap-inline px-row py-row min-[768px]:grid-cols-[160px_minmax(0,1fr)]',\n entry.degraded && 'border-l border-tag-error-icon',\n )}\n >\n <dt\n className=\"flex min-w-0 flex-col gap-tight font-code text-xs text-foreground-neutral-muted\"\n title={entry.field}\n >\n <span className=\"block truncate\">{entry.field}</span>\n <span className=\"block break-all text-foreground-neutral-subtle\">\n {entry.expression}\n </span>\n </dt>\n <dd className=\"flex min-w-0 flex-col gap-tight text-xs text-foreground-neutral-base\">\n {entry.degraded ? <span className=\"sr-only\">Degraded evaluation</span> : null}\n <div className=\"break-words font-code\">\n {empty ? <span className=\"text-tag-error-text\">(empty)</span> : entry.value}\n </div>\n <div className=\"flex min-w-0 flex-wrap gap-x-inline gap-y-tight text-foreground-neutral-muted\">\n {entry.degraded ? <span className=\"text-tag-error-text\">degraded</span> : null}\n {entry.truncated || entry.exprTruncated ? <span>truncated</span> : null}\n </div>\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n\nfunction InspectorLoading() {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading troubleshooting details\"\n className=\"flex flex-col gap-inline\"\n >\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-120 w-full\" />\n </div>\n );\n}\n\nfunction EmptyInspector() {\n return (\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n No additional troubleshooting details were recorded.\n </Text>\n );\n}\n\nfunction selectedStepError(\n step: Step,\n attemptError: Record<string, unknown> | null,\n): StepError | null {\n return toSelectedAttemptError(step, attemptError) ?? step.error;\n}\n\nfunction failureTitle(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_failed':\n return 'Checkout failed';\n case 'checkout_auth_failed':\n return 'Checkout authentication failed';\n case 'checkout_unavailable':\n return 'Checkout service unavailable';\n case 'checkout_path_invalid':\n return 'Checkout path is invalid';\n case 'checkout_destination_occupied':\n return 'Checkout destination is already occupied';\n case 'git_unavailable':\n return 'Git was unavailable';\n case 'workspace_prep_failed':\n return 'Workspace preparation failed';\n case 'setup_aborted':\n return 'Step setup was aborted';\n case 'config_unresolvable':\n return 'Step configuration could not be resolved';\n case 'output_invalid':\n return 'Step output was invalid';\n case 'agent_config_invalid':\n return 'Agent configuration is invalid';\n case 'agent_invocation_failed':\n return 'Agent invocation failed';\n case 'agent_harness_unavailable':\n return 'Agent harness was unavailable';\n case 'runner_lost':\n return 'Runner stopped responding';\n case 'timed_out':\n return 'Step timed out';\n case 'step_failed':\n return 'A step failed';\n case 'dependency_not_completed':\n return 'A dependency did not complete';\n case 'condition_false':\n return 'The job condition was false';\n case 'default_gate_rejected':\n return 'The default gate rejected this job';\n case 'condition_rejected':\n return 'The job condition rejected this job';\n case 'condition_errored':\n return 'The job condition could not be evaluated';\n case 'user_cancelled':\n return 'The job was cancelled by a user';\n case 'run_cancelled':\n return 'The run was cancelled';\n case 'unknown':\n return 'The failure reason was not recorded';\n default:\n return 'Step failed';\n }\n}\n\nfunction failureDescription(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_auth_failed':\n return 'Checkout credentials were rejected. Verify repository access before re-running.';\n case 'checkout_unavailable':\n return 'The checkout service was unavailable. Retry after the service recovers.';\n case 'git_unavailable':\n return 'The runner could not start Git. Check the runner image before re-running.';\n case 'workspace_prep_failed':\n return 'The runner could not prepare its workspace. Review the runner setup details.';\n case 'config_unresolvable':\n return 'The resolved configuration contains a value that could not be evaluated.';\n case 'output_invalid':\n return 'The step returned output that did not match the declared contract.';\n case 'agent_config_invalid':\n return 'The agent configuration is not valid for this step.';\n case 'agent_invocation_failed':\n return 'The agent invocation failed after configuration was accepted.';\n case 'agent_harness_unavailable':\n return 'The runner could not start the agent harness.';\n case 'runner_lost':\n return 'The runner stopped responding before the step completed.';\n case 'timed_out':\n return 'The step exceeded its configured time limit.';\n case 'dependency_not_completed':\n return 'A required job did not complete, so this job could not start.';\n case 'condition_false':\n case 'condition_rejected':\n return 'The job condition did not allow this job to run.';\n case 'condition_errored':\n return 'The job condition could not be evaluated.';\n case 'default_gate_rejected':\n return 'A required job did not succeed, so this job was not allowed to run.';\n case 'step_failed':\n return 'A step failed before this job could complete.';\n case 'user_cancelled':\n case 'run_cancelled':\n return 'The run was cancelled before this work completed.';\n case 'unknown':\n return 'No machine-readable failure reason was recorded.';\n default:\n return `${humanize(reason)}. Review the details below and re-run after resolving the cause.`;\n }\n}\n\nfunction sourceLinkForFailure(reason: string | JobStatusReason): boolean {\n return (\n reason === 'config_unresolvable' ||\n reason === 'agent_config_invalid' ||\n reason === 'output_invalid' ||\n reason === 'default_gate_rejected' ||\n reason === 'condition_rejected' ||\n reason === 'condition_errored'\n );\n}\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction countConfigValues(value: unknown): number {\n if (Array.isArray(value))\n return value.reduce((total, item) => total + countConfigValues(item), 0);\n if (value !== null && typeof value === 'object') {\n return Object.values(value).reduce((total, item) => total + countConfigValues(item), 0);\n }\n return value === undefined ? 0 : 1;\n}\n"],"names":["Button","Callout","CalloutContent","CalloutDescription","CalloutTitle","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Code","Text","cn","Link","useStepAttemptDetailQuery","workflowRunSearchParams","humanizeStatus","AgentConfigFailureCallout","toSelectedAttemptError","JsonCode","JsonCodeTabs","StepInspectorSheet","entry","open","onOpenChange","workspaceSlug","projectSlug","workflowRunId","runAttempt","jobId","annotationCount","error","selectedStepError","step","inspectorQuery","id","attempt","enabled","side","className","label","statusVisual","kind","StepInspector","showFailure","query","StepFailureCallout","reason","statusReason","title","failureTitle","sourceLink","sourceLinkForFailure","sourceLocation","type","config","agentConfig","role","variant","div","span","failureDescription","message","as","to","params","search","tab","stepId","stepAttemptId","detail","data","trace","evaluationTrace","resolvedConfig","hasInputs","undefined","countConfigValues","authoredConfig","hasOutputs","outputs","output","response","hasTrace","length","hasAnnotations","detailCount","Number","isPending","InspectorLoading","isError","size","onClick","refetch","InspectorSection","ConfigCode","value","emptyMessage","pre","EvaluationTrace","EmptyInspector","children","section","aria-label","bold","entries","filename","keyCounts","Map","dl","map","keyBase","dropped","occurrence","get","set","empty","field","expression","evaluatedAt","fillTarget","degraded","dt","dd","truncated","exprTruncated","attemptError","humanize","replaceAll","replace","letter","toUpperCase","Array","isArray","reduce","total","item","Object","values"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/job-detail/step-troubleshooting.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout, CalloutContent, CalloutDescription, CalloutTitle} from '@shipfox/react-ui/callout';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport type {ReactNode} from 'react';\nimport type {\n EvaluationTraceEntry,\n JobStatusReason,\n Step,\n StepAttempt,\n StepError,\n} from '#core/workflow-run.js';\nimport {useStepAttemptDetailQuery} from '#hooks/api/step-attempt-detail.js';\nimport {workflowRunSearchParams} from '#routes/inputs.js';\nimport {humanizeStatus, type StepListEntryModel} from '../step-list/step-list-model.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {toSelectedAttemptError} from './job-empty-states.js';\nimport {JsonCode, type JsonCodeEntry, JsonCodeTabs} from './json-code.js';\n\nexport interface StepInspectorSheetProps {\n entry: StepListEntryModel;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount?: number | undefined;\n}\n\nexport function StepInspectorSheet({\n entry,\n open,\n onOpenChange,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: StepInspectorSheetProps) {\n const error = selectedStepError(entry.step, entry.error);\n const inspectorQuery = useStepAttemptDetailQuery(entry.step.id, entry.attempt, {\n enabled: open,\n });\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"w-full sm:max-w-[560px]\">\n <SheetHeader>\n <SheetTitle>{entry.step.label}</SheetTitle>\n <SheetDescription>\n Attempt #{entry.attempt} · {humanizeStatus(entry.statusVisual.kind)}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-section\">\n <StepInspector\n step={entry.step}\n attempt={entry}\n error={error}\n showFailure={entry.statusVisual.kind === 'failed' || entry.error !== null}\n query={inspectorQuery}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n jobId={jobId}\n annotationCount={annotationCount}\n />\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction StepFailureCallout({\n step,\n attempt,\n error,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n}) {\n const reason = error?.reason ?? step.statusReason ?? 'unknown';\n const title = failureTitle(reason);\n const sourceLink = sourceLinkForFailure(reason) && step.sourceLocation;\n\n if (step.type === 'agent' && reason === 'agent_config_invalid') {\n return (\n <AgentConfigFailureCallout\n workspaceSlug={workspaceSlug}\n config={step.agentConfig}\n error={error}\n />\n );\n }\n\n return (\n <Callout\n role=\"alert\"\n type=\"error\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-error-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>{title}</CalloutTitle>\n <CalloutDescription>\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-inline gap-y-tight\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <span>{failureDescription(reason)}</span>\n {error?.message ? (\n <span className=\"text-foreground-neutral-muted\">{error.message}</span>\n ) : null}\n </div>\n <Code as=\"span\" variant=\"label\" className=\"text-tag-error-text\">\n {reason}\n </Code>\n {sourceLink ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n workflowRunSearchParams(\n {tab: 'source'},\n {stepId: step.id, stepAttemptId: attempt.id, runAttempt},\n ) as never\n }\n className=\"font-medium text-foreground-highlight-interactive underline-offset-2 hover:underline\"\n >\n View in source\n </Link>\n ) : null}\n </div>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n );\n}\n\nfunction StepInspector({\n step,\n attempt,\n error,\n showFailure,\n query,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n showFailure: boolean;\n query: ReturnType<typeof useStepAttemptDetailQuery>;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount: number | undefined;\n}) {\n const detail = query.data;\n const trace = detail?.evaluationTrace ?? null;\n const resolvedConfig = detail?.config ?? null;\n const hasInputs =\n detail !== undefined &&\n (countConfigValues(detail.authoredConfig) > 0 || countConfigValues(resolvedConfig) > 0);\n const hasOutputs =\n attempt.outputs !== null || attempt.output !== null || attempt.response !== null;\n const hasTrace = trace !== null && trace.length > 0;\n const hasAnnotations = annotationCount !== undefined && annotationCount > 0;\n const detailCount = Number(hasInputs) + Number(hasOutputs) + Number(hasTrace);\n\n return (\n <div className=\"flex min-w-0 flex-col gap-section\">\n {showFailure ? (\n <StepFailureCallout\n step={step}\n attempt={attempt}\n error={error}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n />\n ) : null}\n {query.isPending ? <InspectorLoading /> : null}\n {query.isError ? (\n <Callout\n role=\"alert\"\n type=\"warning\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-warning-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>Details unavailable</CalloutTitle>\n <CalloutDescription className=\"flex items-center justify-between gap-inline\">\n <span>We could not load the resolved configuration for this attempt.</span>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n onClick={() => void query.refetch()}\n >\n Retry\n </Button>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n ) : null}\n {detail ? (\n <div className=\"flex min-w-0 flex-col gap-group\">\n {hasInputs ? (\n <InspectorSection title=\"Inputs\">\n <ConfigCode authoredConfig={detail.authoredConfig} resolvedConfig={resolvedConfig} />\n </InspectorSection>\n ) : null}\n {hasOutputs ? (\n <InspectorSection title=\"Outputs\">\n {attempt.outputs !== null || attempt.output !== null ? (\n <JsonCode\n value={attempt.outputs ?? attempt.output ?? {}}\n emptyMessage=\"No outputs declared; the `outputs:` mapping is empty.\"\n />\n ) : null}\n {attempt.response !== null ? (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Response\n </Text>\n <pre className=\"max-h-160 min-w-0 overflow-auto rounded-6 border border-border-neutral-base bg-background-neutral-subtle p-tight font-code text-xs leading-18 text-foreground-neutral-muted scrollbar\">\n {attempt.response}\n </pre>\n </div>\n ) : null}\n </InspectorSection>\n ) : null}\n {hasTrace ? (\n <InspectorSection title=\"Evaluation\">\n <EvaluationTrace trace={trace ?? []} />\n </InspectorSection>\n ) : null}\n {detailCount === 0 && !showFailure && !hasAnnotations ? <EmptyInspector /> : null}\n </div>\n ) : null}\n {hasAnnotations ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={workflowRunSearchParams({tab: 'annotations'}, {jobId, runAttempt}) as never}\n className=\"inline-flex w-fit rounded-4 text-xs text-foreground-highlight-interactive underline-offset-2 hover:underline focus-visible:shadow-button-neutral-focus\"\n >\n View {annotationCount} annotation{annotationCount === 1 ? '' : 's'}\n </Link>\n ) : null}\n {!query.isPending && !query.isError && !detail && !showFailure && !hasAnnotations ? (\n <EmptyInspector />\n ) : null}\n </div>\n );\n}\n\nfunction InspectorSection({title, children}: {title: string; children: ReactNode}) {\n return (\n <section className=\"flex min-w-0 flex-col gap-inline\" aria-label={title}>\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {title}\n </Text>\n {children}\n </section>\n );\n}\n\nfunction ConfigCode({\n authoredConfig,\n resolvedConfig,\n}: {\n authoredConfig: Record<string, unknown> | null;\n resolvedConfig: Record<string, unknown> | null;\n}) {\n const entries: JsonCodeEntry[] = [\n ...(authoredConfig\n ? [\n {\n filename: 'authored.json',\n label: 'Authored configuration',\n value: authoredConfig,\n },\n ]\n : []),\n ...(resolvedConfig\n ? [\n {\n filename: 'resolved.json',\n label: 'Resolved configuration',\n value: resolvedConfig,\n },\n ]\n : []),\n ];\n\n if (entries.length === 0) return null;\n return <JsonCodeTabs entries={entries} />;\n}\n\nexport function EvaluationTrace({trace}: {trace: readonly EvaluationTraceEntry[]}) {\n const keyCounts = new Map<string, number>();\n\n return (\n <dl className=\"flex min-w-0 flex-col divide-y divide-border-neutral-base rounded-6 border border-border-neutral-base\">\n {trace.map((entry) => {\n if ('dropped' in entry) {\n const keyBase = `limit-${entry.dropped}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className=\"px-row py-row text-xs text-foreground-neutral-muted\"\n >\n {entry.dropped} more evaluation{entry.dropped === 1 ? '' : 's'} not recorded\n </div>\n );\n }\n\n const empty = entry.value === undefined || entry.value === '';\n const keyBase = `evaluation-${entry.field}-${entry.expression}-${entry.evaluatedAt}-${entry.fillTarget}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className={cn(\n 'grid min-w-0 grid-cols-1 gap-inline px-row py-row min-[768px]:grid-cols-[160px_minmax(0,1fr)]',\n entry.degraded && 'border-l border-tag-error-icon',\n )}\n >\n <dt\n className=\"flex min-w-0 flex-col gap-tight font-code text-xs text-foreground-neutral-muted\"\n title={entry.field}\n >\n <span className=\"block truncate\">{entry.field}</span>\n <span className=\"block break-all text-foreground-neutral-subtle\">\n {entry.expression}\n </span>\n </dt>\n <dd className=\"flex min-w-0 flex-col gap-tight text-xs text-foreground-neutral-base\">\n {entry.degraded ? <span className=\"sr-only\">Degraded evaluation</span> : null}\n <div className=\"break-words font-code\">\n {empty ? <span className=\"text-tag-error-text\">(empty)</span> : entry.value}\n </div>\n <div className=\"flex min-w-0 flex-wrap gap-x-inline gap-y-tight text-foreground-neutral-muted\">\n {entry.degraded ? <span className=\"text-tag-error-text\">degraded</span> : null}\n {entry.truncated || entry.exprTruncated ? <span>truncated</span> : null}\n </div>\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n\nfunction InspectorLoading() {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading troubleshooting details\"\n className=\"flex flex-col gap-inline\"\n >\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-120 w-full\" />\n </div>\n );\n}\n\nfunction EmptyInspector() {\n return (\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n No additional troubleshooting details were recorded.\n </Text>\n );\n}\n\nfunction selectedStepError(\n step: Step,\n attemptError: Record<string, unknown> | null,\n): StepError | null {\n return toSelectedAttemptError(step, attemptError) ?? step.error;\n}\n\nfunction failureTitle(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_failed':\n return 'Checkout failed';\n case 'checkout_auth_failed':\n return 'Checkout authentication failed';\n case 'checkout_unavailable':\n return 'Checkout service unavailable';\n case 'checkout_path_invalid':\n return 'Checkout path is invalid';\n case 'checkout_destination_occupied':\n return 'Checkout destination is already occupied';\n case 'git_unavailable':\n return 'Git was unavailable';\n case 'workspace_prep_failed':\n return 'Workspace preparation failed';\n case 'setup_aborted':\n return 'Step setup was aborted';\n case 'config_unresolvable':\n return 'Step configuration could not be resolved';\n case 'output_invalid':\n return 'Step output was invalid';\n case 'agent_config_invalid':\n return 'Agent configuration is invalid';\n case 'agent_invocation_failed':\n return 'Agent invocation failed';\n case 'agent_harness_unavailable':\n return 'Agent harness was unavailable';\n case 'runner_lost':\n return 'Runner stopped responding';\n case 'output_too_large':\n return 'Job output exceeded its size limit';\n case 'timed_out':\n return 'Step timed out';\n case 'step_failed':\n return 'A step failed';\n case 'dependency_not_completed':\n return 'A dependency did not complete';\n case 'condition_false':\n return 'The job condition was false';\n case 'default_gate_rejected':\n return 'The default gate rejected this job';\n case 'condition_rejected':\n return 'The job condition rejected this job';\n case 'condition_errored':\n return 'The job condition could not be evaluated';\n case 'user_cancelled':\n return 'The job was cancelled by a user';\n case 'run_cancelled':\n return 'The run was cancelled';\n case 'unknown':\n return 'The failure reason was not recorded';\n default:\n return 'Step failed';\n }\n}\n\nfunction failureDescription(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_auth_failed':\n return 'Checkout credentials were rejected. Verify repository access before re-running.';\n case 'checkout_unavailable':\n return 'The checkout service was unavailable. Retry after the service recovers.';\n case 'git_unavailable':\n return 'The runner could not start Git. Check the runner image before re-running.';\n case 'workspace_prep_failed':\n return 'The runner could not prepare its workspace. Review the runner setup details.';\n case 'config_unresolvable':\n return 'The resolved configuration contains a value that could not be evaluated.';\n case 'output_invalid':\n return 'The step returned output that did not match the declared contract.';\n case 'agent_config_invalid':\n return 'The agent configuration is not valid for this step.';\n case 'agent_invocation_failed':\n return 'The agent invocation failed after configuration was accepted.';\n case 'agent_harness_unavailable':\n return 'The runner could not start the agent harness.';\n case 'runner_lost':\n return 'The runner stopped responding before the step completed.';\n case 'output_too_large':\n return 'The materialized job output exceeded its configured size limit.';\n case 'timed_out':\n return 'The step exceeded its configured time limit.';\n case 'dependency_not_completed':\n return 'A required job did not complete, so this job could not start.';\n case 'condition_false':\n case 'condition_rejected':\n return 'The job condition did not allow this job to run.';\n case 'condition_errored':\n return 'The job condition could not be evaluated.';\n case 'default_gate_rejected':\n return 'A required job did not succeed, so this job was not allowed to run.';\n case 'step_failed':\n return 'A step failed before this job could complete.';\n case 'user_cancelled':\n case 'run_cancelled':\n return 'The run was cancelled before this work completed.';\n case 'unknown':\n return 'No machine-readable failure reason was recorded.';\n default:\n return `${humanize(reason)}. Review the details below and re-run after resolving the cause.`;\n }\n}\n\nfunction sourceLinkForFailure(reason: string | JobStatusReason): boolean {\n return (\n reason === 'config_unresolvable' ||\n reason === 'agent_config_invalid' ||\n reason === 'output_invalid' ||\n reason === 'default_gate_rejected' ||\n reason === 'condition_rejected' ||\n reason === 'condition_errored'\n );\n}\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction countConfigValues(value: unknown): number {\n if (Array.isArray(value))\n return value.reduce((total, item) => total + countConfigValues(item), 0);\n if (value !== null && typeof value === 'object') {\n return Object.values(value).reduce((total, item) => total + countConfigValues(item), 0);\n }\n return value === undefined ? 0 : 1;\n}\n"],"names":["Button","Callout","CalloutContent","CalloutDescription","CalloutTitle","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Code","Text","cn","Link","useStepAttemptDetailQuery","workflowRunSearchParams","humanizeStatus","AgentConfigFailureCallout","toSelectedAttemptError","JsonCode","JsonCodeTabs","StepInspectorSheet","entry","open","onOpenChange","workspaceSlug","projectSlug","workflowRunId","runAttempt","jobId","annotationCount","error","selectedStepError","step","inspectorQuery","id","attempt","enabled","side","className","label","statusVisual","kind","StepInspector","showFailure","query","StepFailureCallout","reason","statusReason","title","failureTitle","sourceLink","sourceLinkForFailure","sourceLocation","type","config","agentConfig","role","variant","div","span","failureDescription","message","as","to","params","search","tab","stepId","stepAttemptId","detail","data","trace","evaluationTrace","resolvedConfig","hasInputs","undefined","countConfigValues","authoredConfig","hasOutputs","outputs","output","response","hasTrace","length","hasAnnotations","detailCount","Number","isPending","InspectorLoading","isError","size","onClick","refetch","InspectorSection","ConfigCode","value","emptyMessage","pre","EvaluationTrace","EmptyInspector","children","section","aria-label","bold","entries","filename","keyCounts","Map","dl","map","keyBase","dropped","occurrence","get","set","empty","field","expression","evaluatedAt","fillTarget","degraded","dt","dd","truncated","exprTruncated","attemptError","humanize","replaceAll","replace","letter","toUpperCase","Array","isArray","reduce","total","item","Object","values"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"step-list-model.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,KAAK,GAAG,EACR,YAAY,EACZ,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,eAAe,EAAE,0BAA0B,GAAG,IAAI,CAAC;IACnD,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC,GAAG,aAAa,CAehB;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAElE;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAoB9D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAepE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD"}
1
+ {"version":3,"file":"step-list-model.d.ts","sourceRoot":"","sources":["../../../src/components/step-list/step-list-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,KAAK,GAAG,EACR,YAAY,EACZ,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,eAAe,EAAE,0BAA0B,GAAG,IAAI,CAAC;IACnD,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,YAAY,GACb,EAAE;IACD,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC,GAAG,aAAa,CAehB;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAElE;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,CAqB9D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAepE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD"}
@@ -26,6 +26,7 @@ export function emptyJobExecutionForJob(job) {
26
26
  name: job.name ?? job.key,
27
27
  status: job.status === 'skipped' ? 'cancelled' : job.status,
28
28
  statusReason: job.statusReason,
29
+ statusReasonMessage: null,
29
30
  runner: job.runner,
30
31
  outputs: job.outputs,
31
32
  triggerEvents: [],
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/step-list/step-list-model.ts"],"sourcesContent":["import {\n getWorkflowStatusVisual,\n type WorkflowStatusVisual,\n} from '#components/workflow-status/status-visuals.js';\nimport {\n defaultJobExecution,\n isWorkflowStatus as isKnownWorkflowStatus,\n type Job,\n JobExecution,\n type Step,\n type StepAttempt,\n type StepAttemptDisplayDuration,\n} from '#core/workflow-run.js';\n\nexport interface StepStatusVisual extends Omit<WorkflowStatusVisual, 'kind'> {\n kind: string;\n ripple: boolean;\n}\n\nexport interface StepAttemptModel extends StepAttempt {\n displayDuration: StepAttemptDisplayDuration | null;\n statusVisual: StepStatusVisual;\n carriedOver: boolean;\n}\n\nexport interface StepModel extends Omit<Step, 'attempts'> {\n index: number;\n label: string;\n attempts: StepAttemptModel[];\n}\n\nexport interface StepListEntryModel extends StepAttemptModel {\n step: StepModel;\n}\n\nexport interface StepListModel {\n jobId: string;\n jobName: string;\n jobExecutionId: string;\n stepCount: number;\n activeEntryId: string | undefined;\n entries: StepListEntryModel[];\n}\n\nexport function buildStepListModel({\n job,\n jobExecution,\n}: {\n job: Job;\n jobExecution?: JobExecution | undefined;\n}): StepListModel {\n const selectedJobExecution = jobExecution ?? defaultStepListJobExecution(job);\n const steps = [...selectedJobExecution.steps].sort(compareSteps).map(toStepModel);\n const entries = steps\n .flatMap((step) => toStepEntries(step, job.carriedOver))\n .sort(compareEntries);\n\n return {\n jobId: job.id,\n jobName: job.name ?? job.key,\n jobExecutionId: selectedJobExecution.id,\n stepCount: steps.length,\n activeEntryId: landingEntryId(entries),\n entries,\n };\n}\n\nexport function defaultStepListJobExecution(job: Job): JobExecution {\n return defaultJobExecution(job) ?? emptyJobExecutionForJob(job);\n}\n\nexport function emptyJobExecutionForJob(job: Job): JobExecution {\n return new JobExecution({\n id: `missing:${job.id}`,\n jobId: job.id,\n sequence: 1,\n name: job.name ?? job.key,\n status: job.status === 'skipped' ? 'cancelled' : job.status,\n statusReason: job.statusReason,\n runner: job.runner,\n outputs: job.outputs,\n triggerEvents: [],\n queuedAt: null,\n startedAt: null,\n finishedAt: null,\n timedOutAt: null,\n evaluationTrace: job.evaluationTrace,\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n steps: [],\n });\n}\n\nexport function getStepStatusVisual(status: string): StepStatusVisual {\n const normalized = normalizeStatus(status);\n\n if (isKnownWorkflowStatus(normalized)) {\n const visual = getWorkflowStatusVisual(normalized);\n return {...visual, ripple: normalized === 'running'};\n }\n\n return {\n kind: status,\n label: humanizeStatus(status),\n dot: 'neutral',\n badge: 'neutral',\n ripple: false,\n };\n}\n\nexport function humanizeStatus(status: string): string {\n const words = status.trim().replace(/[_-]+/g, ' ').replace(/\\s+/g, ' ').toLowerCase();\n if (!words) return 'Unknown';\n const firstLetter = words.at(0);\n return firstLetter === undefined ? 'Unknown' : firstLetter.toUpperCase() + words.slice(1);\n}\n\nfunction toStepModel(step: Step, index: number): StepModel {\n const attempts = [...step.attempts].sort(compareAttempts).map((attempt) => ({\n ...attempt,\n displayDuration: attempt.displayDuration,\n statusVisual: getStepStatusVisual(attempt.status),\n carriedOver: false,\n }));\n\n return {\n ...step,\n index: index + 1,\n label: stepLabel(step, index),\n attempts,\n };\n}\n\nfunction stepLabel(step: Step, index: number): string {\n const name = step.name.trim();\n if (name) return name;\n\n const key = step.key?.trim();\n if (key) return key;\n\n return `Step ${index + 1}`;\n}\n\nfunction toStepEntries(step: StepModel, carriedOverJob: boolean): StepListEntryModel[] {\n if (step.attempts.length > 0) {\n return step.attempts.map((attempt) => ({\n ...attempt,\n step,\n }));\n }\n\n if (!carriedOverJob) return [];\n\n return [\n {\n id: `carried-over:${step.id}`,\n stepId: step.id,\n jobExecutionId: step.jobExecutionId,\n attempt: step.currentAttempt,\n executionOrder: step.position,\n status: step.status,\n exitCode: null,\n output: null,\n outputs: null,\n response: null,\n error: null,\n gateResult: null,\n restartFeedback: null,\n startedAt: step.createdAt,\n finishedAt: null,\n displayDuration: null,\n statusVisual: getStepStatusVisual(step.status),\n carriedOver: true,\n step,\n },\n ];\n}\n\nfunction compareSteps(left: Step, right: Step): number {\n return (\n left.position - right.position ||\n (left.name ?? '').localeCompare(right.name ?? '') ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction compareAttempts(left: Step['attempts'][number], right: Step['attempts'][number]) {\n return left.attempt - right.attempt || left.id.localeCompare(right.id);\n}\n\nfunction compareEntries(left: StepListEntryModel, right: StepListEntryModel): number {\n return (\n left.executionOrder - right.executionOrder ||\n left.step.index - right.step.index ||\n left.attempt - right.attempt ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction landingEntryId(entries: readonly StepListEntryModel[]): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.statusVisual.kind === 'running') return entry.id;\n }\n return undefined;\n}\n\nfunction normalizeStatus(status: string): string {\n return status.trim().toLowerCase().replace(/-/g, '_');\n}\n"],"names":["getWorkflowStatusVisual","defaultJobExecution","isWorkflowStatus","isKnownWorkflowStatus","JobExecution","buildStepListModel","job","jobExecution","selectedJobExecution","defaultStepListJobExecution","steps","sort","compareSteps","map","toStepModel","entries","flatMap","step","toStepEntries","carriedOver","compareEntries","jobId","id","jobName","name","key","jobExecutionId","stepCount","length","activeEntryId","landingEntryId","emptyJobExecutionForJob","sequence","status","statusReason","runner","outputs","triggerEvents","queuedAt","startedAt","finishedAt","timedOutAt","evaluationTrace","createdAt","updatedAt","getStepStatusVisual","normalized","normalizeStatus","visual","ripple","kind","label","humanizeStatus","dot","badge","words","trim","replace","toLowerCase","firstLetter","at","undefined","toUpperCase","slice","index","attempts","compareAttempts","attempt","displayDuration","statusVisual","stepLabel","carriedOverJob","stepId","currentAttempt","executionOrder","position","exitCode","output","response","error","gateResult","restartFeedback","left","right","localeCompare","entry"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/step-list/step-list-model.ts"],"sourcesContent":["import {\n getWorkflowStatusVisual,\n type WorkflowStatusVisual,\n} from '#components/workflow-status/status-visuals.js';\nimport {\n defaultJobExecution,\n isWorkflowStatus as isKnownWorkflowStatus,\n type Job,\n JobExecution,\n type Step,\n type StepAttempt,\n type StepAttemptDisplayDuration,\n} from '#core/workflow-run.js';\n\nexport interface StepStatusVisual extends Omit<WorkflowStatusVisual, 'kind'> {\n kind: string;\n ripple: boolean;\n}\n\nexport interface StepAttemptModel extends StepAttempt {\n displayDuration: StepAttemptDisplayDuration | null;\n statusVisual: StepStatusVisual;\n carriedOver: boolean;\n}\n\nexport interface StepModel extends Omit<Step, 'attempts'> {\n index: number;\n label: string;\n attempts: StepAttemptModel[];\n}\n\nexport interface StepListEntryModel extends StepAttemptModel {\n step: StepModel;\n}\n\nexport interface StepListModel {\n jobId: string;\n jobName: string;\n jobExecutionId: string;\n stepCount: number;\n activeEntryId: string | undefined;\n entries: StepListEntryModel[];\n}\n\nexport function buildStepListModel({\n job,\n jobExecution,\n}: {\n job: Job;\n jobExecution?: JobExecution | undefined;\n}): StepListModel {\n const selectedJobExecution = jobExecution ?? defaultStepListJobExecution(job);\n const steps = [...selectedJobExecution.steps].sort(compareSteps).map(toStepModel);\n const entries = steps\n .flatMap((step) => toStepEntries(step, job.carriedOver))\n .sort(compareEntries);\n\n return {\n jobId: job.id,\n jobName: job.name ?? job.key,\n jobExecutionId: selectedJobExecution.id,\n stepCount: steps.length,\n activeEntryId: landingEntryId(entries),\n entries,\n };\n}\n\nexport function defaultStepListJobExecution(job: Job): JobExecution {\n return defaultJobExecution(job) ?? emptyJobExecutionForJob(job);\n}\n\nexport function emptyJobExecutionForJob(job: Job): JobExecution {\n return new JobExecution({\n id: `missing:${job.id}`,\n jobId: job.id,\n sequence: 1,\n name: job.name ?? job.key,\n status: job.status === 'skipped' ? 'cancelled' : job.status,\n statusReason: job.statusReason,\n statusReasonMessage: null,\n runner: job.runner,\n outputs: job.outputs,\n triggerEvents: [],\n queuedAt: null,\n startedAt: null,\n finishedAt: null,\n timedOutAt: null,\n evaluationTrace: job.evaluationTrace,\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n steps: [],\n });\n}\n\nexport function getStepStatusVisual(status: string): StepStatusVisual {\n const normalized = normalizeStatus(status);\n\n if (isKnownWorkflowStatus(normalized)) {\n const visual = getWorkflowStatusVisual(normalized);\n return {...visual, ripple: normalized === 'running'};\n }\n\n return {\n kind: status,\n label: humanizeStatus(status),\n dot: 'neutral',\n badge: 'neutral',\n ripple: false,\n };\n}\n\nexport function humanizeStatus(status: string): string {\n const words = status.trim().replace(/[_-]+/g, ' ').replace(/\\s+/g, ' ').toLowerCase();\n if (!words) return 'Unknown';\n const firstLetter = words.at(0);\n return firstLetter === undefined ? 'Unknown' : firstLetter.toUpperCase() + words.slice(1);\n}\n\nfunction toStepModel(step: Step, index: number): StepModel {\n const attempts = [...step.attempts].sort(compareAttempts).map((attempt) => ({\n ...attempt,\n displayDuration: attempt.displayDuration,\n statusVisual: getStepStatusVisual(attempt.status),\n carriedOver: false,\n }));\n\n return {\n ...step,\n index: index + 1,\n label: stepLabel(step, index),\n attempts,\n };\n}\n\nfunction stepLabel(step: Step, index: number): string {\n const name = step.name.trim();\n if (name) return name;\n\n const key = step.key?.trim();\n if (key) return key;\n\n return `Step ${index + 1}`;\n}\n\nfunction toStepEntries(step: StepModel, carriedOverJob: boolean): StepListEntryModel[] {\n if (step.attempts.length > 0) {\n return step.attempts.map((attempt) => ({\n ...attempt,\n step,\n }));\n }\n\n if (!carriedOverJob) return [];\n\n return [\n {\n id: `carried-over:${step.id}`,\n stepId: step.id,\n jobExecutionId: step.jobExecutionId,\n attempt: step.currentAttempt,\n executionOrder: step.position,\n status: step.status,\n exitCode: null,\n output: null,\n outputs: null,\n response: null,\n error: null,\n gateResult: null,\n restartFeedback: null,\n startedAt: step.createdAt,\n finishedAt: null,\n displayDuration: null,\n statusVisual: getStepStatusVisual(step.status),\n carriedOver: true,\n step,\n },\n ];\n}\n\nfunction compareSteps(left: Step, right: Step): number {\n return (\n left.position - right.position ||\n (left.name ?? '').localeCompare(right.name ?? '') ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction compareAttempts(left: Step['attempts'][number], right: Step['attempts'][number]) {\n return left.attempt - right.attempt || left.id.localeCompare(right.id);\n}\n\nfunction compareEntries(left: StepListEntryModel, right: StepListEntryModel): number {\n return (\n left.executionOrder - right.executionOrder ||\n left.step.index - right.step.index ||\n left.attempt - right.attempt ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction landingEntryId(entries: readonly StepListEntryModel[]): string | undefined {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.statusVisual.kind === 'running') return entry.id;\n }\n return undefined;\n}\n\nfunction normalizeStatus(status: string): string {\n return status.trim().toLowerCase().replace(/-/g, '_');\n}\n"],"names":["getWorkflowStatusVisual","defaultJobExecution","isWorkflowStatus","isKnownWorkflowStatus","JobExecution","buildStepListModel","job","jobExecution","selectedJobExecution","defaultStepListJobExecution","steps","sort","compareSteps","map","toStepModel","entries","flatMap","step","toStepEntries","carriedOver","compareEntries","jobId","id","jobName","name","key","jobExecutionId","stepCount","length","activeEntryId","landingEntryId","emptyJobExecutionForJob","sequence","status","statusReason","statusReasonMessage","runner","outputs","triggerEvents","queuedAt","startedAt","finishedAt","timedOutAt","evaluationTrace","createdAt","updatedAt","getStepStatusVisual","normalized","normalizeStatus","visual","ripple","kind","label","humanizeStatus","dot","badge","words","trim","replace","toLowerCase","firstLetter","at","undefined","toUpperCase","slice","index","attempts","compareAttempts","attempt","displayDuration","statusVisual","stepLabel","carriedOverJob","stepId","currentAttempt","executionOrder","position","exitCode","output","response","error","gateResult","restartFeedback","left","right","localeCompare","entry"],"mappings":"AAAA,SACEA,uBAAuB,QAElB,gDAAgD;AACvD,SACEC,mBAAmB,EACnBC,oBAAoBC,qBAAqB,EAEzCC,YAAY,QAIP,wBAAwB;AAgC/B,OAAO,SAASC,mBAAmB,EACjCC,GAAG,EACHC,YAAY,EAIb;IACC,MAAMC,uBAAuBD,gBAAgBE,4BAA4BH;IACzE,MAAMI,QAAQ;WAAIF,qBAAqBE,KAAK;KAAC,CAACC,IAAI,CAACC,cAAcC,GAAG,CAACC;IACrE,MAAMC,UAAUL,MACbM,OAAO,CAAC,CAACC,OAASC,cAAcD,MAAMX,IAAIa,WAAW,GACrDR,IAAI,CAACS;IAER,OAAO;QACLC,OAAOf,IAAIgB,EAAE;QACbC,SAASjB,IAAIkB,IAAI,IAAIlB,IAAImB,GAAG;QAC5BC,gBAAgBlB,qBAAqBc,EAAE;QACvCK,WAAWjB,MAAMkB,MAAM;QACvBC,eAAeC,eAAef;QAC9BA;IACF;AACF;AAEA,OAAO,SAASN,4BAA4BH,GAAQ;IAClD,OAAOL,oBAAoBK,QAAQyB,wBAAwBzB;AAC7D;AAEA,OAAO,SAASyB,wBAAwBzB,GAAQ;IAC9C,OAAO,IAAIF,aAAa;QACtBkB,IAAI,CAAC,QAAQ,EAAEhB,IAAIgB,EAAE,EAAE;QACvBD,OAAOf,IAAIgB,EAAE;QACbU,UAAU;QACVR,MAAMlB,IAAIkB,IAAI,IAAIlB,IAAImB,GAAG;QACzBQ,QAAQ3B,IAAI2B,MAAM,KAAK,YAAY,cAAc3B,IAAI2B,MAAM;QAC3DC,cAAc5B,IAAI4B,YAAY;QAC9BC,qBAAqB;QACrBC,QAAQ9B,IAAI8B,MAAM;QAClBC,SAAS/B,IAAI+B,OAAO;QACpBC,eAAe,EAAE;QACjBC,UAAU;QACVC,WAAW;QACXC,YAAY;QACZC,YAAY;QACZC,iBAAiBrC,IAAIqC,eAAe;QACpCC,WAAWtC,IAAIsC,SAAS;QACxBC,WAAWvC,IAAIuC,SAAS;QACxBnC,OAAO,EAAE;IACX;AACF;AAEA,OAAO,SAASoC,oBAAoBb,MAAc;IAChD,MAAMc,aAAaC,gBAAgBf;IAEnC,IAAI9B,sBAAsB4C,aAAa;QACrC,MAAME,SAASjD,wBAAwB+C;QACvC,OAAO;YAAC,GAAGE,MAAM;YAAEC,QAAQH,eAAe;QAAS;IACrD;IAEA,OAAO;QACLI,MAAMlB;QACNmB,OAAOC,eAAepB;QACtBqB,KAAK;QACLC,OAAO;QACPL,QAAQ;IACV;AACF;AAEA,OAAO,SAASG,eAAepB,MAAc;IAC3C,MAAMuB,QAAQvB,OAAOwB,IAAI,GAAGC,OAAO,CAAC,UAAU,KAAKA,OAAO,CAAC,QAAQ,KAAKC,WAAW;IACnF,IAAI,CAACH,OAAO,OAAO;IACnB,MAAMI,cAAcJ,MAAMK,EAAE,CAAC;IAC7B,OAAOD,gBAAgBE,YAAY,YAAYF,YAAYG,WAAW,KAAKP,MAAMQ,KAAK,CAAC;AACzF;AAEA,SAASlD,YAAYG,IAAU,EAAEgD,KAAa;IAC5C,MAAMC,WAAW;WAAIjD,KAAKiD,QAAQ;KAAC,CAACvD,IAAI,CAACwD,iBAAiBtD,GAAG,CAAC,CAACuD,UAAa,CAAA;YAC1E,GAAGA,OAAO;YACVC,iBAAiBD,QAAQC,eAAe;YACxCC,cAAcxB,oBAAoBsB,QAAQnC,MAAM;YAChDd,aAAa;QACf,CAAA;IAEA,OAAO;QACL,GAAGF,IAAI;QACPgD,OAAOA,QAAQ;QACfb,OAAOmB,UAAUtD,MAAMgD;QACvBC;IACF;AACF;AAEA,SAASK,UAAUtD,IAAU,EAAEgD,KAAa;IAC1C,MAAMzC,OAAOP,KAAKO,IAAI,CAACiC,IAAI;IAC3B,IAAIjC,MAAM,OAAOA;IAEjB,MAAMC,MAAMR,KAAKQ,GAAG,EAAEgC;IACtB,IAAIhC,KAAK,OAAOA;IAEhB,OAAO,CAAC,KAAK,EAAEwC,QAAQ,GAAG;AAC5B;AAEA,SAAS/C,cAAcD,IAAe,EAAEuD,cAAuB;IAC7D,IAAIvD,KAAKiD,QAAQ,CAACtC,MAAM,GAAG,GAAG;QAC5B,OAAOX,KAAKiD,QAAQ,CAACrD,GAAG,CAAC,CAACuD,UAAa,CAAA;gBACrC,GAAGA,OAAO;gBACVnD;YACF,CAAA;IACF;IAEA,IAAI,CAACuD,gBAAgB,OAAO,EAAE;IAE9B,OAAO;QACL;YACElD,IAAI,CAAC,aAAa,EAAEL,KAAKK,EAAE,EAAE;YAC7BmD,QAAQxD,KAAKK,EAAE;YACfI,gBAAgBT,KAAKS,cAAc;YACnC0C,SAASnD,KAAKyD,cAAc;YAC5BC,gBAAgB1D,KAAK2D,QAAQ;YAC7B3C,QAAQhB,KAAKgB,MAAM;YACnB4C,UAAU;YACVC,QAAQ;YACRzC,SAAS;YACT0C,UAAU;YACVC,OAAO;YACPC,YAAY;YACZC,iBAAiB;YACjB1C,WAAWvB,KAAK2B,SAAS;YACzBH,YAAY;YACZ4B,iBAAiB;YACjBC,cAAcxB,oBAAoB7B,KAAKgB,MAAM;YAC7Cd,aAAa;YACbF;QACF;KACD;AACH;AAEA,SAASL,aAAauE,IAAU,EAAEC,KAAW;IAC3C,OACED,KAAKP,QAAQ,GAAGQ,MAAMR,QAAQ,IAC9B,AAACO,CAAAA,KAAK3D,IAAI,IAAI,EAAC,EAAG6D,aAAa,CAACD,MAAM5D,IAAI,IAAI,OAC9C2D,KAAK7D,EAAE,CAAC+D,aAAa,CAACD,MAAM9D,EAAE;AAElC;AAEA,SAAS6C,gBAAgBgB,IAA8B,EAAEC,KAA+B;IACtF,OAAOD,KAAKf,OAAO,GAAGgB,MAAMhB,OAAO,IAAIe,KAAK7D,EAAE,CAAC+D,aAAa,CAACD,MAAM9D,EAAE;AACvE;AAEA,SAASF,eAAe+D,IAAwB,EAAEC,KAAyB;IACzE,OACED,KAAKR,cAAc,GAAGS,MAAMT,cAAc,IAC1CQ,KAAKlE,IAAI,CAACgD,KAAK,GAAGmB,MAAMnE,IAAI,CAACgD,KAAK,IAClCkB,KAAKf,OAAO,GAAGgB,MAAMhB,OAAO,IAC5Be,KAAK7D,EAAE,CAAC+D,aAAa,CAACD,MAAM9D,EAAE;AAElC;AAEA,SAASQ,eAAef,OAAsC;IAC5D,IAAK,IAAIkD,QAAQlD,QAAQa,MAAM,GAAG,GAAGqC,SAAS,GAAGA,SAAS,EAAG;QAC3D,MAAMqB,QAAQvE,OAAO,CAACkD,MAAM;QAC5B,IAAIqB,OAAOhB,aAAanB,SAAS,WAAW,OAAOmC,MAAMhE,EAAE;IAC7D;IACA,OAAOwC;AACT;AAEA,SAASd,gBAAgBf,MAAc;IACrC,OAAOA,OAAOwB,IAAI,GAAGE,WAAW,GAAGD,OAAO,CAAC,MAAM;AACnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-workspace-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAG3B,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,iBAAiB,CAAC;IACvB,aAAa,EAAE,mBAAmB,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC1C,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACtD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,aAAa,EACb,WAAW,EACX,GAAG,EACH,aAAa,EACb,YAAY,EACZ,SAAc,EACd,iBAAiB,GAClB,EAAE,oBAAoB,+BA0DtB"}
1
+ {"version":3,"file":"run-workspace-nav.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAG3B,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,iBAAiB,CAAC;IACvB,aAAa,EAAE,mBAAmB,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC1C,iBAAiB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACtD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,aAAa,EACb,WAAW,EACX,GAAG,EACH,aAAa,EACb,YAAY,EACZ,SAAc,EACd,iBAAiB,GAClB,EAAE,oBAAoB,+BA8DtB"}
@@ -26,10 +26,11 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
26
26
  intervalMs: 1000,
27
27
  reducedMotionIntervalMs: 10_000,
28
28
  children: /*#__PURE__*/ _jsx("aside", {
29
- className: "w-full shrink-0 border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r",
29
+ className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r",
30
30
  children: /*#__PURE__*/ _jsxs(Collapsible, {
31
31
  open: mobileOpen,
32
32
  onOpenChange: setMobileOpen,
33
+ className: "flex min-h-0 flex-col min-[768px]:flex-1",
33
34
  children: [
34
35
  /*#__PURE__*/ _jsx(CollapsibleTrigger, {
35
36
  asChild: true,
@@ -63,7 +64,7 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
63
64
  })
64
65
  }),
65
66
  /*#__PURE__*/ _jsx("div", {
66
- className: cn('max-h-[50vh] overflow-y-auto p-tight min-[768px]:block min-[768px]:max-h-none min-[768px]:p-[12px]', !mobileOpen && 'hidden'),
67
+ className: cn('flex min-h-0 max-h-[50vh] flex-col overflow-y-auto p-tight scrollbar min-[768px]:min-h-0 min-[768px]:max-h-none min-[768px]:flex-1 min-[768px]:flex min-[768px]:overflow-hidden min-[768px]:p-[12px]', !mobileOpen && 'hidden'),
67
68
  children: /*#__PURE__*/ _jsx(RunWorkspaceNavContent, {
68
69
  workspaceSlug: workspaceSlug,
69
70
  projectSlug: projectSlug,
@@ -105,7 +106,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
105
106
  ]);
106
107
  return /*#__PURE__*/ _jsxs("nav", {
107
108
  "aria-label": "Run workspace",
108
- className: "flex min-w-0 flex-col gap-group",
109
+ className: "flex min-h-0 min-w-0 flex-1 flex-col gap-group",
109
110
  children: [
110
111
  /*#__PURE__*/ _jsx("ul", {
111
112
  children: /*#__PURE__*/ _jsx("li", {
@@ -122,7 +123,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
122
123
  }),
123
124
  /*#__PURE__*/ _jsxs("section", {
124
125
  "aria-labelledby": "run-workspace-jobs-heading",
125
- className: "min-w-0",
126
+ className: "flex min-h-0 min-w-0 flex-1 flex-col",
126
127
  children: [
127
128
  /*#__PURE__*/ _jsxs("div", {
128
129
  className: "flex items-center justify-between gap-inline px-tight pb-[6px]",
@@ -144,7 +145,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
144
145
  ]
145
146
  }),
146
147
  /*#__PURE__*/ _jsx("ol", {
147
- className: "max-h-[320px] overflow-y-auto",
148
+ className: "min-h-0 flex-1 overflow-y-auto scrollbar",
148
149
  children: jobs.map((job)=>{
149
150
  const current = job.id === currentJobId;
150
151
  const execution = defaultJobExecution(job);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"sourcesContent":["import {Collapsible, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n type Job,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobExecutionTimeText} from '../job-detail/job-execution-time-text.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface RunWorkspaceNavProps {\n workspaceSlug: string;\n projectSlug: string;\n run: WorkflowRunDetail;\n activeSection: RunWorkspaceSection;\n currentJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n annotationSummary?: RunAnnotationSummary | undefined;\n}\n\n/**\n * The stable navigation model shared by run-level and job-level routes. The graph explains\n * topology; this compact index makes moving between dedicated job pages predictable.\n */\nexport function RunWorkspaceNav({\n workspaceSlug,\n projectSlug,\n run,\n activeSection,\n currentJobId,\n jobSearch = {},\n annotationSummary,\n}: RunWorkspaceNavProps) {\n const jobs = useMemo(() => [...run.jobs].sort(compareJobs), [run.jobs]);\n const [mobileOpen, setMobileOpen] = useState(false);\n const currentJob = jobs.find((job) => job.id === currentJobId);\n const currentLabel = currentJob?.displayName ?? sectionLabel(activeSection);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside className=\"w-full shrink-0 border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r\">\n <Collapsible open={mobileOpen} onOpenChange={setMobileOpen}>\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex min-h-44 w-full items-center justify-between gap-cluster px-row text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden\"\n aria-label=\"Toggle run navigation\"\n >\n <span className=\"min-w-0\">\n <Text as=\"span\" size=\"xs\" className=\"block text-foreground-neutral-muted\">\n Run navigation\n </Text>\n <span className=\"block truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {currentLabel}\n </span>\n </span>\n <Icon\n name=\"chevronDown\"\n size={14}\n aria-hidden=\"true\"\n className={cn(\n 'shrink-0 text-foreground-neutral-muted transition-transform',\n mobileOpen && 'rotate-180',\n )}\n />\n </button>\n </CollapsibleTrigger>\n <div\n className={cn(\n 'max-h-[50vh] overflow-y-auto p-tight min-[768px]:block min-[768px]:max-h-none min-[768px]:p-[12px]',\n !mobileOpen && 'hidden',\n )}\n >\n <RunWorkspaceNavContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={run}\n jobs={jobs}\n activeSection={activeSection}\n currentJobId={currentJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n mobileOpen={mobileOpen}\n onNavigate={() => setMobileOpen(false)}\n />\n </div>\n </Collapsible>\n </aside>\n </TimeTickerProvider>\n );\n}\n\nfunction RunWorkspaceNavContent({\n workspaceSlug,\n projectSlug,\n run,\n jobs,\n activeSection,\n currentJobId,\n jobSearch,\n annotationSummary,\n mobileOpen,\n onNavigate,\n}: RunWorkspaceNavProps & {\n jobs: Job[];\n jobSearch: WorkflowJobSearch;\n mobileOpen: boolean;\n onNavigate: () => void;\n}) {\n const currentRowRef = useRef<HTMLAnchorElement>(null);\n const runAttempt = jobSearch.runAttempt ?? run.runAttempt.attempt;\n\n useEffect(() => {\n if (!currentJobId || mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n useEffect(() => {\n if (!currentJobId || !mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n return (\n <nav aria-label=\"Run workspace\" className=\"flex min-w-0 flex-col gap-group\">\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"summary\"\n current={!currentJobId && activeSection === 'summary'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n\n <section aria-labelledby=\"run-workspace-jobs-heading\" className=\"min-w-0\">\n <div className=\"flex items-center justify-between gap-inline px-tight pb-[6px]\">\n <Text\n as=\"h2\"\n id=\"run-workspace-jobs-heading\"\n size=\"xs\"\n bold\n className=\"text-foreground-neutral-muted\"\n >\n Jobs\n </Text>\n <Text as=\"span\" size=\"xs\" className=\"font-code text-foreground-neutral-subtle\">\n {jobs.length}\n </Text>\n </div>\n <ol className=\"max-h-[320px] overflow-y-auto\">\n {jobs.map((job) => {\n const current = job.id === currentJobId;\n const execution = defaultJobExecution(job);\n const duration = execution?.displayDuration ?? job.displayDuration;\n\n return (\n <li key={job.id}>\n <Link\n ref={current ? currentRowRef : undefined}\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id, jobId: job.id}}\n search={workflowJobSearchParams({runAttempt}) as never}\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n className={cn(\n 'flex min-h-32 min-w-0 items-center gap-inline rounded-4 px-tight text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n <WorkflowStatusIcon\n status={deriveJobDisplayStatus(job)}\n size={12}\n tooltip={false}\n />\n <span className=\"min-w-0 truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {job.displayName}\n </span>\n <span className=\"ml-auto shrink-0 font-code text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n {duration ? <JobExecutionTimeText time={duration} /> : '—'}\n </span>\n </Link>\n </li>\n );\n })}\n </ol>\n </section>\n\n <section aria-labelledby=\"run-workspace-details-heading\">\n <Text\n as=\"h2\"\n id=\"run-workspace-details-heading\"\n size=\"xs\"\n bold\n className=\"px-tight pb-[6px] text-foreground-neutral-muted\"\n >\n Run details\n </Text>\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"annotations\"\n current={!currentJobId && activeSection === 'annotations'}\n count={annotationSummary?.total}\n countTruncated={annotationSummary?.truncated}\n onNavigate={onNavigate}\n />\n </li>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"source\"\n current={!currentJobId && activeSection === 'source'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n </section>\n </nav>\n );\n}\n\nfunction RunSectionLink({\n workspaceSlug,\n projectSlug,\n runId,\n runAttempt,\n section,\n current,\n count,\n countTruncated = false,\n onNavigate,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n runAttempt: number;\n section: RunWorkspaceSection;\n current: boolean;\n count?: number | undefined;\n /** The read hit its page budget, so the count is a lower bound and renders as `N+`. */\n countTruncated?: boolean | undefined;\n onNavigate?: (() => void) | undefined;\n}) {\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId}}\n search={\n workflowRunSearchParams(\n {runAttempt, ...(section === 'summary' ? {} : {tab: section})},\n {runAttempt},\n ) as never\n }\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n aria-label={\n count\n ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}`\n : undefined\n }\n className={cn(\n 'flex min-h-32 items-center gap-inline rounded-4 px-tight text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n {sectionLabel(section)}\n {count ? (\n <span\n aria-hidden=\"true\"\n className=\"ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums\"\n >\n {count}\n {countTruncated ? '+' : ''}\n </span>\n ) : null}\n </Link>\n );\n}\n\nfunction sectionLabel(section: RunWorkspaceSection): string {\n if (section === 'annotations') return 'Annotations';\n if (section === 'source') return 'Source';\n return 'Summary';\n}\n\nfunction compareJobs(left: Job, right: Job): number {\n return left.position - right.position || left.id.localeCompare(right.id);\n}\n"],"names":["Collapsible","CollapsibleTrigger","Icon","TimeTickerProvider","Text","cn","Link","useEffect","useMemo","useRef","useState","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","workflowJobSearchParams","workflowRunSearchParams","JobExecutionTimeText","RunWorkspaceNav","workspaceSlug","projectSlug","run","activeSection","currentJobId","jobSearch","annotationSummary","jobs","sort","compareJobs","mobileOpen","setMobileOpen","currentJob","find","job","id","currentLabel","displayName","sectionLabel","intervalMs","reducedMotionIntervalMs","aside","className","open","onOpenChange","asChild","button","type","aria-label","span","as","size","name","aria-hidden","div","RunWorkspaceNavContent","onNavigate","currentRowRef","runAttempt","attempt","current","scrollIntoView","block","nav","ul","li","RunSectionLink","runId","section","aria-labelledby","bold","length","ol","map","execution","duration","displayDuration","ref","undefined","to","params","workflowRunId","jobId","search","onClick","aria-current","status","tooltip","time","count","total","countTruncated","truncated","tab","left","right","position","localeCompare"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-view/run-workspace-nav.tsx"],"sourcesContent":["import {Collapsible, CollapsibleTrigger} from '@shipfox/react-ui/collapsible';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport type {RunAnnotationSummary} from '#core/run-annotation.js';\nimport {\n defaultJobExecution,\n deriveJobDisplayStatus,\n type Job,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport {\n type WorkflowJobSearch,\n type WorkflowRunTab,\n workflowJobSearchParams,\n workflowRunSearchParams,\n} from '#routes/inputs.js';\nimport {JobExecutionTimeText} from '../job-detail/job-execution-time-text.js';\n\ntype RunWorkspaceSection = Exclude<WorkflowRunTab, 'jobs'>;\n\nexport interface RunWorkspaceNavProps {\n workspaceSlug: string;\n projectSlug: string;\n run: WorkflowRunDetail;\n activeSection: RunWorkspaceSection;\n currentJobId?: string | undefined;\n jobSearch?: WorkflowJobSearch | undefined;\n annotationSummary?: RunAnnotationSummary | undefined;\n}\n\n/**\n * The stable navigation model shared by run-level and job-level routes. The graph explains\n * topology; this compact index makes moving between dedicated job pages predictable.\n */\nexport function RunWorkspaceNav({\n workspaceSlug,\n projectSlug,\n run,\n activeSection,\n currentJobId,\n jobSearch = {},\n annotationSummary,\n}: RunWorkspaceNavProps) {\n const jobs = useMemo(() => [...run.jobs].sort(compareJobs), [run.jobs]);\n const [mobileOpen, setMobileOpen] = useState(false);\n const currentJob = jobs.find((job) => job.id === currentJobId);\n const currentLabel = currentJob?.displayName ?? sectionLabel(activeSection);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside className=\"flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base bg-background-neutral-background min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r\">\n <Collapsible\n open={mobileOpen}\n onOpenChange={setMobileOpen}\n className=\"flex min-h-0 flex-col min-[768px]:flex-1\"\n >\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"flex min-h-44 w-full items-center justify-between gap-cluster px-row text-left outline-none focus-visible:shadow-border-interactive-with-active min-[768px]:hidden\"\n aria-label=\"Toggle run navigation\"\n >\n <span className=\"min-w-0\">\n <Text as=\"span\" size=\"xs\" className=\"block text-foreground-neutral-muted\">\n Run navigation\n </Text>\n <span className=\"block truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {currentLabel}\n </span>\n </span>\n <Icon\n name=\"chevronDown\"\n size={14}\n aria-hidden=\"true\"\n className={cn(\n 'shrink-0 text-foreground-neutral-muted transition-transform',\n mobileOpen && 'rotate-180',\n )}\n />\n </button>\n </CollapsibleTrigger>\n <div\n className={cn(\n 'flex min-h-0 max-h-[50vh] flex-col overflow-y-auto p-tight scrollbar min-[768px]:min-h-0 min-[768px]:max-h-none min-[768px]:flex-1 min-[768px]:flex min-[768px]:overflow-hidden min-[768px]:p-[12px]',\n !mobileOpen && 'hidden',\n )}\n >\n <RunWorkspaceNavContent\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n run={run}\n jobs={jobs}\n activeSection={activeSection}\n currentJobId={currentJobId}\n jobSearch={jobSearch}\n annotationSummary={annotationSummary}\n mobileOpen={mobileOpen}\n onNavigate={() => setMobileOpen(false)}\n />\n </div>\n </Collapsible>\n </aside>\n </TimeTickerProvider>\n );\n}\n\nfunction RunWorkspaceNavContent({\n workspaceSlug,\n projectSlug,\n run,\n jobs,\n activeSection,\n currentJobId,\n jobSearch,\n annotationSummary,\n mobileOpen,\n onNavigate,\n}: RunWorkspaceNavProps & {\n jobs: Job[];\n jobSearch: WorkflowJobSearch;\n mobileOpen: boolean;\n onNavigate: () => void;\n}) {\n const currentRowRef = useRef<HTMLAnchorElement>(null);\n const runAttempt = jobSearch.runAttempt ?? run.runAttempt.attempt;\n\n useEffect(() => {\n if (!currentJobId || mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n useEffect(() => {\n if (!currentJobId || !mobileOpen) return;\n currentRowRef.current?.scrollIntoView({block: 'nearest'});\n }, [currentJobId, mobileOpen]);\n\n return (\n <nav aria-label=\"Run workspace\" className=\"flex min-h-0 min-w-0 flex-1 flex-col gap-group\">\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"summary\"\n current={!currentJobId && activeSection === 'summary'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n\n <section\n aria-labelledby=\"run-workspace-jobs-heading\"\n className=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n >\n <div className=\"flex items-center justify-between gap-inline px-tight pb-[6px]\">\n <Text\n as=\"h2\"\n id=\"run-workspace-jobs-heading\"\n size=\"xs\"\n bold\n className=\"text-foreground-neutral-muted\"\n >\n Jobs\n </Text>\n <Text as=\"span\" size=\"xs\" className=\"font-code text-foreground-neutral-subtle\">\n {jobs.length}\n </Text>\n </div>\n <ol className=\"min-h-0 flex-1 overflow-y-auto scrollbar\">\n {jobs.map((job) => {\n const current = job.id === currentJobId;\n const execution = defaultJobExecution(job);\n const duration = execution?.displayDuration ?? job.displayDuration;\n\n return (\n <li key={job.id}>\n <Link\n ref={current ? currentRowRef : undefined}\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId/jobs/$jobId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id, jobId: job.id}}\n search={workflowJobSearchParams({runAttempt}) as never}\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n className={cn(\n 'flex min-h-32 min-w-0 items-center gap-inline rounded-4 px-tight text-left outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n <WorkflowStatusIcon\n status={deriveJobDisplayStatus(job)}\n size={12}\n tooltip={false}\n />\n <span className=\"min-w-0 truncate font-code text-xs leading-20 text-foreground-neutral-base\">\n {job.displayName}\n </span>\n <span className=\"ml-auto shrink-0 font-code text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n {duration ? <JobExecutionTimeText time={duration} /> : '—'}\n </span>\n </Link>\n </li>\n );\n })}\n </ol>\n </section>\n\n <section aria-labelledby=\"run-workspace-details-heading\">\n <Text\n as=\"h2\"\n id=\"run-workspace-details-heading\"\n size=\"xs\"\n bold\n className=\"px-tight pb-[6px] text-foreground-neutral-muted\"\n >\n Run details\n </Text>\n <ul>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"annotations\"\n current={!currentJobId && activeSection === 'annotations'}\n count={annotationSummary?.total}\n countTruncated={annotationSummary?.truncated}\n onNavigate={onNavigate}\n />\n </li>\n <li>\n <RunSectionLink\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n runId={run.id}\n runAttempt={runAttempt}\n section=\"source\"\n current={!currentJobId && activeSection === 'source'}\n onNavigate={onNavigate}\n />\n </li>\n </ul>\n </section>\n </nav>\n );\n}\n\nfunction RunSectionLink({\n workspaceSlug,\n projectSlug,\n runId,\n runAttempt,\n section,\n current,\n count,\n countTruncated = false,\n onNavigate,\n}: {\n workspaceSlug: string;\n projectSlug: string;\n runId: string;\n runAttempt: number;\n section: RunWorkspaceSection;\n current: boolean;\n count?: number | undefined;\n /** The read hit its page budget, so the count is a lower bound and renders as `N+`. */\n countTruncated?: boolean | undefined;\n onNavigate?: (() => void) | undefined;\n}) {\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: runId}}\n search={\n workflowRunSearchParams(\n {runAttempt, ...(section === 'summary' ? {} : {tab: section})},\n {runAttempt},\n ) as never\n }\n onClick={onNavigate}\n aria-current={current ? 'page' : undefined}\n aria-label={\n count\n ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}`\n : undefined\n }\n className={cn(\n 'flex min-h-32 items-center gap-inline rounded-4 px-tight text-xs font-medium text-foreground-neutral-base outline-none transition-colors hover:bg-background-neutral-hover focus-visible:shadow-border-interactive-with-active @max-[767px]:min-h-44 [@media(pointer:coarse)]:min-h-44',\n current && 'bg-background-neutral-hover',\n )}\n >\n {sectionLabel(section)}\n {count ? (\n <span\n aria-hidden=\"true\"\n className=\"ml-auto font-code text-xs text-foreground-neutral-muted tabular-nums\"\n >\n {count}\n {countTruncated ? '+' : ''}\n </span>\n ) : null}\n </Link>\n );\n}\n\nfunction sectionLabel(section: RunWorkspaceSection): string {\n if (section === 'annotations') return 'Annotations';\n if (section === 'source') return 'Source';\n return 'Summary';\n}\n\nfunction compareJobs(left: Job, right: Job): number {\n return left.position - right.position || left.id.localeCompare(right.id);\n}\n"],"names":["Collapsible","CollapsibleTrigger","Icon","TimeTickerProvider","Text","cn","Link","useEffect","useMemo","useRef","useState","WorkflowStatusIcon","defaultJobExecution","deriveJobDisplayStatus","workflowJobSearchParams","workflowRunSearchParams","JobExecutionTimeText","RunWorkspaceNav","workspaceSlug","projectSlug","run","activeSection","currentJobId","jobSearch","annotationSummary","jobs","sort","compareJobs","mobileOpen","setMobileOpen","currentJob","find","job","id","currentLabel","displayName","sectionLabel","intervalMs","reducedMotionIntervalMs","aside","className","open","onOpenChange","asChild","button","type","aria-label","span","as","size","name","aria-hidden","div","RunWorkspaceNavContent","onNavigate","currentRowRef","runAttempt","attempt","current","scrollIntoView","block","nav","ul","li","RunSectionLink","runId","section","aria-labelledby","bold","length","ol","map","execution","duration","displayDuration","ref","undefined","to","params","workflowRunId","jobId","search","onClick","aria-current","status","tooltip","time","count","total","countTruncated","truncated","tab","left","right","position","localeCompare"],"mappings":"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"}
@@ -35,6 +35,7 @@ interface JobExecutionFields {
35
35
  name: string;
36
36
  status: JobExecutionStatus;
37
37
  statusReason: string | null;
38
+ statusReasonMessage: string | null;
38
39
  runner: string[] | null;
39
40
  outputs: Record<string, unknown> | null;
40
41
  triggerEvents: WorkflowExecutionEvent[];
@@ -54,6 +55,7 @@ export declare class JobExecution {
54
55
  name: string;
55
56
  status: JobExecutionStatus;
56
57
  statusReason: string | null;
58
+ statusReasonMessage: string | null;
57
59
  runner: string[] | null;
58
60
  outputs: Record<string, unknown> | null;
59
61
  triggerEvents: WorkflowExecutionEvent[];
@@ -1 +1 @@
1
- {"version":3,"file":"job-execution.d.ts","sourceRoot":"","sources":["../../../src/core/entities/job-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,QAAQ,EAAqB,MAAM,UAAU,CAAC;AAC3D,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,mBAAmB,CAAC;AAE5D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAC9F,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,CAAC;AAC3D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;CACf;AACD,MAAM,MAAM,gBAAgB,GACxB;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAC,GACnC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC;AACrC,MAAM,MAAM,2BAA2B,GACnC,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GAAG,gBAAgB,CAAC,GACpC,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,GAAG,gBAAgB,CAAC,CAAC;AAEvC,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,kBAAkB,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,aAAa,EAAE,sBAAsB,EAAE,CAAC;IACxC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,qBAAa,YAAY;IACvB,EAAE,EAAG,MAAM,CAAC;IACZ,KAAK,EAAG,MAAM,CAAC;IACf,QAAQ,EAAG,MAAM,CAAC;IAClB,IAAI,EAAG,MAAM,CAAC;IACd,MAAM,EAAG,kBAAkB,CAAC;IAC5B,YAAY,EAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAG,MAAM,EAAE,GAAG,IAAI,CAAC;IACzB,OAAO,EAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,aAAa,EAAG,sBAAsB,EAAE,CAAC;IACzC,QAAQ,EAAG,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAG,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAG,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAChD,SAAS,EAAG,MAAM,CAAC;IACnB,SAAS,EAAG,MAAM,CAAC;IACnB,KAAK,EAAG,IAAI,EAAE,CAAC;IAEf,YAAY,MAAM,EAAE,kBAAkB,EAErC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,SAAS,IAAI,gBAAgB,GAAG,IAAI,CAEvC;IAED,IAAI,OAAO,IAAI,gBAAgB,GAAG,IAAI,CAErC;IAED,IAAI,eAAe,IAAI,2BAA2B,GAAG,IAAI,CAExD;CACF;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,MAAM,EACN,KAAK,GACN,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,yBAAyB,CAIpE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAEhF;AAED,wBAAgB,mCAAmC,CAAC,EAClD,QAAQ,EACR,SAAS,EACT,UAAU,GACX,EAAE;IACD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,gBAAgB,GAAG,IAAI,CAO1B;AAED,wBAAgB,iCAAiC,CAAC,EAChD,SAAS,EACT,UAAU,GACX,EAAE;IACD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,gBAAgB,GAAG,IAAI,CAG1B;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,IAAI,EACJ,EAAE,GACH,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB,GAAG,gBAAgB,GAAG,IAAI,CAK1B;AAED,wBAAgB,yCAAyC,CAAC,UAAU,EAAE;IACpE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,2BAA2B,GAAG,IAAI,CAQrC"}
1
+ {"version":3,"file":"job-execution.d.ts","sourceRoot":"","sources":["../../../src/core/entities/job-execution.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/entities/job-execution.ts"],"sourcesContent":["import {type Duration, intervalToDuration} from 'date-fns';\nimport type {Step} from './step.js';\nimport type {EvaluationTraceEntry} from './step-attempt.js';\n\nexport type JobExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';\nexport type JobExecutionDisplayStatus = JobExecutionStatus;\nexport interface WorkflowExecutionEvent {\n source: string;\n event: string;\n deliveryId: string;\n receivedAt: string;\n project: {id: string} | null;\n repository: string | null;\n ref: string | null;\n commit: string | null;\n data: unknown;\n}\nexport type JobExecutionTime =\n | {state: 'fixed'; elapsed: Duration}\n | {state: 'live'; fromIso: string};\nexport type JobExecutionDisplayDuration =\n | ({kind: 'queue'} & JobExecutionTime)\n | ({kind: 'run'} & JobExecutionTime);\n\ninterface JobExecutionFields {\n id: string;\n jobId: string;\n sequence: number;\n name: string;\n status: JobExecutionStatus;\n statusReason: string | null;\n runner: string[] | null;\n outputs: Record<string, unknown> | null;\n triggerEvents: WorkflowExecutionEvent[];\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n timedOutAt: string | null;\n evaluationTrace: EvaluationTraceEntry[] | null;\n createdAt: string;\n updatedAt: string;\n steps: Step[];\n}\n\nexport class JobExecution {\n id!: string;\n jobId!: string;\n sequence!: number;\n name!: string;\n status!: JobExecutionStatus;\n statusReason!: string | null;\n runner!: string[] | null;\n outputs!: Record<string, unknown> | null;\n triggerEvents!: WorkflowExecutionEvent[];\n queuedAt!: string | null;\n startedAt!: string | null;\n finishedAt!: string | null;\n timedOutAt!: string | null;\n evaluationTrace!: EvaluationTraceEntry[] | null;\n createdAt!: string;\n updatedAt!: string;\n steps!: Step[];\n\n constructor(fields: JobExecutionFields) {\n Object.assign(this, fields);\n }\n\n get displayName(): string {\n return this.name;\n }\n\n get queueTime(): JobExecutionTime | null {\n return jobExecutionQueueTimeFromTimestamps(this);\n }\n\n get runTime(): JobExecutionTime | null {\n return jobExecutionRunTimeFromTimestamps(this);\n }\n\n get displayDuration(): JobExecutionDisplayDuration | null {\n return jobExecutionDisplayDurationFromTimestamps(this);\n }\n}\n\nexport function deriveJobExecutionDisplayStatus({\n status,\n steps,\n}: Pick<JobExecution, 'status' | 'steps'>): JobExecutionDisplayStatus {\n if (isTerminalJobExecutionStatus(status)) return status;\n if (steps.some((step) => step.status === 'running')) return 'running';\n return 'pending';\n}\n\nexport function isTerminalJobExecutionStatus(status: JobExecutionStatus): boolean {\n return status === 'succeeded' || status === 'failed' || status === 'cancelled';\n}\n\nexport function jobExecutionQueueTimeFromTimestamps({\n queuedAt,\n startedAt,\n finishedAt,\n}: {\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionTime | null {\n if (queuedAt === null) return null;\n if (finishedAt !== null && startedAt === null) return null;\n if (startedAt === null) return {state: 'live', fromIso: queuedAt};\n\n const elapsed = durationBetween(queuedAt, startedAt);\n return elapsed === null ? null : {state: 'fixed', elapsed};\n}\n\nexport function jobExecutionRunTimeFromTimestamps({\n startedAt,\n finishedAt,\n}: {\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionTime | null {\n if (startedAt === null) return null;\n return elapsedTimeFromTimestamps({from: startedAt, to: finishedAt});\n}\n\n/**\n * The elapsed span between two marks, still accruing while the closing mark is missing. Every\n * duration this app shows is one of these, so queue time and run time measure the same way and\n * only differ in which marks they read.\n */\nexport function elapsedTimeFromTimestamps({\n from,\n to,\n}: {\n from: string;\n to: string | null;\n}): JobExecutionTime | null {\n if (to === null) return {state: 'live', fromIso: from};\n\n const elapsed = durationBetween(from, to);\n return elapsed === null ? null : {state: 'fixed', elapsed};\n}\n\nexport function jobExecutionDisplayDurationFromTimestamps(timestamps: {\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionDisplayDuration | null {\n const runTime = jobExecutionRunTimeFromTimestamps(timestamps);\n if (runTime !== null) return {kind: 'run', ...runTime};\n\n const queueTime = jobExecutionQueueTimeFromTimestamps(timestamps);\n if (queueTime !== null) return {kind: 'queue', ...queueTime};\n\n return null;\n}\n\nfunction durationBetween(from: string, to: string): Duration | null {\n const start = new Date(from);\n const end = new Date(to);\n if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime())) return null;\n\n return intervalToDuration({\n start,\n end: end < start ? start : end,\n });\n}\n"],"names":["intervalToDuration","JobExecution","fields","Object","assign","displayName","name","queueTime","jobExecutionQueueTimeFromTimestamps","runTime","jobExecutionRunTimeFromTimestamps","displayDuration","jobExecutionDisplayDurationFromTimestamps","deriveJobExecutionDisplayStatus","status","steps","isTerminalJobExecutionStatus","some","step","queuedAt","startedAt","finishedAt","state","fromIso","elapsed","durationBetween","elapsedTimeFromTimestamps","from","to","timestamps","kind","start","Date","end","Number","isFinite","getTime"],"mappings":"AAAA,SAAuBA,kBAAkB,QAAO,WAAW;AA4C3D,OAAO,MAAMC;IAmBX,YAAYC,MAA0B,CAAE;QACtCC,OAAOC,MAAM,CAAC,IAAI,EAAEF;IACtB;IAEA,IAAIG,cAAsB;QACxB,OAAO,IAAI,CAACC,IAAI;IAClB;IAEA,IAAIC,YAAqC;QACvC,OAAOC,oCAAoC,IAAI;IACjD;IAEA,IAAIC,UAAmC;QACrC,OAAOC,kCAAkC,IAAI;IAC/C;IAEA,IAAIC,kBAAsD;QACxD,OAAOC,0CAA0C,IAAI;IACvD;AACF;AAEA,OAAO,SAASC,gCAAgC,EAC9CC,MAAM,EACNC,KAAK,EACkC;IACvC,IAAIC,6BAA6BF,SAAS,OAAOA;IACjD,IAAIC,MAAME,IAAI,CAAC,CAACC,OAASA,KAAKJ,MAAM,KAAK,YAAY,OAAO;IAC5D,OAAO;AACT;AAEA,OAAO,SAASE,6BAA6BF,MAA0B;IACrE,OAAOA,WAAW,eAAeA,WAAW,YAAYA,WAAW;AACrE;AAEA,OAAO,SAASN,oCAAoC,EAClDW,QAAQ,EACRC,SAAS,EACTC,UAAU,EAKX;IACC,IAAIF,aAAa,MAAM,OAAO;IAC9B,IAAIE,eAAe,QAAQD,cAAc,MAAM,OAAO;IACtD,IAAIA,cAAc,MAAM,OAAO;QAACE,OAAO;QAAQC,SAASJ;IAAQ;IAEhE,MAAMK,UAAUC,gBAAgBN,UAAUC;IAC1C,OAAOI,YAAY,OAAO,OAAO;QAACF,OAAO;QAASE;IAAO;AAC3D;AAEA,OAAO,SAASd,kCAAkC,EAChDU,SAAS,EACTC,UAAU,EAIX;IACC,IAAID,cAAc,MAAM,OAAO;IAC/B,OAAOM,0BAA0B;QAACC,MAAMP;QAAWQ,IAAIP;IAAU;AACnE;AAEA;;;;CAIC,GACD,OAAO,SAASK,0BAA0B,EACxCC,IAAI,EACJC,EAAE,EAIH;IACC,IAAIA,OAAO,MAAM,OAAO;QAACN,OAAO;QAAQC,SAASI;IAAI;IAErD,MAAMH,UAAUC,gBAAgBE,MAAMC;IACtC,OAAOJ,YAAY,OAAO,OAAO;QAACF,OAAO;QAASE;IAAO;AAC3D;AAEA,OAAO,SAASZ,0CAA0CiB,UAIzD;IACC,MAAMpB,UAAUC,kCAAkCmB;IAClD,IAAIpB,YAAY,MAAM,OAAO;QAACqB,MAAM;QAAO,GAAGrB,OAAO;IAAA;IAErD,MAAMF,YAAYC,oCAAoCqB;IACtD,IAAItB,cAAc,MAAM,OAAO;QAACuB,MAAM;QAAS,GAAGvB,SAAS;IAAA;IAE3D,OAAO;AACT;AAEA,SAASkB,gBAAgBE,IAAY,EAAEC,EAAU;IAC/C,MAAMG,QAAQ,IAAIC,KAAKL;IACvB,MAAMM,MAAM,IAAID,KAAKJ;IACrB,IAAI,CAACM,OAAOC,QAAQ,CAACJ,MAAMK,OAAO,OAAO,CAACF,OAAOC,QAAQ,CAACF,IAAIG,OAAO,KAAK,OAAO;IAEjF,OAAOpC,mBAAmB;QACxB+B;QACAE,KAAKA,MAAMF,QAAQA,QAAQE;IAC7B;AACF"}
1
+ {"version":3,"sources":["../../../src/core/entities/job-execution.ts"],"sourcesContent":["import {type Duration, intervalToDuration} from 'date-fns';\nimport type {Step} from './step.js';\nimport type {EvaluationTraceEntry} from './step-attempt.js';\n\nexport type JobExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';\nexport type JobExecutionDisplayStatus = JobExecutionStatus;\nexport interface WorkflowExecutionEvent {\n source: string;\n event: string;\n deliveryId: string;\n receivedAt: string;\n project: {id: string} | null;\n repository: string | null;\n ref: string | null;\n commit: string | null;\n data: unknown;\n}\nexport type JobExecutionTime =\n | {state: 'fixed'; elapsed: Duration}\n | {state: 'live'; fromIso: string};\nexport type JobExecutionDisplayDuration =\n | ({kind: 'queue'} & JobExecutionTime)\n | ({kind: 'run'} & JobExecutionTime);\n\ninterface JobExecutionFields {\n id: string;\n jobId: string;\n sequence: number;\n name: string;\n status: JobExecutionStatus;\n statusReason: string | null;\n statusReasonMessage: string | null;\n runner: string[] | null;\n outputs: Record<string, unknown> | null;\n triggerEvents: WorkflowExecutionEvent[];\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n timedOutAt: string | null;\n evaluationTrace: EvaluationTraceEntry[] | null;\n createdAt: string;\n updatedAt: string;\n steps: Step[];\n}\n\nexport class JobExecution {\n id!: string;\n jobId!: string;\n sequence!: number;\n name!: string;\n status!: JobExecutionStatus;\n statusReason!: string | null;\n statusReasonMessage!: string | null;\n runner!: string[] | null;\n outputs!: Record<string, unknown> | null;\n triggerEvents!: WorkflowExecutionEvent[];\n queuedAt!: string | null;\n startedAt!: string | null;\n finishedAt!: string | null;\n timedOutAt!: string | null;\n evaluationTrace!: EvaluationTraceEntry[] | null;\n createdAt!: string;\n updatedAt!: string;\n steps!: Step[];\n\n constructor(fields: JobExecutionFields) {\n Object.assign(this, fields);\n }\n\n get displayName(): string {\n return this.name;\n }\n\n get queueTime(): JobExecutionTime | null {\n return jobExecutionQueueTimeFromTimestamps(this);\n }\n\n get runTime(): JobExecutionTime | null {\n return jobExecutionRunTimeFromTimestamps(this);\n }\n\n get displayDuration(): JobExecutionDisplayDuration | null {\n return jobExecutionDisplayDurationFromTimestamps(this);\n }\n}\n\nexport function deriveJobExecutionDisplayStatus({\n status,\n steps,\n}: Pick<JobExecution, 'status' | 'steps'>): JobExecutionDisplayStatus {\n if (isTerminalJobExecutionStatus(status)) return status;\n if (steps.some((step) => step.status === 'running')) return 'running';\n return 'pending';\n}\n\nexport function isTerminalJobExecutionStatus(status: JobExecutionStatus): boolean {\n return status === 'succeeded' || status === 'failed' || status === 'cancelled';\n}\n\nexport function jobExecutionQueueTimeFromTimestamps({\n queuedAt,\n startedAt,\n finishedAt,\n}: {\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionTime | null {\n if (queuedAt === null) return null;\n if (finishedAt !== null && startedAt === null) return null;\n if (startedAt === null) return {state: 'live', fromIso: queuedAt};\n\n const elapsed = durationBetween(queuedAt, startedAt);\n return elapsed === null ? null : {state: 'fixed', elapsed};\n}\n\nexport function jobExecutionRunTimeFromTimestamps({\n startedAt,\n finishedAt,\n}: {\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionTime | null {\n if (startedAt === null) return null;\n return elapsedTimeFromTimestamps({from: startedAt, to: finishedAt});\n}\n\n/**\n * The elapsed span between two marks, still accruing while the closing mark is missing. Every\n * duration this app shows is one of these, so queue time and run time measure the same way and\n * only differ in which marks they read.\n */\nexport function elapsedTimeFromTimestamps({\n from,\n to,\n}: {\n from: string;\n to: string | null;\n}): JobExecutionTime | null {\n if (to === null) return {state: 'live', fromIso: from};\n\n const elapsed = durationBetween(from, to);\n return elapsed === null ? null : {state: 'fixed', elapsed};\n}\n\nexport function jobExecutionDisplayDurationFromTimestamps(timestamps: {\n queuedAt: string | null;\n startedAt: string | null;\n finishedAt: string | null;\n}): JobExecutionDisplayDuration | null {\n const runTime = jobExecutionRunTimeFromTimestamps(timestamps);\n if (runTime !== null) return {kind: 'run', ...runTime};\n\n const queueTime = jobExecutionQueueTimeFromTimestamps(timestamps);\n if (queueTime !== null) return {kind: 'queue', ...queueTime};\n\n return null;\n}\n\nfunction durationBetween(from: string, to: string): Duration | null {\n const start = new Date(from);\n const end = new Date(to);\n if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime())) return null;\n\n return intervalToDuration({\n start,\n end: end < start ? start : end,\n });\n}\n"],"names":["intervalToDuration","JobExecution","fields","Object","assign","displayName","name","queueTime","jobExecutionQueueTimeFromTimestamps","runTime","jobExecutionRunTimeFromTimestamps","displayDuration","jobExecutionDisplayDurationFromTimestamps","deriveJobExecutionDisplayStatus","status","steps","isTerminalJobExecutionStatus","some","step","queuedAt","startedAt","finishedAt","state","fromIso","elapsed","durationBetween","elapsedTimeFromTimestamps","from","to","timestamps","kind","start","Date","end","Number","isFinite","getTime"],"mappings":"AAAA,SAAuBA,kBAAkB,QAAO,WAAW;AA6C3D,OAAO,MAAMC;IAoBX,YAAYC,MAA0B,CAAE;QACtCC,OAAOC,MAAM,CAAC,IAAI,EAAEF;IACtB;IAEA,IAAIG,cAAsB;QACxB,OAAO,IAAI,CAACC,IAAI;IAClB;IAEA,IAAIC,YAAqC;QACvC,OAAOC,oCAAoC,IAAI;IACjD;IAEA,IAAIC,UAAmC;QACrC,OAAOC,kCAAkC,IAAI;IAC/C;IAEA,IAAIC,kBAAsD;QACxD,OAAOC,0CAA0C,IAAI;IACvD;AACF;AAEA,OAAO,SAASC,gCAAgC,EAC9CC,MAAM,EACNC,KAAK,EACkC;IACvC,IAAIC,6BAA6BF,SAAS,OAAOA;IACjD,IAAIC,MAAME,IAAI,CAAC,CAACC,OAASA,KAAKJ,MAAM,KAAK,YAAY,OAAO;IAC5D,OAAO;AACT;AAEA,OAAO,SAASE,6BAA6BF,MAA0B;IACrE,OAAOA,WAAW,eAAeA,WAAW,YAAYA,WAAW;AACrE;AAEA,OAAO,SAASN,oCAAoC,EAClDW,QAAQ,EACRC,SAAS,EACTC,UAAU,EAKX;IACC,IAAIF,aAAa,MAAM,OAAO;IAC9B,IAAIE,eAAe,QAAQD,cAAc,MAAM,OAAO;IACtD,IAAIA,cAAc,MAAM,OAAO;QAACE,OAAO;QAAQC,SAASJ;IAAQ;IAEhE,MAAMK,UAAUC,gBAAgBN,UAAUC;IAC1C,OAAOI,YAAY,OAAO,OAAO;QAACF,OAAO;QAASE;IAAO;AAC3D;AAEA,OAAO,SAASd,kCAAkC,EAChDU,SAAS,EACTC,UAAU,EAIX;IACC,IAAID,cAAc,MAAM,OAAO;IAC/B,OAAOM,0BAA0B;QAACC,MAAMP;QAAWQ,IAAIP;IAAU;AACnE;AAEA;;;;CAIC,GACD,OAAO,SAASK,0BAA0B,EACxCC,IAAI,EACJC,EAAE,EAIH;IACC,IAAIA,OAAO,MAAM,OAAO;QAACN,OAAO;QAAQC,SAASI;IAAI;IAErD,MAAMH,UAAUC,gBAAgBE,MAAMC;IACtC,OAAOJ,YAAY,OAAO,OAAO;QAACF,OAAO;QAASE;IAAO;AAC3D;AAEA,OAAO,SAASZ,0CAA0CiB,UAIzD;IACC,MAAMpB,UAAUC,kCAAkCmB;IAClD,IAAIpB,YAAY,MAAM,OAAO;QAACqB,MAAM;QAAO,GAAGrB,OAAO;IAAA;IAErD,MAAMF,YAAYC,oCAAoCqB;IACtD,IAAItB,cAAc,MAAM,OAAO;QAACuB,MAAM;QAAS,GAAGvB,SAAS;IAAA;IAE3D,OAAO;AACT;AAEA,SAASkB,gBAAgBE,IAAY,EAAEC,EAAU;IAC/C,MAAMG,QAAQ,IAAIC,KAAKL;IACvB,MAAMM,MAAM,IAAID,KAAKJ;IACrB,IAAI,CAACM,OAAOC,QAAQ,CAACJ,MAAMK,OAAO,OAAO,CAACF,OAAOC,QAAQ,CAACF,IAAIG,OAAO,KAAK,OAAO;IAEjF,OAAOpC,mBAAmB;QACxB+B;QACAE,KAAKA,MAAMF,QAAQA,QAAQE;IAC7B;AACF"}
@@ -5,7 +5,7 @@ export type JobDisplayStatus = JobStatus | 'listening';
5
5
  export type JobMode = 'one_shot' | 'listening';
6
6
  export type ListenerStatus = 'inactive' | 'listening' | 'resolved';
7
7
  export type ResolutionReason = 'until' | 'timeout' | 'max_executions' | 'cancelled';
8
- export type JobStatusReason = 'dependency_not_completed' | 'condition_false' | 'default_gate_rejected' | 'condition_rejected' | 'condition_errored' | 'user_cancelled' | 'run_cancelled' | 'timed_out' | 'runner_lost' | 'step_failed' | 'unknown';
8
+ export type JobStatusReason = 'dependency_not_completed' | 'condition_false' | 'default_gate_rejected' | 'condition_rejected' | 'condition_errored' | 'user_cancelled' | 'run_cancelled' | 'timed_out' | 'runner_lost' | 'output_too_large' | 'step_failed' | 'unknown' | 'output_invalid';
9
9
  export interface JobListening {
10
10
  on: Array<{
11
11
  source: string;
@@ -1 +1 @@
1
- {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/core/entities/job.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/core/entities/job.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/entities/job.ts"],"sourcesContent":["import {\n deriveJobExecutionDisplayStatus,\n type JobExecution,\n type JobExecutionDisplayDuration,\n} from './job-execution.js';\nimport type {EvaluationTraceEntry} from './step-attempt.js';\n\nexport type JobStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';\nexport type JobDisplayStatus = JobStatus | 'listening';\nexport type JobMode = 'one_shot' | 'listening';\nexport type ListenerStatus = 'inactive' | 'listening' | 'resolved';\nexport type ResolutionReason = 'until' | 'timeout' | 'max_executions' | 'cancelled';\nexport type JobStatusReason =\n | 'dependency_not_completed'\n | 'condition_false'\n | 'default_gate_rejected'\n | 'condition_rejected'\n | 'condition_errored'\n | 'user_cancelled'\n | 'run_cancelled'\n | 'timed_out'\n | 'runner_lost'\n | 'step_failed'\n | 'unknown';\nexport interface JobListening {\n on: Array<{\n source: string;\n event: string;\n inputs?: Record<string, unknown> | undefined;\n filter?: string | undefined;\n }>;\n until: Array<{\n source: string;\n event: string;\n inputs?: Record<string, unknown> | undefined;\n filter?: string | undefined;\n }> | null;\n timeoutMs: number | null;\n maxExecutions: number | null;\n batch: {\n debounceMs?: number | undefined;\n maxSize?: number | undefined;\n maxWaitMs?: number | undefined;\n } | null;\n onResolve: 'finish' | 'cancel';\n executionTimeoutMs: number | null;\n name: string | null;\n}\n\nexport type JobDisplayDuration = JobExecutionDisplayDuration;\n\nexport const WORKFLOW_JOB_STATUSES = [\n 'pending',\n 'running',\n 'succeeded',\n 'failed',\n 'cancelled',\n 'skipped',\n] as const satisfies readonly JobStatus[];\n\nexport const TERMINAL_WORKFLOW_JOB_STATUSES = [\n 'succeeded',\n 'failed',\n 'cancelled',\n 'skipped',\n] as const satisfies readonly JobStatus[];\n\nconst TERMINAL_JOB_STATUS_SET = new Set<JobStatus>(TERMINAL_WORKFLOW_JOB_STATUSES);\n\ninterface JobFields {\n id: string;\n runAttemptId: string;\n key: string;\n name: string | null;\n mode: JobMode;\n status: JobStatus;\n statusReason: JobStatusReason | null;\n carriedOver: boolean;\n outputs: Record<string, unknown> | null;\n success: string | null;\n runner: string[] | null;\n evaluationTrace: EvaluationTraceEntry[] | null;\n listening: JobListening | null;\n listenerStatus: ListenerStatus;\n resolutionReason: ResolutionReason | null;\n dependencies: string[];\n position: number;\n createdAt: string;\n updatedAt: string;\n jobExecutions: JobExecution[];\n}\n\nexport class Job {\n id!: string;\n runAttemptId!: string;\n key!: string;\n name!: string | null;\n mode!: JobMode;\n status!: JobStatus;\n statusReason!: JobStatusReason | null;\n carriedOver!: boolean;\n outputs!: Record<string, unknown> | null;\n success!: string | null;\n runner!: string[] | null;\n evaluationTrace!: EvaluationTraceEntry[] | null;\n listening!: JobListening | null;\n listenerStatus!: ListenerStatus;\n resolutionReason!: ResolutionReason | null;\n dependencies!: string[];\n position!: number;\n createdAt!: string;\n updatedAt!: string;\n jobExecutions!: JobExecution[];\n\n constructor(fields: JobFields) {\n Object.assign(this, fields);\n }\n\n get displayName(): string {\n return this.name ?? this.key;\n }\n\n get displayDuration(): JobDisplayDuration | null {\n if (this.mode === 'listening') return null;\n if (this.jobExecutions.length !== 1) return null;\n return this.jobExecutions[0]?.displayDuration ?? null;\n }\n\n get executionCountVisible(): boolean {\n return (\n this.jobExecutions.length > 0 && (this.mode === 'listening' || this.jobExecutions.length > 1)\n );\n }\n}\n\nexport function isTerminalJobStatus(status: JobStatus): boolean {\n return TERMINAL_JOB_STATUS_SET.has(status);\n}\n\nexport function deriveJobDisplayStatus(\n job: Pick<Job, 'mode' | 'status' | 'listenerStatus' | 'jobExecutions'>,\n): JobDisplayStatus {\n if (isTerminalJobStatus(job.status)) return job.status;\n if (job.mode === 'listening' && job.listenerStatus === 'listening') return 'listening';\n\n const execution = defaultJobExecution(job);\n return execution ? deriveJobExecutionDisplayStatus(execution) : 'pending';\n}\n\nexport function resolveJobExecution(\n job: Job,\n jobExecutionId: string | undefined,\n): JobExecution | undefined {\n const selectedExecution = jobExecutionId\n ? job.jobExecutions.find((jobExecution) => jobExecution.id === jobExecutionId)\n : undefined;\n if (selectedExecution) return selectedExecution;\n\n return defaultJobExecution(job);\n}\n\nexport function defaultJobExecution(job: Pick<Job, 'jobExecutions'>): JobExecution | undefined {\n const runningExecution = job.jobExecutions.find(\n (jobExecution) => jobExecution.status === 'running',\n );\n if (runningExecution) return runningExecution;\n\n return job.jobExecutions.reduce<JobExecution | undefined>((latest, jobExecution) => {\n if (!latest) return jobExecution;\n return jobExecution.sequence > latest.sequence ? jobExecution : latest;\n }, undefined);\n}\n"],"names":["deriveJobExecutionDisplayStatus","WORKFLOW_JOB_STATUSES","TERMINAL_WORKFLOW_JOB_STATUSES","TERMINAL_JOB_STATUS_SET","Set","Job","fields","Object","assign","displayName","name","key","displayDuration","mode","jobExecutions","length","executionCountVisible","isTerminalJobStatus","status","has","deriveJobDisplayStatus","job","listenerStatus","execution","defaultJobExecution","resolveJobExecution","jobExecutionId","selectedExecution","find","jobExecution","id","undefined","runningExecution","reduce","latest","sequence"],"mappings":"AAAA,SACEA,+BAA+B,QAG1B,qBAAqB;AA+C5B,OAAO,MAAMC,wBAAwB;IACnC;IACA;IACA;IACA;IACA;IACA;CACD,CAAyC;AAE1C,OAAO,MAAMC,iCAAiC;IAC5C;IACA;IACA;IACA;CACD,CAAyC;AAE1C,MAAMC,0BAA0B,IAAIC,IAAeF;AAyBnD,OAAO,MAAMG;IAsBX,YAAYC,MAAiB,CAAE;QAC7BC,OAAOC,MAAM,CAAC,IAAI,EAAEF;IACtB;IAEA,IAAIG,cAAsB;QACxB,OAAO,IAAI,CAACC,IAAI,IAAI,IAAI,CAACC,GAAG;IAC9B;IAEA,IAAIC,kBAA6C;QAC/C,IAAI,IAAI,CAACC,IAAI,KAAK,aAAa,OAAO;QACtC,IAAI,IAAI,CAACC,aAAa,CAACC,MAAM,KAAK,GAAG,OAAO;QAC5C,OAAO,IAAI,CAACD,aAAa,CAAC,EAAE,EAAEF,mBAAmB;IACnD;IAEA,IAAII,wBAAiC;QACnC,OACE,IAAI,CAACF,aAAa,CAACC,MAAM,GAAG,KAAM,CAAA,IAAI,CAACF,IAAI,KAAK,eAAe,IAAI,CAACC,aAAa,CAACC,MAAM,GAAG,CAAA;IAE/F;AACF;AAEA,OAAO,SAASE,oBAAoBC,MAAiB;IACnD,OAAOf,wBAAwBgB,GAAG,CAACD;AACrC;AAEA,OAAO,SAASE,uBACdC,GAAsE;IAEtE,IAAIJ,oBAAoBI,IAAIH,MAAM,GAAG,OAAOG,IAAIH,MAAM;IACtD,IAAIG,IAAIR,IAAI,KAAK,eAAeQ,IAAIC,cAAc,KAAK,aAAa,OAAO;IAE3E,MAAMC,YAAYC,oBAAoBH;IACtC,OAAOE,YAAYvB,gCAAgCuB,aAAa;AAClE;AAEA,OAAO,SAASE,oBACdJ,GAAQ,EACRK,cAAkC;IAElC,MAAMC,oBAAoBD,iBACtBL,IAAIP,aAAa,CAACc,IAAI,CAAC,CAACC,eAAiBA,aAAaC,EAAE,KAAKJ,kBAC7DK;IACJ,IAAIJ,mBAAmB,OAAOA;IAE9B,OAAOH,oBAAoBH;AAC7B;AAEA,OAAO,SAASG,oBAAoBH,GAA+B;IACjE,MAAMW,mBAAmBX,IAAIP,aAAa,CAACc,IAAI,CAC7C,CAACC,eAAiBA,aAAaX,MAAM,KAAK;IAE5C,IAAIc,kBAAkB,OAAOA;IAE7B,OAAOX,IAAIP,aAAa,CAACmB,MAAM,CAA2B,CAACC,QAAQL;QACjE,IAAI,CAACK,QAAQ,OAAOL;QACpB,OAAOA,aAAaM,QAAQ,GAAGD,OAAOC,QAAQ,GAAGN,eAAeK;IAClE,GAAGH;AACL"}
1
+ {"version":3,"sources":["../../../src/core/entities/job.ts"],"sourcesContent":["import {\n deriveJobExecutionDisplayStatus,\n type JobExecution,\n type JobExecutionDisplayDuration,\n} from './job-execution.js';\nimport type {EvaluationTraceEntry} from './step-attempt.js';\n\nexport type JobStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'skipped';\nexport type JobDisplayStatus = JobStatus | 'listening';\nexport type JobMode = 'one_shot' | 'listening';\nexport type ListenerStatus = 'inactive' | 'listening' | 'resolved';\nexport type ResolutionReason = 'until' | 'timeout' | 'max_executions' | 'cancelled';\nexport type JobStatusReason =\n | 'dependency_not_completed'\n | 'condition_false'\n | 'default_gate_rejected'\n | 'condition_rejected'\n | 'condition_errored'\n | 'user_cancelled'\n | 'run_cancelled'\n | 'timed_out'\n | 'runner_lost'\n | 'output_too_large'\n | 'step_failed'\n | 'unknown'\n | 'output_invalid';\nexport interface JobListening {\n on: Array<{\n source: string;\n event: string;\n inputs?: Record<string, unknown> | undefined;\n filter?: string | undefined;\n }>;\n until: Array<{\n source: string;\n event: string;\n inputs?: Record<string, unknown> | undefined;\n filter?: string | undefined;\n }> | null;\n timeoutMs: number | null;\n maxExecutions: number | null;\n batch: {\n debounceMs?: number | undefined;\n maxSize?: number | undefined;\n maxWaitMs?: number | undefined;\n } | null;\n onResolve: 'finish' | 'cancel';\n executionTimeoutMs: number | null;\n name: string | null;\n}\n\nexport type JobDisplayDuration = JobExecutionDisplayDuration;\n\nexport const WORKFLOW_JOB_STATUSES = [\n 'pending',\n 'running',\n 'succeeded',\n 'failed',\n 'cancelled',\n 'skipped',\n] as const satisfies readonly JobStatus[];\n\nexport const TERMINAL_WORKFLOW_JOB_STATUSES = [\n 'succeeded',\n 'failed',\n 'cancelled',\n 'skipped',\n] as const satisfies readonly JobStatus[];\n\nconst TERMINAL_JOB_STATUS_SET = new Set<JobStatus>(TERMINAL_WORKFLOW_JOB_STATUSES);\n\ninterface JobFields {\n id: string;\n runAttemptId: string;\n key: string;\n name: string | null;\n mode: JobMode;\n status: JobStatus;\n statusReason: JobStatusReason | null;\n carriedOver: boolean;\n outputs: Record<string, unknown> | null;\n success: string | null;\n runner: string[] | null;\n evaluationTrace: EvaluationTraceEntry[] | null;\n listening: JobListening | null;\n listenerStatus: ListenerStatus;\n resolutionReason: ResolutionReason | null;\n dependencies: string[];\n position: number;\n createdAt: string;\n updatedAt: string;\n jobExecutions: JobExecution[];\n}\n\nexport class Job {\n id!: string;\n runAttemptId!: string;\n key!: string;\n name!: string | null;\n mode!: JobMode;\n status!: JobStatus;\n statusReason!: JobStatusReason | null;\n carriedOver!: boolean;\n outputs!: Record<string, unknown> | null;\n success!: string | null;\n runner!: string[] | null;\n evaluationTrace!: EvaluationTraceEntry[] | null;\n listening!: JobListening | null;\n listenerStatus!: ListenerStatus;\n resolutionReason!: ResolutionReason | null;\n dependencies!: string[];\n position!: number;\n createdAt!: string;\n updatedAt!: string;\n jobExecutions!: JobExecution[];\n\n constructor(fields: JobFields) {\n Object.assign(this, fields);\n }\n\n get displayName(): string {\n return this.name ?? this.key;\n }\n\n get displayDuration(): JobDisplayDuration | null {\n if (this.mode === 'listening') return null;\n if (this.jobExecutions.length !== 1) return null;\n return this.jobExecutions[0]?.displayDuration ?? null;\n }\n\n get executionCountVisible(): boolean {\n return (\n this.jobExecutions.length > 0 && (this.mode === 'listening' || this.jobExecutions.length > 1)\n );\n }\n}\n\nexport function isTerminalJobStatus(status: JobStatus): boolean {\n return TERMINAL_JOB_STATUS_SET.has(status);\n}\n\nexport function deriveJobDisplayStatus(\n job: Pick<Job, 'mode' | 'status' | 'listenerStatus' | 'jobExecutions'>,\n): JobDisplayStatus {\n if (isTerminalJobStatus(job.status)) return job.status;\n if (job.mode === 'listening' && job.listenerStatus === 'listening') return 'listening';\n\n const execution = defaultJobExecution(job);\n return execution ? deriveJobExecutionDisplayStatus(execution) : 'pending';\n}\n\nexport function resolveJobExecution(\n job: Job,\n jobExecutionId: string | undefined,\n): JobExecution | undefined {\n const selectedExecution = jobExecutionId\n ? job.jobExecutions.find((jobExecution) => jobExecution.id === jobExecutionId)\n : undefined;\n if (selectedExecution) return selectedExecution;\n\n return defaultJobExecution(job);\n}\n\nexport function defaultJobExecution(job: Pick<Job, 'jobExecutions'>): JobExecution | undefined {\n const runningExecution = job.jobExecutions.find(\n (jobExecution) => jobExecution.status === 'running',\n );\n if (runningExecution) return runningExecution;\n\n return job.jobExecutions.reduce<JobExecution | undefined>((latest, jobExecution) => {\n if (!latest) return jobExecution;\n return jobExecution.sequence > latest.sequence ? jobExecution : latest;\n }, undefined);\n}\n"],"names":["deriveJobExecutionDisplayStatus","WORKFLOW_JOB_STATUSES","TERMINAL_WORKFLOW_JOB_STATUSES","TERMINAL_JOB_STATUS_SET","Set","Job","fields","Object","assign","displayName","name","key","displayDuration","mode","jobExecutions","length","executionCountVisible","isTerminalJobStatus","status","has","deriveJobDisplayStatus","job","listenerStatus","execution","defaultJobExecution","resolveJobExecution","jobExecutionId","selectedExecution","find","jobExecution","id","undefined","runningExecution","reduce","latest","sequence"],"mappings":"AAAA,SACEA,+BAA+B,QAG1B,qBAAqB;AAiD5B,OAAO,MAAMC,wBAAwB;IACnC;IACA;IACA;IACA;IACA;IACA;CACD,CAAyC;AAE1C,OAAO,MAAMC,iCAAiC;IAC5C;IACA;IACA;IACA;CACD,CAAyC;AAE1C,MAAMC,0BAA0B,IAAIC,IAAeF;AAyBnD,OAAO,MAAMG;IAsBX,YAAYC,MAAiB,CAAE;QAC7BC,OAAOC,MAAM,CAAC,IAAI,EAAEF;IACtB;IAEA,IAAIG,cAAsB;QACxB,OAAO,IAAI,CAACC,IAAI,IAAI,IAAI,CAACC,GAAG;IAC9B;IAEA,IAAIC,kBAA6C;QAC/C,IAAI,IAAI,CAACC,IAAI,KAAK,aAAa,OAAO;QACtC,IAAI,IAAI,CAACC,aAAa,CAACC,MAAM,KAAK,GAAG,OAAO;QAC5C,OAAO,IAAI,CAACD,aAAa,CAAC,EAAE,EAAEF,mBAAmB;IACnD;IAEA,IAAII,wBAAiC;QACnC,OACE,IAAI,CAACF,aAAa,CAACC,MAAM,GAAG,KAAM,CAAA,IAAI,CAACF,IAAI,KAAK,eAAe,IAAI,CAACC,aAAa,CAACC,MAAM,GAAG,CAAA;IAE/F;AACF;AAEA,OAAO,SAASE,oBAAoBC,MAAiB;IACnD,OAAOf,wBAAwBgB,GAAG,CAACD;AACrC;AAEA,OAAO,SAASE,uBACdC,GAAsE;IAEtE,IAAIJ,oBAAoBI,IAAIH,MAAM,GAAG,OAAOG,IAAIH,MAAM;IACtD,IAAIG,IAAIR,IAAI,KAAK,eAAeQ,IAAIC,cAAc,KAAK,aAAa,OAAO;IAE3E,MAAMC,YAAYC,oBAAoBH;IACtC,OAAOE,YAAYvB,gCAAgCuB,aAAa;AAClE;AAEA,OAAO,SAASE,oBACdJ,GAAQ,EACRK,cAAkC;IAElC,MAAMC,oBAAoBD,iBACtBL,IAAIP,aAAa,CAACc,IAAI,CAAC,CAACC,eAAiBA,aAAaC,EAAE,KAAKJ,kBAC7DK;IACJ,IAAIJ,mBAAmB,OAAOA;IAE9B,OAAOH,oBAAoBH;AAC7B;AAEA,OAAO,SAASG,oBAAoBH,GAA+B;IACjE,MAAMW,mBAAmBX,IAAIP,aAAa,CAACc,IAAI,CAC7C,CAACC,eAAiBA,aAAaX,MAAM,KAAK;IAE5C,IAAIc,kBAAkB,OAAOA;IAE7B,OAAOX,IAAIP,aAAa,CAACmB,MAAM,CAA2B,CAACC,QAAQL;QACjE,IAAI,CAACK,QAAQ,OAAOL;QACpB,OAAOA,aAAaM,QAAQ,GAAGD,OAAOC,QAAQ,GAAGN,eAAeK;IAClE,GAAGH;AACL"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workflow-run-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,4BAA4B,EAC5B,cAAc,EAGd,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,oBAAoB,EACzB,GAAG,EACH,YAAY,EAEZ,KAAK,IAAI,EACT,WAAW,EAGX,KAAK,WAAW,EAChB,kBAAkB,EAElB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EAGvB,MAAM,uBAAuB,CAAC;AAE/B,wBAAgB,aAAa,CAAC,GAAG,EAAE,sBAAsB,GAAG,WAAW,CA8BtE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,kBAAkB,CAWnF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,sBAAsB,GAAG,iBAAiB,CAclF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,sBAAsB,GAAG,mBAAmB,CAkBtF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,0BAA0B,GAAG,mBAAmB,CAM1F;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CAOxF;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,uBAAuB,GAAG,GAAG,CAuBvD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,gCAAgC,GAAG,YAAY,CAoBlF;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CA+B1D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,GAAG,WAAW,CAkBtF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,4BAA4B;IAEjE,MAAM;IACN,OAAO;IACP,cAAc;IACd,MAAM;IACN,eAAe;EAElB"}
1
+ {"version":3,"file":"workflow-run-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workflow-run-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,4BAA4B,EAC5B,cAAc,EAGd,qBAAqB,EACrB,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,oBAAoB,EACzB,GAAG,EACH,YAAY,EAEZ,KAAK,IAAI,EACT,WAAW,EAGX,KAAK,WAAW,EAChB,kBAAkB,EAElB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EAGvB,MAAM,uBAAuB,CAAC;AAE/B,wBAAgB,aAAa,CAAC,GAAG,EAAE,sBAAsB,GAAG,WAAW,CA8BtE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,kBAAkB,CAWnF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,sBAAsB,GAAG,iBAAiB,CAclF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,sBAAsB,GAAG,mBAAmB,CAkBtF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,0BAA0B,GAAG,mBAAmB,CAM1F;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,4BAA4B,GAAG,iBAAiB,CAOxF;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,uBAAuB,GAAG,GAAG,CAuBvD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,gCAAgC,GAAG,YAAY,CAqBlF;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CA+B1D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,GAAG,WAAW,CAkBtF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,4BAA4B;IAEjE,MAAM;IACN,OAAO;IACP,cAAc;IACd,MAAM;IACN,eAAe;EAElB"}
@@ -127,6 +127,7 @@ export function toJobExecution(dto) {
127
127
  name: dto.name,
128
128
  status: dto.status,
129
129
  statusReason: dto.status_reason,
130
+ statusReasonMessage: dto.status_reason_message ?? null,
130
131
  runner: dto.runner ?? null,
131
132
  outputs: dto.outputs ?? null,
132
133
  triggerEvents: (dto.trigger_events ?? []).map(toWorkflowExecutionEvent),