|
1 | | -import { useEffect, useMemo, useState, type ComponentType, type ReactNode } from 'react' |
| 1 | +import { useEffect, useMemo, useRef, useState, type ComponentType, type ReactNode } from 'react' |
2 | 2 | import { Activity, AlertTriangle, GitBranch, Layers3, Loader2, Terminal } from 'lucide-react' |
3 | 3 | import { clsx } from 'clsx' |
4 | 4 | import { EmptyState, FetchResult, StatusDot, mapHealthToTone } from '@skyhook-io/k8s-ui' |
@@ -69,14 +69,22 @@ export function BatchExecutionFullscreen({ kind, apiKind, namespace, name, resou |
69 | 69 | const runs = scheduledRunsFor(kind, runsQuery.data?.runs, resource, apiKind, namespace, name) |
70 | 70 | const defaultRun = useMemo(() => pickDefaultRun(runs), [runs]) |
71 | 71 | const [selectedRunName, setSelectedRunName] = useState('') |
| 72 | + const userSelectedRunRef = useRef(false) |
72 | 73 |
|
73 | 74 | useEffect(() => { |
74 | 75 | if (runs.length === 0) { |
| 76 | + userSelectedRunRef.current = false |
75 | 77 | setSelectedRunName('') |
76 | 78 | return |
77 | 79 | } |
| 80 | + const nextDefaultRunName = defaultRun?.name ?? runs[0].name |
78 | 81 | if (!runs.some((run) => run.name === selectedRunName)) { |
79 | | - setSelectedRunName(defaultRun?.name ?? runs[0].name) |
| 82 | + userSelectedRunRef.current = false |
| 83 | + setSelectedRunName(nextDefaultRunName) |
| 84 | + return |
| 85 | + } |
| 86 | + if (!userSelectedRunRef.current && selectedRunName !== nextDefaultRunName) { |
| 87 | + setSelectedRunName(nextDefaultRunName) |
80 | 88 | } |
81 | 89 | }, [runs, selectedRunName, defaultRun]) |
82 | 90 |
|
@@ -136,7 +144,10 @@ export function BatchExecutionFullscreen({ kind, apiKind, namespace, name, resou |
136 | 144 | key={`${run.kind}/${run.namespace}/${run.name}`} |
137 | 145 | run={run} |
138 | 146 | selected={selectedRun?.name === run.name} |
139 | | - onClick={() => setSelectedRunName(run.name)} |
| 147 | + onClick={() => { |
| 148 | + userSelectedRunRef.current = true |
| 149 | + setSelectedRunName(run.name) |
| 150 | + }} |
140 | 151 | /> |
141 | 152 | ))} |
142 | 153 | </div> |
@@ -178,7 +189,8 @@ export function BatchExecutionFullscreen({ kind, apiKind, namespace, name, resou |
178 | 189 | <div className="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-xs text-theme-text-tertiary"> |
179 | 190 | <span>{RUN_KIND_LABEL[selectedRun.kind] ?? selectedRun.kind}</span> |
180 | 191 | {selectedRun.startedAt && <span>started {formatAge(selectedRun.startedAt)}</span>} |
181 | | - {selectedRun.scheduledAt && <span>scheduled {formatAge(selectedRun.scheduledAt)}</span>} |
| 192 | + {selectedRun.trigger === 'manual' && <span>manual trigger</span>} |
| 193 | + {selectedRun.scheduledAt && <span>cron scheduled {formatAge(selectedRun.scheduledAt)}</span>} |
182 | 194 | {selectedRun.template && <span>template {selectedRun.template}</span>} |
183 | 195 | {selectedResourceQuery.isFetching && <span>refreshing</span>} |
184 | 196 | </div> |
@@ -449,11 +461,14 @@ function SourceFacts({ source }: { source: ReturnType<typeof sourceFacts> }) { |
449 | 461 | } |
450 | 462 |
|
451 | 463 | function RunDetailList({ run, resource, workflowExecution }: { run: WorkloadRun; resource: any; workflowExecution: WorkflowExecutionModel | null }) { |
452 | | - const rows = [ |
| 464 | + const rows: Array<[string, string]> = [ |
453 | 465 | ['Started', run.startedAt ? formatAge(run.startedAt) : '-'], |
454 | 466 | ['Finished', run.finishedAt ? formatAge(run.finishedAt) : run.active ? 'Running' : '-'], |
455 | | - ['Scheduled', run.scheduledAt ? formatAge(run.scheduledAt) : '-'], |
456 | | - ['Schedule delay', formatScheduleDelay(run) || '-'], |
| 467 | + ['Trigger', run.trigger === 'manual' ? 'Manual' : run.scheduledAt ? 'Cron schedule' : '-'], |
| 468 | + ...(run.scheduledAt ? [ |
| 469 | + ['Cron scheduled', formatAge(run.scheduledAt)], |
| 470 | + ['Start delay', formatScheduleDelay(run) || '-'], |
| 471 | + ] as Array<[string, string]> : []), |
457 | 472 | ['Parallelism', run.parallelism ? String(run.parallelism) : '-'], |
458 | 473 | ['Pods', podBreakdown(run, workflowExecution) || '-'], |
459 | 474 | ['Steps', stepBreakdown(run, workflowExecution) || '-'], |
@@ -482,7 +497,7 @@ function RunMetrics({ run, resource, workflowExecution, retainedRuns }: { run: W |
482 | 497 | ['Active retained', activeRuns ? String(activeRuns) : '0'], |
483 | 498 | ['Failed retained', failedRuns ? String(failedRuns) : '0'], |
484 | 499 | ['Current duration', formatRunDuration(run) || '-'], |
485 | | - ['Schedule delay', formatScheduleDelay(run) || '-'], |
| 500 | + ['Start delay', run.scheduledAt ? formatScheduleDelay(run) || '-' : '-'], |
486 | 501 | ['Completions', jobSpec.completions != null ? String(jobSpec.completions) : run.desired ? String(run.desired) : '-'], |
487 | 502 | ['Resource duration', resourceDuration || '-'], |
488 | 503 | ] |
@@ -893,7 +908,7 @@ function jobPseudoSteps(run: WorkloadRun, resource: any): WorkflowExecutionNode[ |
893 | 908 |
|
894 | 909 | function jobActivity(run: WorkloadRun, resource: any): WorkflowExecutionActivity[] { |
895 | 910 | const items: WorkflowExecutionActivity[] = [] |
896 | | - if (run.scheduledAt) items.push({ id: 'scheduled', at: run.scheduledAt, label: 'Scheduled', tone: 'info' }) |
| 911 | + if (run.scheduledAt) items.push({ id: 'scheduled', at: run.scheduledAt, label: 'Cron scheduled', tone: 'info' }) |
897 | 912 | if (run.startedAt) items.push({ id: 'started', at: run.startedAt, label: 'Job started', tone: 'info' }) |
898 | 913 | const conditions = Array.isArray(resource?.status?.conditions) ? resource.status.conditions : [] |
899 | 914 | for (const condition of conditions) { |
|
0 commit comments