@shipfox/client-workflows 21.0.0 → 22.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +22 -0
- package/dist/components/job-detail/job-detail-view.js +1 -2
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/job-empty-states.js +2 -2
- package/dist/components/job-detail/job-empty-states.js.map +1 -1
- package/dist/components/job-graph/job-graph-content.js +2 -2
- package/dist/components/job-graph/job-graph-content.js.map +1 -1
- package/dist/components/step-list/step-list.js +1 -2
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-content.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-content.js +13 -7
- package/dist/components/workflow-run-list/workflow-run-list-content.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +42 -37
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +14 -10
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +3 -3
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.d.ts.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +20 -7
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +68 -50
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/pages/project-workflows-page.js +170 -158
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/job-detail/job-detail-view.tsx +1 -2
- package/src/components/job-detail/job-empty-states.tsx +2 -2
- package/src/components/job-graph/job-graph-content.tsx +2 -2
- package/src/components/step-list/step-list.tsx +1 -2
- package/src/components/workflow-run-list/workflow-run-list-content.tsx +7 -2
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +41 -40
- package/src/components/workflow-run-list/workflow-run-row.tsx +11 -8
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +1 -1
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +9 -1
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +3 -3
- package/src/components/workflow-run-view/run-workspace-nav.test.tsx +40 -2
- package/src/components/workflow-run-view/run-workspace-nav.tsx +28 -9
- package/src/components/workflow-run-view/workflow-run-view.stories.tsx +3 -1
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +11 -8
- package/src/components/workflow-run-view/workflow-run-view.tsx +78 -70
- package/src/pages/project-workflows-page.tsx +134 -125
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {MetadataSeparator} from '@shipfox/client-ui';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport {WorkflowRunNumberLabel} from '#components/workflow-run-number-label.js';\nimport {\n isWorkflowRunTerminal,\n type Job,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRunDetail,\n type WorkflowRunRerunMode,\n} from '#core/workflow-run.js';\nimport {WorkflowRunDurationLabel} from '../workflow-run-duration-label.js';\nimport {getWorkflowStatusVisual} from '../workflow-status/status-visuals.js';\nimport {WorkflowRunAttemptSwitcher} from './workflow-run-attempt-switcher.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_RUN_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\nconst RERUN_BUTTON_SURFACE_CLASS_NAME =\n 'bg-background-neutral-base hover:bg-background-neutral-hover active:bg-background-neutral-pressed';\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n run: WorkflowRunDetail;\n cancelling?: boolean | undefined;\n onCancel?: (() => void) | undefined;\n rerunPending?: boolean | undefined;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n latestAttempt?: number | undefined;\n}\n\nexport function WorkflowRunSummary({\n workspaceSlug,\n projectSlug,\n run,\n cancelling = false,\n onCancel,\n rerunPending = false,\n onRerun,\n latestAttempt,\n}: WorkflowRunSummaryProps) {\n const headingId = useId();\n const status = getWorkflowStatusVisual(run.runAttempt.status);\n const action = workflowRunActionForRun(run);\n const hasAction = canRenderWorkflowRunAction(action, onCancel, onRerun);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceSlug && projectSlug\n ? {workspaceSlug, projectSlug, latestAttempt}\n : null;\n const displayDuration = run.runAttempt.displayDuration;\n const hasStarted = run.hasStartedJobExecution;\n const {ref: headingTextRef, isTruncated: isHeadingTruncated} =\n useIsTextTruncated<HTMLSpanElement>(run.name);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section aria-labelledby={headingId} className=\"px-row py-row\">\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1\">\n <div className=\"col-start-1 row-start-1 min-w-0 max-[480px]:col-start-auto max-[480px]:row-start-auto\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Badge variant={status.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {status.label}\n </span>\n </Badge>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <Header as=\"h1\" id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span ref={headingTextRef} className=\"block min-w-0 truncate\">\n {run.name}\n </span>\n </Header>\n </TooltipTrigger>\n {isHeadingTruncated ? (\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"max-w-[360px] break-words\">\n {run.name}\n </Text>\n </TooltipContent>\n ) : null}\n </Tooltip>\n </div>\n </div>\n\n {hasAction ? (\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-inline justify-self-end max-[480px]:col-start-auto max-[480px]:row-start-auto max-[480px]:justify-self-start\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n </div>\n ) : null}\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-cluster overflow-hidden text-foreground-neutral-subtle max-[480px]:col-span-1 max-[480px]:row-start-auto\">\n {run.number !== null ? (\n <>\n <WorkflowRunNumberLabel run={run} />\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n </>\n ) : null}\n\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceSlug={attemptSwitcher.workspaceSlug}\n projectSlug={attemptSwitcher.projectSlug}\n run={run}\n latestAttempt={attemptSwitcher.latestAttempt}\n />\n ) : null}\n\n {run.triggerDisplayLabel ? (\n <>\n {attemptSwitcher ? <MetadataSeparator /> : null}\n <span className=\"min-w-0\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={run.triggerLabel}\n className=\"inline-flex max-w-full min-w-0 cursor-help items-center gap-tight rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-subtle outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {run.triggerLabel}\n </Text>\n </TooltipContent>\n </Tooltip>\n </span>\n </>\n ) : null}\n\n {run.number !== null || attemptSwitcher || run.triggerDisplayLabel ? (\n <MetadataSeparator />\n ) : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-subtle\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n hasStarted={hasStarted}\n className=\"text-foreground-neutral-subtle\"\n />\n </>\n ) : null}\n </div>\n </div>\n </section>\n </TimeTickerProvider>\n );\n}\n\nfunction WorkflowRunActionSlot({\n action,\n cancelling,\n onCancel,\n rerunPending,\n onRerun,\n}: {\n action: WorkflowRunAction;\n cancelling: boolean;\n onCancel?: (() => void) | undefined;\n rerunPending: boolean;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n}) {\n if (action === 'none') return null;\n\n if (action === 'cancel') {\n if (!onCancel) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"danger\"\n size=\"xs\"\n isLoading={cancelling}\n disabled={cancelling}\n onClick={onCancel}\n >\n Cancel workflow\n </Button>\n );\n }\n\n if (action === 'rerun-all') {\n if (!onRerun) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n className={RERUN_BUTTON_SURFACE_CLASS_NAME}\n isLoading={rerunPending}\n disabled={rerunPending}\n onClick={() => onRerun('all')}\n >\n Re-run workflow\n </Button>\n );\n }\n\n if (!onRerun) return null;\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n className={RERUN_BUTTON_SURFACE_CLASS_NAME}\n iconRight=\"arrowDownSLine\"\n isLoading={rerunPending}\n disabled={rerunPending}\n >\n Re-run jobs\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('all')}>\n Re-run all jobs\n </DropdownMenuItem>\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('failed')}>\n Re-run failed jobs\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction workflowRunActionForRun(run: WorkflowRunDetail): WorkflowRunAction {\n if (run.runAttempt.attempt !== run.currentAttempt) return 'none';\n if (!isWorkflowRunTerminal(run.runAttempt.status)) return 'cancel';\n if (run.runAttempt.status === 'succeeded' || !hasFailedOrCancelledJobs(run)) return 'rerun-all';\n return 'rerun-menu';\n}\n\nfunction canRenderWorkflowRunAction(\n action: WorkflowRunAction,\n onCancel: (() => void) | undefined,\n onRerun: ((mode: WorkflowRunRerunMode) => void) | undefined,\n): boolean {\n if (action === 'cancel') return onCancel !== undefined;\n if (action === 'rerun-all' || action === 'rerun-menu') return onRerun !== undefined;\n return false;\n}\n\nfunction hasFailedOrCancelledJobs(run: WorkflowRunDetail): boolean {\n if (!workflowRunHasJobs(run)) return false;\n\n return run.jobs.some((job) => job.status === 'failed' || job.status === 'cancelled');\n}\n\nfunction workflowRunHasJobs(run: WorkflowRunDetail): run is WorkflowRunDetail & {jobs: Job[]} {\n return 'jobs' in run && Array.isArray(run.jobs);\n}\n"],"names":["TriggerSourceIcon","MetadataSeparator","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useId","WorkflowRunNumberLabel","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","RERUN_BUTTON_SURFACE_CLASS_NAME","WorkflowRunSummary","workspaceSlug","projectSlug","run","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","runAttempt","action","workflowRunActionForRun","hasAction","canRenderWorkflowRunAction","attemptSwitcher","displayDuration","hasStarted","hasStartedJobExecution","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","as","id","WorkflowRunActionSlot","number","triggerDisplayLabel","button","type","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","createdAt","duration","isLoading","disabled","onClick","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","undefined","workflowRunHasJobs","jobs","some","job","Array","isArray"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {MetadataSeparator} from '@shipfox/client-ui';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport {WorkflowRunNumberLabel} from '#components/workflow-run-number-label.js';\nimport {\n isWorkflowRunTerminal,\n type Job,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRunDetail,\n type WorkflowRunRerunMode,\n} from '#core/workflow-run.js';\nimport {WorkflowRunDurationLabel} from '../workflow-run-duration-label.js';\nimport {getWorkflowStatusVisual} from '../workflow-status/status-visuals.js';\nimport {WorkflowRunAttemptSwitcher} from './workflow-run-attempt-switcher.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_RUN_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\nconst NEUTRAL_ACTION_SURFACE_CLASS_NAME =\n 'bg-background-neutral-base hover:bg-background-neutral-hover active:bg-background-neutral-pressed';\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n run: WorkflowRunDetail;\n cancelling?: boolean | undefined;\n onCancel?: (() => void) | undefined;\n rerunPending?: boolean | undefined;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n latestAttempt?: number | undefined;\n}\n\nexport function WorkflowRunSummary({\n workspaceSlug,\n projectSlug,\n run,\n cancelling = false,\n onCancel,\n rerunPending = false,\n onRerun,\n latestAttempt,\n}: WorkflowRunSummaryProps) {\n const headingId = useId();\n const status = getWorkflowStatusVisual(run.runAttempt.status);\n const action = workflowRunActionForRun(run);\n const hasAction = canRenderWorkflowRunAction(action, onCancel, onRerun);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceSlug && projectSlug\n ? {workspaceSlug, projectSlug, latestAttempt}\n : null;\n const displayDuration = run.runAttempt.displayDuration;\n const hasStarted = run.hasStartedJobExecution;\n const {ref: headingTextRef, isTruncated: isHeadingTruncated} =\n useIsTextTruncated<HTMLSpanElement>(run.name);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section aria-labelledby={headingId} className=\"px-row py-row\">\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1\">\n <div className=\"col-start-1 row-start-1 min-w-0 max-[480px]:col-start-auto max-[480px]:row-start-auto\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Badge variant={status.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {status.label}\n </span>\n </Badge>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <Header as=\"h1\" id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span ref={headingTextRef} className=\"block min-w-0 truncate\">\n {run.name}\n </span>\n </Header>\n </TooltipTrigger>\n {isHeadingTruncated ? (\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"max-w-[360px] break-words\">\n {run.name}\n </Text>\n </TooltipContent>\n ) : null}\n </Tooltip>\n </div>\n </div>\n\n {hasAction ? (\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-inline justify-self-end max-[480px]:col-start-auto max-[480px]:row-start-auto max-[480px]:justify-self-start\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n </div>\n ) : null}\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-cluster overflow-hidden text-foreground-neutral-subtle max-[480px]:col-span-1 max-[480px]:row-start-auto\">\n {run.number !== null ? (\n <>\n <WorkflowRunNumberLabel run={run} />\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n </>\n ) : null}\n\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceSlug={attemptSwitcher.workspaceSlug}\n projectSlug={attemptSwitcher.projectSlug}\n run={run}\n latestAttempt={attemptSwitcher.latestAttempt}\n />\n ) : null}\n\n {run.triggerDisplayLabel ? (\n <>\n {attemptSwitcher ? <MetadataSeparator /> : null}\n <span className=\"min-w-0\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={run.triggerLabel}\n className=\"inline-flex max-w-full min-w-0 cursor-help items-center gap-tight rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-subtle outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {run.triggerLabel}\n </Text>\n </TooltipContent>\n </Tooltip>\n </span>\n </>\n ) : null}\n\n {run.number !== null || attemptSwitcher || run.triggerDisplayLabel ? (\n <MetadataSeparator />\n ) : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-subtle\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n hasStarted={hasStarted}\n className=\"text-foreground-neutral-subtle\"\n />\n </>\n ) : null}\n </div>\n </div>\n </section>\n </TimeTickerProvider>\n );\n}\n\nfunction WorkflowRunActionSlot({\n action,\n cancelling,\n onCancel,\n rerunPending,\n onRerun,\n}: {\n action: WorkflowRunAction;\n cancelling: boolean;\n onCancel?: (() => void) | undefined;\n rerunPending: boolean;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n}) {\n if (action === 'none') return null;\n\n if (action === 'cancel') {\n if (!onCancel) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"danger\"\n size=\"xs\"\n isLoading={cancelling}\n disabled={cancelling}\n onClick={onCancel}\n >\n Cancel workflow\n </Button>\n );\n }\n\n if (action === 'rerun-all') {\n if (!onRerun) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n className={NEUTRAL_ACTION_SURFACE_CLASS_NAME}\n isLoading={rerunPending}\n disabled={rerunPending}\n onClick={() => onRerun('all')}\n >\n Re-run workflow\n </Button>\n );\n }\n\n if (!onRerun) return null;\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n className={NEUTRAL_ACTION_SURFACE_CLASS_NAME}\n iconRight=\"arrowDownSLine\"\n isLoading={rerunPending}\n disabled={rerunPending}\n >\n Re-run jobs\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('all')}>\n Re-run all jobs\n </DropdownMenuItem>\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('failed')}>\n Re-run failed jobs\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction workflowRunActionForRun(run: WorkflowRunDetail): WorkflowRunAction {\n if (run.runAttempt.attempt !== run.currentAttempt) return 'none';\n if (!isWorkflowRunTerminal(run.runAttempt.status)) return 'cancel';\n if (run.runAttempt.status === 'succeeded' || !hasFailedOrCancelledJobs(run)) return 'rerun-all';\n return 'rerun-menu';\n}\n\nfunction canRenderWorkflowRunAction(\n action: WorkflowRunAction,\n onCancel: (() => void) | undefined,\n onRerun: ((mode: WorkflowRunRerunMode) => void) | undefined,\n): boolean {\n if (action === 'cancel') return onCancel !== undefined;\n if (action === 'rerun-all' || action === 'rerun-menu') return onRerun !== undefined;\n return false;\n}\n\nfunction hasFailedOrCancelledJobs(run: WorkflowRunDetail): boolean {\n if (!workflowRunHasJobs(run)) return false;\n\n return run.jobs.some((job) => job.status === 'failed' || job.status === 'cancelled');\n}\n\nfunction workflowRunHasJobs(run: WorkflowRunDetail): run is WorkflowRunDetail & {jobs: Job[]} {\n return 'jobs' in run && Array.isArray(run.jobs);\n}\n"],"names":["TriggerSourceIcon","MetadataSeparator","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useId","WorkflowRunNumberLabel","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","NEUTRAL_ACTION_SURFACE_CLASS_NAME","WorkflowRunSummary","workspaceSlug","projectSlug","run","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","runAttempt","action","workflowRunActionForRun","hasAction","canRenderWorkflowRunAction","attemptSwitcher","displayDuration","hasStarted","hasStartedJobExecution","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","as","id","WorkflowRunActionSlot","number","triggerDisplayLabel","button","type","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","createdAt","duration","isLoading","disabled","onClick","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","undefined","workflowRunHasJobs","jobs","some","job","Array","isArray"],"mappings":";AAAA,SAAQA,iBAAiB,QAAO,2BAA2B;AAC3D,SAAQC,iBAAiB,QAAO,qBAAqB;AACrD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,YAAY,QAAO,kCAAkC;AAC7D,SAAQC,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,KAAK,QAAO,QAAQ;AAC5B,SAAQC,sBAAsB,QAAO,2CAA2C;AAChF,SACEC,qBAAqB,EAErBC,qBAAqB,QAGhB,wBAAwB;AAC/B,SAAQC,wBAAwB,QAAO,oCAAoC;AAC3E,SAAQC,uBAAuB,QAAO,uCAAuC;AAC7E,SAAQC,0BAA0B,QAAO,qCAAqC;AAE9E,MAAMC,8BAA8BC,KAAKC,GAAG,IACvCN,sBAAsBO,GAAG,CAAC,CAACC,SAAWN,wBAAwBM,QAAQC,KAAK,CAACC,MAAM;AAEvF,MAAMC,oCACJ;AAeF,OAAO,SAASC,mBAAmB,EACjCC,aAAa,EACbC,WAAW,EACXC,GAAG,EACHC,aAAa,KAAK,EAClBC,QAAQ,EACRC,eAAe,KAAK,EACpBC,OAAO,EACPC,aAAa,EACW;IACxB,MAAMC,YAAYxB;IAClB,MAAMW,SAASN,wBAAwBa,IAAIO,UAAU,CAACd,MAAM;IAC5D,MAAMe,SAASC,wBAAwBT;IACvC,MAAMU,YAAYC,2BAA2BH,QAAQN,UAAUE;IAC/D,MAAMQ,kBACJP,iBAAiBA,gBAAgB,KAAKP,iBAAiBC,cACnD;QAACD;QAAeC;QAAaM;IAAa,IAC1C;IACN,MAAMQ,kBAAkBb,IAAIO,UAAU,CAACM,eAAe;IACtD,MAAMC,aAAad,IAAIe,sBAAsB;IAC7C,MAAM,EAACC,KAAKC,cAAc,EAAEC,aAAaC,kBAAkB,EAAC,GAC1D7C,mBAAoC0B,IAAIoB,IAAI;IAE9C,qBACE,KAAC5C;QAAmB6C,YAAY;QAAMC,yBAAyB;kBAC7D,cAAA,KAACC;YAAQC,mBAAiBlB;YAAWmB,WAAU;sBAC7C,cAAA,MAACC;gBAAID,WAAU;;kCACb,KAACC;wBAAID,WAAU;kCACb,cAAA,MAACC;4BAAID,WAAU;;8CACb,KAACzD;oCAAM2D,SAASlC,OAAOmC,KAAK;oCAAEC,MAAK;8CACjC,cAAA,KAACC;wCAAKL,WAAU;wCAAcM,OAAO;4CAACC,OAAO,GAAG3C,4BAA4B,EAAE,CAAC;wCAAA;kDAC5EI,OAAOC,KAAK;;;8CAIjB,MAACjB;;sDACC,KAACE;4CAAesD,OAAO;sDACrB,cAAA,KAACrD;gDAAOsD,IAAG;gDAAKC,IAAI7B;gDAAWqB,SAAQ;gDAAKF,WAAU;0DACpD,cAAA,KAACK;oDAAKd,KAAKC;oDAAgBQ,WAAU;8DAClCzB,IAAIoB,IAAI;;;;wCAIdD,mCACC,KAACzC;sDACC,cAAA,KAACG;gDAAKqD,IAAG;gDAAOL,MAAK;gDAAKJ,WAAU;0DACjCzB,IAAIoB,IAAI;;6CAGX;;;;;;oBAKTV,0BACC,KAACgB;wBAAID,WAAU;kCACb,cAAA,KAACW;4BACC5B,QAAQA;4BACRP,YAAYA;4BACZC,UAAUA;4BACVC,cAAcA;4BACdC,SAASA;;yBAGX;kCAEJ,MAACsB;wBAAID,WAAU;;4BACZzB,IAAIqC,MAAM,KAAK,qBACd;;kDACE,KAACtD;wCAAuBiB,KAAKA;;oCAC5BY,mBAAmBZ,IAAIsC,mBAAmB,iBAAG,KAACvE,yBAAuB;;iCAEtE;4BAEH6C,gCACC,KAACxB;gCACCU,eAAec,gBAAgBd,aAAa;gCAC5CC,aAAaa,gBAAgBb,WAAW;gCACxCC,KAAKA;gCACLK,eAAeO,gBAAgBP,aAAa;iCAE5C;4BAEHL,IAAIsC,mBAAmB,iBACtB;;oCACG1B,gCAAkB,KAAC7C,yBAAuB;kDAC3C,KAAC+D;wCAAKL,WAAU;kDACd,cAAA,MAAChD;;8DACC,KAACE;oDAAesD,OAAO;8DACrB,cAAA,MAACM;wDACCC,MAAK;wDACLC,cAAYzC,IAAI0C,YAAY;wDAC5BjB,WAAU;;0EAEV,KAAC3D;gEACC6E,UAAU3C,IAAI4C,eAAe;gEAC7BC,QAAQ7C,IAAI8C,aAAa;gEACzBC,eAAY;gEACZtB,WAAU;;0EAEZ,KAAC5C;gEAAKqD,IAAG;gEAAOL,MAAK;gEAAKJ,WAAU;0EACjCzB,IAAIsC,mBAAmB;;;;;8DAI9B,KAAC5D;8DACC,cAAA,KAACG;wDAAKqD,IAAG;wDAAOL,MAAK;wDAAKJ,WAAU;kEACjCzB,IAAI0C,YAAY;;;;;;;iCAMzB;4BAEH1C,IAAIqC,MAAM,KAAK,QAAQzB,mBAAmBZ,IAAIsC,mBAAmB,iBAChE,KAACvE,yBACC;0CACJ,KAACQ;gCACCyE,OAAOhD,IAAIO,UAAU,CAAC0C,SAAS;gCAC/BxB,WAAU;;4BAGXZ,gCACC;;kDACE,KAAC9C;kDACD,KAACmB;wCACCgE,UAAUrC;wCACVC,YAAYA;wCACZW,WAAU;;;iCAGZ;;;;;;;AAMhB;AAEA,SAASW,sBAAsB,EAC7B5B,MAAM,EACNP,UAAU,EACVC,QAAQ,EACRC,YAAY,EACZC,OAAO,EAOR;IACC,IAAII,WAAW,QAAQ,OAAO;IAE9B,IAAIA,WAAW,UAAU;QACvB,IAAI,CAACN,UAAU,OAAO;QAEtB,qBACE,KAACjC;YACCuE,MAAK;YACLb,SAAQ;YACRE,MAAK;YACLsB,WAAWlD;YACXmD,UAAUnD;YACVoD,SAASnD;sBACV;;IAIL;IAEA,IAAIM,WAAW,aAAa;QAC1B,IAAI,CAACJ,SAAS,OAAO;QAErB,qBACE,KAACnC;YACCuE,MAAK;YACLb,SAAQ;YACRE,MAAK;YACLJ,WAAW7B;YACXuD,WAAWhD;YACXiD,UAAUjD;YACVkD,SAAS,IAAMjD,QAAQ;sBACxB;;IAIL;IAEA,IAAI,CAACA,SAAS,OAAO;IAErB,qBACE,MAAClC;;0BACC,KAACG;gBAAoB4D,OAAO;0BAC1B,cAAA,KAAChE;oBACCuE,MAAK;oBACLb,SAAQ;oBACRE,MAAK;oBACLJ,WAAW7B;oBACX0D,WAAU;oBACVH,WAAWhD;oBACXiD,UAAUjD;8BACX;;;0BAIH,MAAChC;gBAAoBoF,OAAM;;kCACzB,KAACnF;wBAAiBgF,UAAUjD;wBAAcqD,UAAU,IAAMpD,QAAQ;kCAAQ;;kCAG1E,KAAChC;wBAAiBgF,UAAUjD;wBAAcqD,UAAU,IAAMpD,QAAQ;kCAAW;;;;;;AAMrF;AAEA,SAASK,wBAAwBT,GAAsB;IACrD,IAAIA,IAAIO,UAAU,CAACkD,OAAO,KAAKzD,IAAI0D,cAAc,EAAE,OAAO;IAC1D,IAAI,CAAC1E,sBAAsBgB,IAAIO,UAAU,CAACd,MAAM,GAAG,OAAO;IAC1D,IAAIO,IAAIO,UAAU,CAACd,MAAM,KAAK,eAAe,CAACkE,yBAAyB3D,MAAM,OAAO;IACpF,OAAO;AACT;AAEA,SAASW,2BACPH,MAAyB,EACzBN,QAAkC,EAClCE,OAA2D;IAE3D,IAAII,WAAW,UAAU,OAAON,aAAa0D;IAC7C,IAAIpD,WAAW,eAAeA,WAAW,cAAc,OAAOJ,YAAYwD;IAC1E,OAAO;AACT;AAEA,SAASD,yBAAyB3D,GAAsB;IACtD,IAAI,CAAC6D,mBAAmB7D,MAAM,OAAO;IAErC,OAAOA,IAAI8D,IAAI,CAACC,IAAI,CAAC,CAACC,MAAQA,IAAIvE,MAAM,KAAK,YAAYuE,IAAIvE,MAAM,KAAK;AAC1E;AAEA,SAASoE,mBAAmB7D,GAAsB;IAChD,OAAO,UAAUA,OAAOiE,MAAMC,OAAO,CAAClE,IAAI8D,IAAI;AAChD"}
|
|
@@ -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;
|
|
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;AAK3D,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,+BAgEtB"}
|
|
@@ -10,6 +10,7 @@ import { WorkflowStatusIcon } from '#components/workflow-status/workflow-status-
|
|
|
10
10
|
import { defaultJobExecution, deriveJobDisplayStatus } from '#core/workflow-run.js';
|
|
11
11
|
import { workflowJobSearchParams, workflowRunSearchParams } from '#routes/inputs.js';
|
|
12
12
|
import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
13
|
+
const RUN_WORKSPACE_LINK_CLASS_NAME = 'relative flex min-h-32 items-center gap-inline rounded-4 px-tight 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';
|
|
13
14
|
/**
|
|
14
15
|
* The stable navigation model shared by run-level and job-level routes. The graph explains
|
|
15
16
|
* topology; this compact index makes moving between dedicated job pages predictable.
|
|
@@ -20,13 +21,14 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
|
20
21
|
run.jobs
|
|
21
22
|
]);
|
|
22
23
|
const [mobileOpen, setMobileOpen] = useState(false);
|
|
23
|
-
const currentJob = jobs.find((job)=>job.id === currentJobId);
|
|
24
|
+
const currentJob = jobs.find((job)=>job.id === currentJobId) ?? (currentJobId ? jobs[0] : undefined);
|
|
25
|
+
const resolvedCurrentJobId = currentJob?.id;
|
|
24
26
|
const currentLabel = currentJob?.displayName ?? sectionLabel(activeSection);
|
|
25
27
|
return /*#__PURE__*/ _jsx(TimeTickerProvider, {
|
|
26
28
|
intervalMs: 1000,
|
|
27
29
|
reducedMotionIntervalMs: 10_000,
|
|
28
30
|
children: /*#__PURE__*/ _jsx("aside", {
|
|
29
|
-
className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base min-[768px]:w-240 min-[768px]:border-b-0
|
|
31
|
+
className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base min-[768px]:w-240 min-[768px]:border-b-0",
|
|
30
32
|
children: /*#__PURE__*/ _jsxs(Collapsible, {
|
|
31
33
|
open: mobileOpen,
|
|
32
34
|
onOpenChange: setMobileOpen,
|
|
@@ -71,7 +73,7 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
|
71
73
|
run: run,
|
|
72
74
|
jobs: jobs,
|
|
73
75
|
activeSection: activeSection,
|
|
74
|
-
currentJobId:
|
|
76
|
+
currentJobId: resolvedCurrentJobId,
|
|
75
77
|
jobSearch: jobSearch,
|
|
76
78
|
annotationSummary: annotationSummary,
|
|
77
79
|
mobileOpen: mobileOpen,
|
|
@@ -106,9 +108,10 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
106
108
|
]);
|
|
107
109
|
return /*#__PURE__*/ _jsxs("nav", {
|
|
108
110
|
"aria-label": "Run workspace",
|
|
109
|
-
className: "flex min-h-0 min-w-0 flex-1 flex-col
|
|
111
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col",
|
|
110
112
|
children: [
|
|
111
113
|
/*#__PURE__*/ _jsx("ul", {
|
|
114
|
+
className: "border-b border-border-neutral-base pb-row",
|
|
112
115
|
children: /*#__PURE__*/ _jsx("li", {
|
|
113
116
|
children: /*#__PURE__*/ _jsx(RunSectionLink, {
|
|
114
117
|
workspaceSlug: workspaceSlug,
|
|
@@ -123,7 +126,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
123
126
|
}),
|
|
124
127
|
/*#__PURE__*/ _jsxs("section", {
|
|
125
128
|
"aria-labelledby": "run-workspace-jobs-heading",
|
|
126
|
-
className: "flex min-h-0 min-w-0 flex-1 flex-col",
|
|
129
|
+
className: "flex min-h-0 min-w-0 flex-1 flex-col border-b border-border-neutral-base py-row",
|
|
127
130
|
children: [
|
|
128
131
|
/*#__PURE__*/ _jsxs("div", {
|
|
129
132
|
className: "flex items-center justify-between gap-inline px-tight pb-[6px]",
|
|
@@ -165,8 +168,9 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
165
168
|
}),
|
|
166
169
|
onClick: onNavigate,
|
|
167
170
|
"aria-current": current ? 'page' : undefined,
|
|
168
|
-
className: cn('
|
|
171
|
+
className: cn(RUN_WORKSPACE_LINK_CLASS_NAME, 'min-w-0 text-left', current && 'bg-background-neutral-hover'),
|
|
169
172
|
children: [
|
|
173
|
+
current ? /*#__PURE__*/ _jsx(RunWorkspaceActiveBar, {}) : null,
|
|
170
174
|
/*#__PURE__*/ _jsx(WorkflowStatusIcon, {
|
|
171
175
|
status: deriveJobDisplayStatus(job),
|
|
172
176
|
size: 12,
|
|
@@ -191,6 +195,7 @@ function RunWorkspaceNavContent({ workspaceSlug, projectSlug, run, jobs, activeS
|
|
|
191
195
|
}),
|
|
192
196
|
/*#__PURE__*/ _jsxs("section", {
|
|
193
197
|
"aria-labelledby": "run-workspace-details-heading",
|
|
198
|
+
className: "pt-row",
|
|
194
199
|
children: [
|
|
195
200
|
/*#__PURE__*/ _jsx(Text, {
|
|
196
201
|
as: "h2",
|
|
@@ -252,8 +257,9 @@ function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section
|
|
|
252
257
|
onClick: onNavigate,
|
|
253
258
|
"aria-current": current ? 'page' : undefined,
|
|
254
259
|
"aria-label": count ? `${sectionLabel(section)}, ${countTruncated ? `${count} or more` : count}` : undefined,
|
|
255
|
-
className: cn('
|
|
260
|
+
className: cn(RUN_WORKSPACE_LINK_CLASS_NAME, 'text-xs font-medium text-foreground-neutral-base', current && 'bg-background-neutral-hover'),
|
|
256
261
|
children: [
|
|
262
|
+
current ? /*#__PURE__*/ _jsx(RunWorkspaceActiveBar, {}) : null,
|
|
257
263
|
sectionLabel(section),
|
|
258
264
|
count ? /*#__PURE__*/ _jsxs("span", {
|
|
259
265
|
"aria-hidden": "true",
|
|
@@ -266,6 +272,13 @@ function RunSectionLink({ workspaceSlug, projectSlug, runId, runAttempt, section
|
|
|
266
272
|
]
|
|
267
273
|
});
|
|
268
274
|
}
|
|
275
|
+
function RunWorkspaceActiveBar() {
|
|
276
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
277
|
+
"aria-hidden": "true",
|
|
278
|
+
"data-run-workspace-active-bar": true,
|
|
279
|
+
className: "absolute inset-y-0 left-0 w-2 rounded-l-4 bg-border-highlights-interactive"
|
|
280
|
+
});
|
|
281
|
+
}
|
|
269
282
|
function sectionLabel(section) {
|
|
270
283
|
if (section === 'annotations') return 'Annotations';
|
|
271
284
|
if (section === 'source') return 'Source';
|
|
@@ -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=\"flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base 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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"}
|
|
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\nconst RUN_WORKSPACE_LINK_CLASS_NAME =\n 'relative flex min-h-32 items-center gap-inline rounded-4 px-tight 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\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 =\n jobs.find((job) => job.id === currentJobId) ?? (currentJobId ? jobs[0] : undefined);\n const resolvedCurrentJobId = currentJob?.id;\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 min-[768px]:w-240 min-[768px]:border-b-0\">\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={resolvedCurrentJobId}\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\">\n <ul className=\"border-b border-border-neutral-base pb-row\">\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 border-b border-border-neutral-base py-row\"\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 RUN_WORKSPACE_LINK_CLASS_NAME,\n 'min-w-0 text-left',\n current && 'bg-background-neutral-hover',\n )}\n >\n {current ? <RunWorkspaceActiveBar /> : null}\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\" className=\"pt-row\">\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 RUN_WORKSPACE_LINK_CLASS_NAME,\n 'text-xs font-medium text-foreground-neutral-base',\n current && 'bg-background-neutral-hover',\n )}\n >\n {current ? <RunWorkspaceActiveBar /> : null}\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 RunWorkspaceActiveBar() {\n return (\n <span\n aria-hidden=\"true\"\n data-run-workspace-active-bar\n className=\"absolute inset-y-0 left-0 w-2 rounded-l-4 bg-border-highlights-interactive\"\n />\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","RUN_WORKSPACE_LINK_CLASS_NAME","RunWorkspaceNav","workspaceSlug","projectSlug","run","activeSection","currentJobId","jobSearch","annotationSummary","jobs","sort","compareJobs","mobileOpen","setMobileOpen","currentJob","find","job","id","undefined","resolvedCurrentJobId","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","to","params","workflowRunId","jobId","search","onClick","aria-current","RunWorkspaceActiveBar","status","tooltip","time","count","total","countTruncated","truncated","tab","data-run-workspace-active-bar","left","right","position","localeCompare"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-run-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAezD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-run-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/workflow-run-view.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAezD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAGpB,MAAM,mBAAmB,CAAC;AAqB3B,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC3C,GAAG,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,EACT,GAAG,EACH,WAAW,EACX,SAAS,EACT,UAAU,GACX,EAAE,oBAAoB,+BA0CtB"}
|
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { ApiError } from '@shipfox/client-api';
|
|
3
3
|
import { QueryLoadError } from '@shipfox/client-ui';
|
|
4
4
|
import { EmptyState } from '@shipfox/react-ui/empty-state';
|
|
5
|
+
import { Panel, PanelBody, PanelHeader } from '@shipfox/react-ui/panel';
|
|
5
6
|
import { RelativeTimeProvider } from '@shipfox/react-ui/relative-time';
|
|
6
7
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shipfox/react-ui/select';
|
|
7
8
|
import { toast } from '@shipfox/react-ui/toast';
|
|
8
9
|
import { Text } from '@shipfox/react-ui/typography';
|
|
9
|
-
import { cn } from '@shipfox/react-ui/utils';
|
|
10
10
|
import { useNavigate } from '@tanstack/react-router';
|
|
11
11
|
import { useEffect, useMemo } from 'react';
|
|
12
12
|
import { buildRunAnnotationList } from '#core/run-annotation.js';
|
|
@@ -22,7 +22,6 @@ import { WorkflowSourceContent } from '../workflow-source-panel/index.js';
|
|
|
22
22
|
import { RunWorkspaceNav } from './run-workspace-nav.js';
|
|
23
23
|
import { resolveWorkflowRunSelection } from './workflow-run-selection.js';
|
|
24
24
|
import { WorkflowRunContentSkeleton, WorkflowRunNotFound, WorkflowRunSkeleton, WorkflowRunStaleError } from './workflow-run-states.js';
|
|
25
|
-
const RUN_WORKSPACE_FRAME_CLASS_NAME = 'mx-auto w-full max-w-[calc(240px_+_1120px)]';
|
|
26
25
|
/**
|
|
27
26
|
* The persistent run workspace. Run-level sections and dedicated job routes share the same
|
|
28
27
|
* header and job index, while the all-jobs Summary always opens on the dependency graph.
|
|
@@ -70,7 +69,6 @@ function RunViewContent({ workspaceSlug, projectSlug, query, annotations, rerunM
|
|
|
70
69
|
const activeSection = runWorkspaceSection(tab);
|
|
71
70
|
const cancelMutation = useCancelWorkflowRunMutation(runData);
|
|
72
71
|
const sourceSnapshot = runData?.sourceSnapshot ?? null;
|
|
73
|
-
const hasJobContent = Boolean(jobContent);
|
|
74
72
|
const resolvedSelection = runData && selection ? resolveWorkflowRunSelection({
|
|
75
73
|
run: runData,
|
|
76
74
|
selection
|
|
@@ -222,7 +220,7 @@ function RunViewContent({ workspaceSlug, projectSlug, query, annotations, rerunM
|
|
|
222
220
|
className: "flex min-h-0 min-w-0 flex-1 flex-col border-t border-border-neutral-base",
|
|
223
221
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
224
222
|
"data-run-workspace-frame": true,
|
|
225
|
-
className:
|
|
223
|
+
className: "flex min-h-0 min-w-0 w-full flex-1 flex-col min-[768px]:flex-row",
|
|
226
224
|
children: [
|
|
227
225
|
runData && workspaceSlug && projectSlug ? /*#__PURE__*/ _jsx(RunWorkspaceNav, {
|
|
228
226
|
workspaceSlug: workspaceSlug,
|
|
@@ -267,18 +265,24 @@ function RunSectionContent({ section, run, annotations, annotationSummary, works
|
|
|
267
265
|
"aria-label": "All jobs summary",
|
|
268
266
|
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
269
267
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
270
|
-
className: "
|
|
268
|
+
className: "flex w-full flex-col gap-group",
|
|
271
269
|
children: [
|
|
272
270
|
/*#__PURE__*/ _jsx(Text, {
|
|
273
271
|
as: "h2",
|
|
274
272
|
className: "sr-only",
|
|
275
273
|
children: "All jobs summary"
|
|
276
274
|
}),
|
|
277
|
-
/*#__PURE__*/ _jsx(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
275
|
+
/*#__PURE__*/ _jsx(Panel, {
|
|
276
|
+
className: "min-h-160",
|
|
277
|
+
children: /*#__PURE__*/ _jsx(PanelBody, {
|
|
278
|
+
className: "min-h-160 bg-background-components-base p-0",
|
|
279
|
+
children: /*#__PURE__*/ _jsx(JobGraph, {
|
|
280
|
+
run: run,
|
|
281
|
+
selectedJobId: selectedJobId,
|
|
282
|
+
onSelectedJobChange: onSelectGraphJob,
|
|
283
|
+
className: "min-h-160 overflow-hidden"
|
|
284
|
+
})
|
|
285
|
+
})
|
|
282
286
|
})
|
|
283
287
|
]
|
|
284
288
|
})
|
|
@@ -301,22 +305,29 @@ function RunSectionContent({ section, run, annotations, annotationSummary, works
|
|
|
301
305
|
"aria-label": "Workflow source",
|
|
302
306
|
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
303
307
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
304
|
-
className: "
|
|
308
|
+
className: "flex min-h-full w-full flex-col",
|
|
305
309
|
children: [
|
|
306
310
|
/*#__PURE__*/ _jsx(Text, {
|
|
307
311
|
as: "h2",
|
|
308
312
|
className: "sr-only",
|
|
309
313
|
children: "Workflow source"
|
|
310
314
|
}),
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
315
|
+
/*#__PURE__*/ _jsx(Panel, {
|
|
316
|
+
className: "min-h-160 flex-1",
|
|
317
|
+
children: /*#__PURE__*/ _jsx(PanelBody, {
|
|
318
|
+
className: "min-h-160 flex-1 p-0",
|
|
319
|
+
children: sourceSnapshot ? /*#__PURE__*/ _jsx(WorkflowSourceContent, {
|
|
320
|
+
source: sourceSnapshot,
|
|
321
|
+
highlightedLineRange: highlightedLineRange,
|
|
322
|
+
scrollHighlightedIntoView: true
|
|
323
|
+
}) : /*#__PURE__*/ _jsx(EmptyState, {
|
|
324
|
+
variant: "panel",
|
|
325
|
+
className: "min-h-160",
|
|
326
|
+
icon: "fileDamageLine",
|
|
327
|
+
title: "Source snapshot unavailable",
|
|
328
|
+
description: run.isTemporary ? 'Temporary runs do not capture workflow source.' : 'This run was created before workflow source snapshots were captured.'
|
|
329
|
+
})
|
|
330
|
+
})
|
|
320
331
|
})
|
|
321
332
|
]
|
|
322
333
|
})
|
|
@@ -359,45 +370,52 @@ function RunAnnotationsSection({ run, annotations, annotationSummary, workspaceS
|
|
|
359
370
|
"aria-label": "Run annotations",
|
|
360
371
|
className: "min-h-0 flex-1 overflow-auto pb-panel pt-[16px]",
|
|
361
372
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
362
|
-
className: "
|
|
373
|
+
className: "flex w-full flex-col",
|
|
363
374
|
children: [
|
|
364
375
|
/*#__PURE__*/ _jsx(Text, {
|
|
365
376
|
as: "h2",
|
|
366
377
|
className: "sr-only",
|
|
367
378
|
children: "Annotations"
|
|
368
379
|
}),
|
|
369
|
-
/*#__PURE__*/ _jsxs(
|
|
370
|
-
className: "flex flex-wrap items-center justify-between gap-inline",
|
|
380
|
+
/*#__PURE__*/ _jsxs(Panel, {
|
|
371
381
|
children: [
|
|
372
|
-
/*#__PURE__*/
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
382
|
+
/*#__PURE__*/ _jsxs(PanelHeader, {
|
|
383
|
+
className: "flex-wrap",
|
|
384
|
+
children: [
|
|
385
|
+
/*#__PURE__*/ _jsx(RunAnnotationSummaryLine, {
|
|
386
|
+
summary: annotationSummary,
|
|
387
|
+
workspaceSlug: workspaceSlug,
|
|
388
|
+
projectSlug: projectSlug,
|
|
389
|
+
workflowRunId: run.id,
|
|
390
|
+
search: selection
|
|
391
|
+
}),
|
|
392
|
+
/*#__PURE__*/ _jsx(AnnotationJobFilter, {
|
|
393
|
+
jobs: run.jobs,
|
|
394
|
+
selectedJobId: selectedJob?.id,
|
|
395
|
+
onSelect: onSelectAnnotationJob
|
|
396
|
+
})
|
|
397
|
+
]
|
|
378
398
|
}),
|
|
379
|
-
/*#__PURE__*/ _jsx(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
399
|
+
/*#__PURE__*/ _jsx(PanelBody, {
|
|
400
|
+
className: "gap-group p-panel",
|
|
401
|
+
children: /*#__PURE__*/ _jsx(RunAnnotationList, {
|
|
402
|
+
query: annotations.query,
|
|
403
|
+
entries: entries,
|
|
404
|
+
derivedAnnotations: derivedAnnotations,
|
|
405
|
+
workspaceSlug: workspaceSlug,
|
|
406
|
+
projectSlug: projectSlug,
|
|
407
|
+
workflowRunId: run.id,
|
|
408
|
+
runAttempt: run.runAttempt.attempt,
|
|
409
|
+
// A run with no annotations at all offers no filter to clear, whatever the URL says.
|
|
410
|
+
filtered: Boolean((severity || selectedJob || selection?.annotation) && ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations)),
|
|
411
|
+
filteredJobName: selectedJob?.displayName,
|
|
412
|
+
filteredSeverity: severity,
|
|
413
|
+
onClearFilters: onClearAnnotationFilters,
|
|
414
|
+
selectedAnnotationId: selection?.annotation
|
|
415
|
+
}, `${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`)
|
|
383
416
|
})
|
|
384
417
|
]
|
|
385
|
-
})
|
|
386
|
-
/*#__PURE__*/ _jsx(RunAnnotationList, {
|
|
387
|
-
query: annotations.query,
|
|
388
|
-
entries: entries,
|
|
389
|
-
derivedAnnotations: derivedAnnotations,
|
|
390
|
-
workspaceSlug: workspaceSlug,
|
|
391
|
-
projectSlug: projectSlug,
|
|
392
|
-
workflowRunId: run.id,
|
|
393
|
-
runAttempt: run.runAttempt.attempt,
|
|
394
|
-
// A run with no annotations at all offers no filter to clear, whatever the URL says.
|
|
395
|
-
filtered: Boolean((severity || selectedJob || selection?.annotation) && ((annotationSummary?.total ?? 0) > 0 || hasSynthesizedJobAnnotations)),
|
|
396
|
-
filteredJobName: selectedJob?.displayName,
|
|
397
|
-
filteredSeverity: severity,
|
|
398
|
-
onClearFilters: onClearAnnotationFilters,
|
|
399
|
-
selectedAnnotationId: selection?.annotation
|
|
400
|
-
}, `${run.id}:${run.runAttempt.attempt}:${severity ?? 'all'}:${selectedJob?.id ?? 'all'}`)
|
|
418
|
+
})
|
|
401
419
|
]
|
|
402
420
|
})
|
|
403
421
|
});
|
|
@@ -477,7 +495,7 @@ function AnnotationJobFilter({ jobs, selectedJobId, onSelect }) {
|
|
|
477
495
|
function RunWorkspaceNavSkeleton() {
|
|
478
496
|
return /*#__PURE__*/ _jsx("aside", {
|
|
479
497
|
"aria-label": "Loading run navigation",
|
|
480
|
-
className: "hidden w-240 shrink-0
|
|
498
|
+
className: "hidden w-240 shrink-0 p-panel-compact min-[768px]:block",
|
|
481
499
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
482
500
|
className: "flex flex-col gap-group",
|
|
483
501
|
children: [
|