@skyhook-io/radar-app 1.14.4 → 1.14.6
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/README.md +2 -9
- package/package.json +6 -6
- package/src/App.tsx +91 -328
- package/src/RadarApp.tsx +3 -8
- package/src/api/client.jobset.test.ts +18 -0
- package/src/api/client.resource-identity.test.ts +44 -0
- package/src/api/client.rightsizing.test.ts +7 -3
- package/src/api/client.ts +233 -78
- package/src/api/preferences.test.ts +54 -0
- package/src/api/preferences.ts +38 -0
- package/src/components/CloudFunnelButton.test.tsx +155 -0
- package/src/components/CloudFunnelButton.tsx +14 -8
- package/src/components/ContextSwitcher.tsx +13 -132
- package/src/components/applications/ApplicationsView.identity.test.ts +39 -0
- package/src/components/applications/ApplicationsView.tsx +5 -3
- package/src/components/audit/AuditSettingsDialog.tsx +15 -11
- package/src/components/diagnose/AIMarkdown.tsx +8 -3
- package/src/components/diagnose/AgentControls.tsx +26 -3
- package/src/components/diagnose/AssessmentCard.tsx +249 -237
- package/src/components/diagnose/DiagnoseContext.tsx +1 -0
- package/src/components/diagnose/InvestigationEvidencePane.test.tsx +47 -0
- package/src/components/diagnose/InvestigationEvidencePane.tsx +15 -2
- package/src/components/diagnose/InvestigationEvidenceSections.tsx +1 -1
- package/src/components/diagnose/InvestigationView.tsx +4 -1
- package/src/components/diagnose/agentCatalog.ts +6 -0
- package/src/components/diagnose/investigationCase.test.tsx +56 -0
- package/src/components/diagnose/investigationEvidence/adapters/logs.test.ts +60 -0
- package/src/components/diagnose/investigationEvidence/adapters/logs.ts +7 -3
- package/src/components/diagnose/investigationEvidence/bodies/streams.tsx +1 -1
- package/src/components/diagnose/investigationEvidence/observations.ts +8 -5
- package/src/components/diagnose/investigationEvidence/types.ts +1 -1
- package/src/components/diagnose/launch.test.ts +23 -0
- package/src/components/diagnose/launch.ts +4 -0
- package/src/components/diagnose/parts.test.tsx +159 -2
- package/src/components/dock/NodeTerminalTab.test.tsx +34 -0
- package/src/components/dock/NodeTerminalTab.tsx +5 -3
- package/src/components/dock/WorkloadLogsTab.test.tsx +66 -0
- package/src/components/dock/WorkloadLogsTab.tsx +2 -1
- package/src/components/execution/BatchExecutionView.render.test.tsx +2 -1
- package/src/components/execution/BatchExecutionView.test.ts +52 -1
- package/src/components/execution/BatchExecutionView.tsx +324 -65
- package/src/components/execution/JobSetAdmission.test.tsx +42 -0
- package/src/components/execution/JobSetAdmission.tsx +17 -0
- package/src/components/execution/JobSetMemberComparison.test.tsx +30 -0
- package/src/components/execution/JobSetMemberComparison.tsx +88 -0
- package/src/components/execution/batch-run-actions.test.ts +1 -0
- package/src/components/execution/batch-timeline.test.ts +3 -0
- package/src/components/execution/execution-definition.test.ts +15 -1
- package/src/components/execution/execution-definition.ts +4 -0
- package/src/components/execution/member-collection.render.test.tsx +142 -0
- package/src/components/gitops/GitOpsView.tsx +33 -2
- package/src/components/gitops/destination-toast.test.ts +33 -0
- package/src/components/gitops/destination-toast.ts +46 -0
- package/src/components/gitops/useDestinationCluster.ts +30 -0
- package/src/components/helm/TrackChartSourceDialog.tsx +20 -11
- package/src/components/home/MCPSetupDialog.tsx +10 -0
- package/src/components/logs/ScheduledWorkloadLogsViewer.tsx +75 -22
- package/src/components/logs/WorkloadLogsViewer.tsx +7 -4
- package/src/components/nav/PrimaryNavRail.tsx +2 -5
- package/src/components/resource/PVCUsageBar.render.test.tsx +168 -0
- package/src/components/resource/PVCUsageBar.tsx +62 -16
- package/src/components/resource/PrometheusChartsGrid.render.test.tsx +1 -1
- package/src/components/resources/ResourcesView.tsx +3 -3
- package/src/components/resources/renderers/CAPIClusterRenderer.tsx +8 -0
- package/src/components/resources/renderers/KueueWorkloadRenderer.test.tsx +39 -0
- package/src/components/resources/renderers/KueueWorkloadRenderer.tsx +37 -0
- package/src/components/resources/renderers/RayClusterRenderer.test.tsx +18 -0
- package/src/components/resources/renderers/RayClusterRenderer.tsx +17 -0
- package/src/components/resources/renderers/RayServiceRenderer.test.tsx +69 -0
- package/src/components/resources/renderers/RayServiceRenderer.tsx +38 -0
- package/src/components/rightsizing/RightsizingScanView.tsx +207 -83
- package/src/components/rightsizing/copy.test.ts +7 -0
- package/src/components/rightsizing/empty-state.test.tsx +67 -0
- package/src/components/rightsizing/model.test.ts +120 -2
- package/src/components/rightsizing/model.ts +36 -13
- package/src/components/rightsizing/notices.test.tsx +176 -0
- package/src/components/settings/OperatorManagedNotice.tsx +17 -0
- package/src/components/settings/SettingsDialog.tsx +157 -42
- package/src/components/settings/settings-state.test.ts +18 -0
- package/src/components/settings/settings-state.ts +18 -0
- package/src/components/timeline/TimelineView.tsx +9 -3
- package/src/components/timeline/TimelineView.urlparams.test.ts +18 -1
- package/src/components/ui/Markdown.tsx +33 -6
- package/src/components/ui/command-items.ts +0 -3
- package/src/components/useContextSwitchFlow.tsx +147 -0
- package/src/components/workload/WorkloadView.test.ts +17 -1
- package/src/components/workload/WorkloadView.tsx +36 -18
- package/src/context/ContextSwitchContext.tsx +18 -2
- package/src/context/NavCustomization.tsx +4 -58
- package/src/context/ThemeContext.tsx +3 -11
- package/src/hooks/useClusterLoadState.ts +2 -2
- package/src/hooks/useFavorites.ts +3 -5
- package/src/utils/auditBadges.ts +1 -1
- package/src/utils/navigation.test.ts +18 -1
- package/src/utils/navigation.ts +12 -5
- package/src/utils/topology-selection.test.ts +56 -0
- package/src/utils/topology-selection.ts +9 -9
- package/src/components/ui/CommandPalette.tsx +0 -261
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act } from 'react'
|
|
3
|
+
import { createRoot, type Root } from 'react-dom/client'
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { WorkloadLogsTab } from './WorkloadLogsTab'
|
|
6
|
+
|
|
7
|
+
const state = vi.hoisted(() => ({ targets: [] as Array<{ kind: string; name: string; role?: string; snapshotOnly?: boolean }> }))
|
|
8
|
+
vi.mock('../../api/client', () => ({
|
|
9
|
+
useResource: (_kind: string, _namespace: string, name: string) => ({
|
|
10
|
+
data: { metadata: { uid: name }, spec: { replicatedJobs: [{ name: name === 'first' ? 'workers' : 'leader' }] } },
|
|
11
|
+
}),
|
|
12
|
+
useWorkloadRuns: (_kind: string, namespace: string, name: string) => ({
|
|
13
|
+
data: { collection: 'members', runs: [{ group: 'batch', kind: 'jobs', namespace, name: `${name}-0`, phase: 'Running', active: true }], total: 1 },
|
|
14
|
+
}),
|
|
15
|
+
}))
|
|
16
|
+
vi.mock('../logs/WorkloadLogsViewer', () => ({
|
|
17
|
+
WorkloadLogsViewer: (props: { kind: string; name: string; role?: string; snapshotOnly?: boolean }) => {
|
|
18
|
+
state.targets.push(props)
|
|
19
|
+
return <div data-log-target={`${props.kind}/${props.name}`} />
|
|
20
|
+
},
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
|
24
|
+
let root: Root
|
|
25
|
+
let element: HTMLDivElement
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
state.targets = []
|
|
28
|
+
element = document.createElement('div')
|
|
29
|
+
document.body.appendChild(element)
|
|
30
|
+
root = createRoot(element)
|
|
31
|
+
})
|
|
32
|
+
afterEach(async () => {
|
|
33
|
+
await act(async () => root.unmount())
|
|
34
|
+
element.remove()
|
|
35
|
+
})
|
|
36
|
+
async function render(name: string, kind = 'JobSet') {
|
|
37
|
+
await act(async () => root.render(<WorkloadLogsTab namespace="training" workloadKind={kind} workloadName={name} />))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('dock JobSet logs', () => {
|
|
41
|
+
it.each(['JobSet', 'jobsets'])('routes %s to selected member logs and supports role snapshots', async kind => {
|
|
42
|
+
await render('first', kind)
|
|
43
|
+
expect(element.querySelector('[data-log-target="jobs/first-0"]')).not.toBeNull()
|
|
44
|
+
const scope = element.querySelector<HTMLSelectElement>('#jobset-log-scope')!
|
|
45
|
+
await act(async () => {
|
|
46
|
+
scope.value = 'role'
|
|
47
|
+
scope.dispatchEvent(new Event('change', { bubbles: true }))
|
|
48
|
+
})
|
|
49
|
+
expect(state.targets.at(-1)).toMatchObject({ kind: 'jobsets', name: 'first', role: 'workers', snapshotOnly: true })
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('resets aggregate scope and role before rendering another JobSet log source', async () => {
|
|
53
|
+
await render('first')
|
|
54
|
+
const scope = element.querySelector<HTMLSelectElement>('#jobset-log-scope')!
|
|
55
|
+
await act(async () => {
|
|
56
|
+
scope.value = 'role'
|
|
57
|
+
scope.dispatchEvent(new Event('change', { bubbles: true }))
|
|
58
|
+
})
|
|
59
|
+
state.targets = []
|
|
60
|
+
await render('second')
|
|
61
|
+
expect(element.querySelector<HTMLSelectElement>('#jobset-log-scope')?.value).toBe('selected')
|
|
62
|
+
expect(element.textContent).not.toContain('workers')
|
|
63
|
+
expect(state.targets.every(target => target.name === 'second-0' && target.role === undefined)).toBe(true)
|
|
64
|
+
expect(element.querySelector('[data-log-target="jobs/second-0"]')).not.toBeNull()
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -17,7 +17,8 @@ export function WorkloadLogsTab({
|
|
|
17
17
|
normalizedKind === 'cronworkflow' || normalizedKind === 'cronworkflows' ||
|
|
18
18
|
normalizedKind === 'workflowtemplate' || normalizedKind === 'workflowtemplates' ||
|
|
19
19
|
normalizedKind === 'clusterworkflowtemplate' || normalizedKind === 'clusterworkflowtemplates' ||
|
|
20
|
-
normalizedKind === 'scaledjob' || normalizedKind === 'scaledjobs'
|
|
20
|
+
normalizedKind === 'scaledjob' || normalizedKind === 'scaledjobs' ||
|
|
21
|
+
normalizedKind === 'jobset' || normalizedKind === 'jobsets'
|
|
21
22
|
|
|
22
23
|
return (
|
|
23
24
|
<div className="h-full">
|
|
@@ -5,7 +5,8 @@ import { BatchExecutionFullscreen } from './BatchExecutionView'
|
|
|
5
5
|
vi.mock('../../api/client', () => ({
|
|
6
6
|
useResource: () => ({}),
|
|
7
7
|
useWorkloadPods: () => ({}),
|
|
8
|
-
|
|
8
|
+
useJobSetResources: () => ({ data: undefined, isLoading: false }),
|
|
9
|
+
useWorkloadRuns: () => ({ data: { collection: 'runs', runs: [], total: 0, truncated: false } }),
|
|
9
10
|
}))
|
|
10
11
|
|
|
11
12
|
describe.each(['Job', 'CronJob', 'ScaledJob'])('%s cleanup retention display', (kind) => {
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import type { WorkflowExecutionActivity } from '@skyhook-io/k8s-ui/utils/workflow-execution'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
activityPreviewItems,
|
|
5
|
+
selectedRunMissing,
|
|
6
|
+
effectiveDefinitionResource,
|
|
7
|
+
isDirectRunKind,
|
|
8
|
+
resourceTargetForRun,
|
|
9
|
+
retentionHistoryCopy,
|
|
10
|
+
runMessageNeedsDisclosure,
|
|
11
|
+
workflowDefinitionParameters,
|
|
12
|
+
workflowDefinitionTarget,
|
|
13
|
+
workflowRunArguments,
|
|
14
|
+
workloadRunKey,
|
|
15
|
+
} from './BatchExecutionView'
|
|
4
16
|
|
|
5
17
|
function activity(id: string, tone: WorkflowExecutionActivity['tone'] = 'success'): WorkflowExecutionActivity {
|
|
6
18
|
return { id, at: '2026-01-01T00:00:00Z', label: id, tone }
|
|
@@ -168,3 +180,42 @@ describe('direct run identity', () => {
|
|
|
168
180
|
expect(isDirectRunKind('WorkflowTemplate', 'workflows')).toBe(false)
|
|
169
181
|
})
|
|
170
182
|
})
|
|
183
|
+
|
|
184
|
+
describe('JobSet member presentation', () => {
|
|
185
|
+
it('keeps the selected Job as the core Kubernetes intermediate', () => {
|
|
186
|
+
expect(resourceTargetForRun({
|
|
187
|
+
kind: 'jobs',
|
|
188
|
+
group: 'batch',
|
|
189
|
+
namespace: 'training',
|
|
190
|
+
name: 'distributed-workers-2',
|
|
191
|
+
phase: 'Running',
|
|
192
|
+
active: true,
|
|
193
|
+
})).toEqual({
|
|
194
|
+
kind: 'jobs',
|
|
195
|
+
group: 'batch',
|
|
196
|
+
namespace: 'training',
|
|
197
|
+
name: 'distributed-workers-2',
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
describe('selection across a member refresh', () => {
|
|
203
|
+
it('preserves a selected Job that has fallen outside the shown window', () => {
|
|
204
|
+
const shown = [{ kind: 'jobs', group: 'batch', namespace: 'training', name: 'current', phase: 'Running', active: true }]
|
|
205
|
+
expect(selectedRunMissing(shown, 'jobs/training/earlier')).toBe(true)
|
|
206
|
+
expect(selectedRunMissing(shown, 'jobs/training/current')).toBe(false)
|
|
207
|
+
expect(selectedRunMissing([], 'jobs/training/earlier')).toBe(true)
|
|
208
|
+
expect(selectedRunMissing(shown, '')).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
describe('run navigation identity', () => {
|
|
214
|
+
it('uses the reported group and preserves the released selection address', () => {
|
|
215
|
+
const run = { group: 'batch', kind: 'jobs', namespace: 'training', name: 'worker', phase: 'Running', active: true }
|
|
216
|
+
expect(workloadRunKey(run)).toBe('jobs/training/worker')
|
|
217
|
+
expect(resourceTargetForRun(run).group).toBe('batch')
|
|
218
|
+
expect(resourceTargetForRun({ ...run, group: 'batch.volcano.sh' }).group).toBe('batch.volcano.sh')
|
|
219
|
+
expect(resourceTargetForRun({ ...run, group: 'argoproj.io', kind: 'workflows' }).group).toBe('argoproj.io')
|
|
220
|
+
})
|
|
221
|
+
})
|