@skyhook-io/radar-app 0.2.2 → 0.3.1
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 +7 -1
- package/package.json +33 -25
- package/src/App.tsx +1449 -382
- package/src/RadarApp.tsx +132 -19
- package/src/api/apiResources.ts +1 -1
- package/src/api/client.argoResourceSync.test.ts +69 -0
- package/src/api/client.delta.test.ts +89 -0
- package/src/api/client.deltaSync.test.ts +216 -0
- package/src/api/client.metrics.test.ts +106 -0
- package/src/api/client.rightsizing.test.ts +32 -0
- package/src/api/client.ts +2730 -271
- package/src/api/client.yaml.test.ts +45 -0
- package/src/api/diagnose.ts +289 -0
- package/src/api/quotas.ts +16 -0
- package/src/api/rbac.ts +57 -0
- package/src/api/timelineSource.test.ts +217 -0
- package/src/api/timelineSource.ts +582 -0
- package/src/components/ConnectionErrorView.tsx +186 -70
- package/src/components/ContextSwitcher.tsx +63 -18
- package/src/components/DebugOverlay.tsx +5 -3
- package/src/components/NamespaceSwitcher.tsx +41 -0
- package/src/components/UserMenu.tsx +69 -21
- package/src/components/applications/ApplicationsView.tsx +936 -0
- package/src/components/audit/AuditSettingsDialog.tsx +79 -17
- package/src/components/audit/AuditView.tsx +65 -62
- package/src/components/compare/CompareViewRoute.tsx +124 -0
- package/src/components/compare/useCompareCandidates.ts +27 -0
- package/src/components/compare/useCompareLauncher.tsx +79 -0
- package/src/components/cost/ApplicationCostTab.test.ts +204 -0
- package/src/components/cost/ApplicationCostTab.tsx +571 -0
- package/src/components/cost/CostTrendChart.tsx +106 -75
- package/src/components/cost/CostView.test.ts +12 -0
- package/src/components/cost/CostView.tsx +507 -223
- package/src/components/cost/CostViewTabs.test.tsx +21 -0
- package/src/components/cost/CostViewTabs.tsx +40 -0
- package/src/components/cost/CurrentAllocationUse.test.ts +21 -0
- package/src/components/cost/CurrentAllocationUse.tsx +126 -0
- package/src/components/cost/WorkloadCostTab.test.ts +153 -0
- package/src/components/cost/WorkloadCostTab.tsx +372 -0
- package/src/components/cost/cloud-console.test.ts +39 -0
- package/src/components/cost/cloud-console.ts +81 -0
- package/src/components/cost/errors.ts +8 -0
- package/src/components/cost/format.test.ts +27 -0
- package/src/components/cost/format.ts +46 -0
- package/src/components/cost/kinds.ts +5 -0
- package/src/components/curl/ServiceCurlButton.tsx +445 -0
- package/src/components/diagnose/AISettings.tsx +147 -0
- package/src/components/diagnose/DiagnoseContext.tsx +495 -0
- package/src/components/diagnose/DiagnoseSurface.tsx +394 -0
- package/src/components/diagnose/Home.tsx +163 -0
- package/src/components/diagnose/InvestigationView.tsx +622 -0
- package/src/components/diagnose/LocalDiagnoseAction.tsx +162 -0
- package/src/components/diagnose/launch.ts +65 -0
- package/src/components/diagnose/parts.tsx +1756 -0
- package/src/components/dock/BottomDock.tsx +2 -3
- package/src/components/dock/DockContext.tsx +1 -0
- package/src/components/dock/TerminalTab.tsx +1 -1
- package/src/components/dock/WorkloadLogsTab.tsx +21 -5
- package/src/components/dock/index.ts +1 -1
- package/src/components/execution/BatchExecutionView.test.ts +170 -0
- package/src/components/execution/BatchExecutionView.tsx +1329 -0
- package/src/components/execution/batch-run-actions.test.ts +48 -0
- package/src/components/execution/batch-run-actions.ts +24 -0
- package/src/components/execution/batch-timeline.test.ts +57 -0
- package/src/components/execution/batch-timeline.ts +46 -0
- package/src/components/execution/execution-definition.test.ts +208 -0
- package/src/components/execution/execution-definition.ts +245 -0
- package/src/components/gitops/ArgoResourceDiffLoader.tsx +23 -0
- package/src/components/gitops/GitOpsView.tsx +1042 -0
- package/src/components/gitops/RevisionMetaChip.tsx +63 -0
- package/src/components/helm/ChartBrowser.tsx +87 -31
- package/src/components/helm/HelmCompareRoute.tsx +1341 -0
- package/src/components/helm/HelmReleaseDrawer.test.ts +17 -0
- package/src/components/helm/HelmReleaseDrawer.tsx +1073 -102
- package/src/components/helm/HelmView.tsx +237 -96
- package/src/components/helm/InstallWizard.tsx +94 -38
- package/src/components/helm/ManifestDiffViewer.tsx +8 -27
- package/src/components/helm/OwnedResources.tsx +34 -59
- package/src/components/helm/RevisionHistory.tsx +52 -3
- package/src/components/helm/RoleGatedPanel.tsx +3 -3
- package/src/components/helm/TrackChartSourceDialog.tsx +185 -0
- package/src/components/helm/ValuesDiffPreview.tsx +17 -7
- package/src/components/helm/ValuesViewer.tsx +49 -53
- package/src/components/helm/helm-utils.ts +4 -0
- package/src/components/home/ActivitySummary.tsx +4 -1
- package/src/components/home/ClusterHealthCard.tsx +56 -42
- package/src/components/home/CostCard.tsx +21 -36
- package/src/components/home/GitOpsControllersCard.tsx +110 -0
- package/src/components/home/HelmSummary.tsx +3 -1
- package/src/components/home/HomeView.tsx +339 -105
- package/src/components/home/MCPSetupDialog.tsx +29 -87
- package/src/components/home/TrafficSummary.tsx +2 -2
- package/src/components/home/mcpToolCatalog.ts +333 -0
- package/src/components/issues/IssuesPane.tsx +151 -0
- package/src/components/logs/LogsViewer.tsx +4 -1
- package/src/components/logs/ScheduledWorkloadLogsViewer.tsx +135 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +4 -1
- package/src/components/nav/PrimaryNavRail.tsx +285 -0
- package/src/components/portforward/PortForwardButton.tsx +118 -47
- package/src/components/portforward/PortForwardManager.tsx +253 -131
- package/src/components/resource/HPACharts.tsx +237 -0
- package/src/components/resource/PVCUsageBar.tsx +59 -0
- package/src/components/resource/PrometheusCharts.tsx +160 -584
- package/src/components/resource/PrometheusChartsGrid.tsx +270 -0
- package/src/components/resource/RestartChart.tsx +133 -0
- package/src/components/resource/RightsizingStrip.test.ts +109 -0
- package/src/components/resource/RightsizingStrip.tsx +363 -0
- package/src/components/resource-drawer/ResourceDrawer.tsx +3 -1
- package/src/components/resources/CompositeRenderer.tsx +101 -0
- package/src/components/resources/ImageFilesystemModal.tsx +19 -12
- package/src/components/resources/PodFilesystemModal.tsx +6 -5
- package/src/components/resources/ResourceDetailDrawer.tsx +13 -3
- package/src/components/resources/ResourcesView.tsx +194 -17
- package/src/components/resources/renderers/CronWorkflowRenderer.tsx +1 -0
- package/src/components/resources/renderers/HPARenderer.tsx +20 -1
- package/src/components/resources/renderers/NamespaceRenderer.tsx +31 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +10 -4
- package/src/components/resources/renderers/PVCRenderer.tsx +19 -1
- package/src/components/resources/renderers/PodRenderer.tsx +30 -6
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +45 -1
- package/src/components/resources/renderers/RoleRenderer.tsx +27 -1
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +28 -1
- package/src/components/resources/renderers/ServiceRenderer.tsx +81 -8
- package/src/components/resources/renderers/WorkloadRenderer.tsx +51 -4
- package/src/components/resources/renderers/index.ts +2 -0
- package/src/components/resources/resource-utils.ts +2 -1
- package/src/components/rightsizing/RightsizingScanView.tsx +938 -0
- package/src/components/rightsizing/copy.test.ts +56 -0
- package/src/components/rightsizing/model.test.ts +227 -0
- package/src/components/rightsizing/model.ts +158 -0
- package/src/components/rightsizing/presentation.test.ts +104 -0
- package/src/components/rightsizing/presentation.ts +94 -0
- package/src/components/settings/MyPermissionsDialog.tsx +241 -0
- package/src/components/settings/SettingsDialog.tsx +1505 -165
- package/src/components/shared/CreateResourceDialog.tsx +9 -2
- package/src/components/shared/LargeClusterNamespacePicker.tsx +3 -3
- package/src/components/timeline/LocalTimelineScrubber.tsx +212 -0
- package/src/components/timeline/RetainedTimelineScrubber.tsx +311 -0
- package/src/components/timeline/TimelineList.tsx +86 -13
- package/src/components/timeline/TimelineSwimlanes.tsx +9 -1299
- package/src/components/timeline/TimelineView.tsx +873 -24
- package/src/components/timeline/TimelineView.urlparams.test.ts +335 -0
- package/src/components/traffic/TrafficFilterSidebar.tsx +10 -45
- package/src/components/traffic/TrafficFlowList.tsx +29 -15
- package/src/components/traffic/TrafficGraph.tsx +42 -24
- package/src/components/traffic/TrafficView.tsx +32 -19
- package/src/components/ui/CommandPalette.tsx +8 -215
- package/src/components/ui/DiagnosticsOverlay.tsx +219 -9
- package/src/components/ui/Markdown.tsx +3 -3
- package/src/components/ui/Omnibar.tsx +602 -0
- package/src/components/ui/RadarOmnibar.tsx +52 -0
- package/src/components/ui/SearchSyntaxHelp.tsx +89 -0
- package/src/components/ui/ShortcutHelpOverlay.tsx +3 -2
- package/src/components/ui/UpdateNotification.tsx +48 -36
- package/src/components/ui/command-items.ts +178 -0
- package/src/components/workload/WorkloadView.tsx +1342 -158
- package/src/context/ConnectionContext.tsx +146 -21
- package/src/context/DiagnoseCustomization.tsx +93 -0
- package/src/context/NavCustomization.tsx +75 -0
- package/src/context/TimelineSource.tsx +50 -0
- package/src/contexts/CapabilitiesContext.tsx +32 -8
- package/src/filter/FilterLocationBridge.tsx +30 -0
- package/src/hooks/useClusterLoadState.ts +73 -0
- package/src/hooks/useDocumentTitle.ts +25 -0
- package/src/hooks/useEventSource.ts +6 -0
- package/src/hooks/useKeyboardShortcuts.tsx +1 -0
- package/src/hooks/useMediaQuery.ts +21 -0
- package/src/hooks/useNavRailPinned.ts +46 -0
- package/src/hooks/useRecentResources.ts +49 -0
- package/src/index.css +162 -1
- package/src/index.ts +73 -1
- package/src/main.tsx +7 -5
- package/src/types/clusterLoadState.ts +33 -0
- package/src/types.ts +2 -0
- package/src/utils/auditBadges.ts +53 -0
- package/src/utils/navigation.ts +64 -1
- package/src/components/ui/NamespaceSelector.tsx +0 -436
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
ApiError,
|
|
4
|
+
getVisibleLiveMetrics,
|
|
5
|
+
isMetricsUnavailableError,
|
|
6
|
+
isLiveMetricsUnavailable,
|
|
7
|
+
normalizeNodeMetricsHistory,
|
|
8
|
+
normalizePodMetricsHistory,
|
|
9
|
+
shouldFetchLiveMetrics,
|
|
10
|
+
} from './client'
|
|
11
|
+
|
|
12
|
+
describe('metrics unavailable classification', () => {
|
|
13
|
+
it('only treats metrics-shaped API failures as metrics unavailable', () => {
|
|
14
|
+
expect(isMetricsUnavailableError(new ApiError('Node metrics not found (metrics-server may not be installed)', 404))).toBe(true)
|
|
15
|
+
expect(isMetricsUnavailableError(new ApiError('the server could not find the requested resource (get nodes.metrics.k8s.io)', 500))).toBe(true)
|
|
16
|
+
expect(isMetricsUnavailableError(new ApiError('failed to get node metrics: the server could not find the requested resource', 500))).toBe(true)
|
|
17
|
+
expect(isMetricsUnavailableError(new ApiError('the server is currently unable to handle the request (get nodes.metrics.k8s.io)', 500))).toBe(true)
|
|
18
|
+
expect(isMetricsUnavailableError(new ApiError('the server could not find the requested resource', 500))).toBe(false)
|
|
19
|
+
expect(isMetricsUnavailableError(new ApiError('no access to nodes', 403))).toBe(false)
|
|
20
|
+
expect(isMetricsUnavailableError(new ApiError('metrics-server forbidden', 500))).toBe(false)
|
|
21
|
+
expect(isMetricsUnavailableError(new ApiError('database unavailable', 500))).toBe(false)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('uses the server-owned unavailable flag for history responses', () => {
|
|
25
|
+
const podHistory = normalizePodMetricsHistory({
|
|
26
|
+
namespace: 'default',
|
|
27
|
+
name: 'api',
|
|
28
|
+
containers: [],
|
|
29
|
+
metricsUnavailable: true,
|
|
30
|
+
collectionError: 'the server could not find the requested resource (get pods.metrics.k8s.io)',
|
|
31
|
+
rawCollectionError: 'the server could not find the requested resource',
|
|
32
|
+
metricsUnavailableDiagnosis: 'The v1beta1.metrics.k8s.io APIService is not registered. Install metrics-server or restore that APIService.',
|
|
33
|
+
})
|
|
34
|
+
expect(podHistory.collectionError).toBeUndefined()
|
|
35
|
+
expect(podHistory.rawCollectionError).toBeUndefined()
|
|
36
|
+
expect(podHistory.metricsUnavailable).toBe(true)
|
|
37
|
+
expect(podHistory.metricsUnavailableReason).toBe('the server could not find the requested resource')
|
|
38
|
+
expect(podHistory.metricsUnavailableDiagnosis).toBe('The v1beta1.metrics.k8s.io APIService is not registered. Install metrics-server or restore that APIService.')
|
|
39
|
+
|
|
40
|
+
const nodeHistory = normalizeNodeMetricsHistory({
|
|
41
|
+
name: 'kind-worker',
|
|
42
|
+
dataPoints: [],
|
|
43
|
+
metricsUnavailable: true,
|
|
44
|
+
collectionError: 'Node metrics not found (metrics-server may not be installed)',
|
|
45
|
+
rawCollectionError: 'the server could not find the requested resource',
|
|
46
|
+
metricsUnavailableDiagnosis: 'The v1beta1.metrics.k8s.io APIService is not Available (FailedDiscoveryCheck). Check the metrics-server Service, endpoints, and API aggregation/TLS configuration.',
|
|
47
|
+
})
|
|
48
|
+
expect(nodeHistory.collectionError).toBeUndefined()
|
|
49
|
+
expect(nodeHistory.rawCollectionError).toBeUndefined()
|
|
50
|
+
expect(nodeHistory.metricsUnavailable).toBe(true)
|
|
51
|
+
expect(nodeHistory.metricsUnavailableReason).toBe('the server could not find the requested resource')
|
|
52
|
+
expect(nodeHistory.metricsUnavailableDiagnosis).toBe('The v1beta1.metrics.k8s.io APIService is not Available (FailedDiscoveryCheck). Check the metrics-server Service, endpoints, and API aggregation/TLS configuration.')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('does not infer history unavailability from collection-error copy', () => {
|
|
56
|
+
const history = normalizeNodeMetricsHistory({
|
|
57
|
+
name: 'kind-worker',
|
|
58
|
+
dataPoints: [],
|
|
59
|
+
collectionError: 'Node metrics not found (metrics-server may not be installed)',
|
|
60
|
+
rawCollectionError: 'the server could not find the requested resource',
|
|
61
|
+
})
|
|
62
|
+
expect(history.collectionError).toBe('Node metrics not found (metrics-server may not be installed)')
|
|
63
|
+
expect(history.rawCollectionError).toBe('the server could not find the requested resource')
|
|
64
|
+
expect(history.metricsUnavailable).toBeUndefined()
|
|
65
|
+
expect(history.metricsUnavailableReason).toBeUndefined()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('keeps non-metrics collection errors visible', () => {
|
|
69
|
+
const history = normalizeNodeMetricsHistory({
|
|
70
|
+
name: 'kind-worker',
|
|
71
|
+
dataPoints: [],
|
|
72
|
+
collectionError: 'forbidden: no access to nodes',
|
|
73
|
+
})
|
|
74
|
+
expect(history.collectionError).toBe('forbidden: no access to nodes')
|
|
75
|
+
expect(history.metricsUnavailable).toBeUndefined()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('keeps generic not-found collection errors visible without a metrics API signal', () => {
|
|
79
|
+
const history = normalizeNodeMetricsHistory({
|
|
80
|
+
name: 'kind-worker',
|
|
81
|
+
dataPoints: [],
|
|
82
|
+
collectionError: 'the server could not find the requested resource',
|
|
83
|
+
})
|
|
84
|
+
expect(history.collectionError).toBe('the server could not find the requested resource')
|
|
85
|
+
expect(history.metricsUnavailable).toBeUndefined()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('waits for history classification before live metrics fetches', () => {
|
|
89
|
+
expect(shouldFetchLiveMetrics(false, false)).toBe(false)
|
|
90
|
+
expect(shouldFetchLiveMetrics(true, false)).toBe(true)
|
|
91
|
+
expect(shouldFetchLiveMetrics(true, true)).toBe(false)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('does not expose cached live metrics while the live query is disabled', () => {
|
|
95
|
+
const cachedMetrics = { usage: { cpu: '10m', memory: '20Mi' } }
|
|
96
|
+
expect(getVisibleLiveMetrics(false, false, cachedMetrics)).toBeUndefined()
|
|
97
|
+
expect(getVisibleLiveMetrics(true, true, cachedMetrics)).toBeUndefined()
|
|
98
|
+
expect(getVisibleLiveMetrics(true, false, cachedMetrics)).toBe(cachedMetrics)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('treats null live metrics as unavailable only after live fetch is enabled', () => {
|
|
102
|
+
expect(isLiveMetricsUnavailable(false, null)).toBe(false)
|
|
103
|
+
expect(isLiveMetricsUnavailable(true, null)).toBe(true)
|
|
104
|
+
expect(isLiveMetricsUnavailable(true, undefined)).toBe(false)
|
|
105
|
+
})
|
|
106
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { skipToken } from '@tanstack/react-query'
|
|
3
|
+
import { getRightsizingScanCacheConfig } from './client'
|
|
4
|
+
|
|
5
|
+
describe('rightsizing scan cache config', () => {
|
|
6
|
+
it('is manual-only and retained briefly', () => {
|
|
7
|
+
const config = getRightsizingScanCacheConfig(['staging', 'default'], 'cluster-a')
|
|
8
|
+
|
|
9
|
+
expect(config.queryFn).toBe(skipToken)
|
|
10
|
+
expect(config.gcTime).toBe(5 * 60 * 1000)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('normalizes namespace order and isolates cluster and namespace scopes', () => {
|
|
14
|
+
const config = getRightsizingScanCacheConfig(['staging', 'default'], 'cluster-a')
|
|
15
|
+
|
|
16
|
+
expect(config.namespaceKey).toBe('default,staging')
|
|
17
|
+
expect(config.queryKey).toEqual([
|
|
18
|
+
'prometheus-rightsizing-scan',
|
|
19
|
+
'cluster-a',
|
|
20
|
+
'default,staging',
|
|
21
|
+
])
|
|
22
|
+
expect(getRightsizingScanCacheConfig(['default', 'staging'], 'cluster-a').queryKey).toEqual(
|
|
23
|
+
config.queryKey,
|
|
24
|
+
)
|
|
25
|
+
expect(getRightsizingScanCacheConfig(['default'], 'cluster-a').queryKey).not.toEqual(
|
|
26
|
+
config.queryKey,
|
|
27
|
+
)
|
|
28
|
+
expect(getRightsizingScanCacheConfig(['staging', 'default'], 'cluster-b').queryKey).not.toEqual(
|
|
29
|
+
config.queryKey,
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
})
|