@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.
Files changed (177) hide show
  1. package/README.md +7 -1
  2. package/package.json +33 -25
  3. package/src/App.tsx +1449 -382
  4. package/src/RadarApp.tsx +132 -19
  5. package/src/api/apiResources.ts +1 -1
  6. package/src/api/client.argoResourceSync.test.ts +69 -0
  7. package/src/api/client.delta.test.ts +89 -0
  8. package/src/api/client.deltaSync.test.ts +216 -0
  9. package/src/api/client.metrics.test.ts +106 -0
  10. package/src/api/client.rightsizing.test.ts +32 -0
  11. package/src/api/client.ts +2730 -271
  12. package/src/api/client.yaml.test.ts +45 -0
  13. package/src/api/diagnose.ts +289 -0
  14. package/src/api/quotas.ts +16 -0
  15. package/src/api/rbac.ts +57 -0
  16. package/src/api/timelineSource.test.ts +217 -0
  17. package/src/api/timelineSource.ts +582 -0
  18. package/src/components/ConnectionErrorView.tsx +186 -70
  19. package/src/components/ContextSwitcher.tsx +63 -18
  20. package/src/components/DebugOverlay.tsx +5 -3
  21. package/src/components/NamespaceSwitcher.tsx +41 -0
  22. package/src/components/UserMenu.tsx +69 -21
  23. package/src/components/applications/ApplicationsView.tsx +936 -0
  24. package/src/components/audit/AuditSettingsDialog.tsx +79 -17
  25. package/src/components/audit/AuditView.tsx +65 -62
  26. package/src/components/compare/CompareViewRoute.tsx +124 -0
  27. package/src/components/compare/useCompareCandidates.ts +27 -0
  28. package/src/components/compare/useCompareLauncher.tsx +79 -0
  29. package/src/components/cost/ApplicationCostTab.test.ts +204 -0
  30. package/src/components/cost/ApplicationCostTab.tsx +571 -0
  31. package/src/components/cost/CostTrendChart.tsx +106 -75
  32. package/src/components/cost/CostView.test.ts +12 -0
  33. package/src/components/cost/CostView.tsx +507 -223
  34. package/src/components/cost/CostViewTabs.test.tsx +21 -0
  35. package/src/components/cost/CostViewTabs.tsx +40 -0
  36. package/src/components/cost/CurrentAllocationUse.test.ts +21 -0
  37. package/src/components/cost/CurrentAllocationUse.tsx +126 -0
  38. package/src/components/cost/WorkloadCostTab.test.ts +153 -0
  39. package/src/components/cost/WorkloadCostTab.tsx +372 -0
  40. package/src/components/cost/cloud-console.test.ts +39 -0
  41. package/src/components/cost/cloud-console.ts +81 -0
  42. package/src/components/cost/errors.ts +8 -0
  43. package/src/components/cost/format.test.ts +27 -0
  44. package/src/components/cost/format.ts +46 -0
  45. package/src/components/cost/kinds.ts +5 -0
  46. package/src/components/curl/ServiceCurlButton.tsx +445 -0
  47. package/src/components/diagnose/AISettings.tsx +147 -0
  48. package/src/components/diagnose/DiagnoseContext.tsx +495 -0
  49. package/src/components/diagnose/DiagnoseSurface.tsx +394 -0
  50. package/src/components/diagnose/Home.tsx +163 -0
  51. package/src/components/diagnose/InvestigationView.tsx +622 -0
  52. package/src/components/diagnose/LocalDiagnoseAction.tsx +162 -0
  53. package/src/components/diagnose/launch.ts +65 -0
  54. package/src/components/diagnose/parts.tsx +1756 -0
  55. package/src/components/dock/BottomDock.tsx +2 -3
  56. package/src/components/dock/DockContext.tsx +1 -0
  57. package/src/components/dock/TerminalTab.tsx +1 -1
  58. package/src/components/dock/WorkloadLogsTab.tsx +21 -5
  59. package/src/components/dock/index.ts +1 -1
  60. package/src/components/execution/BatchExecutionView.test.ts +170 -0
  61. package/src/components/execution/BatchExecutionView.tsx +1329 -0
  62. package/src/components/execution/batch-run-actions.test.ts +48 -0
  63. package/src/components/execution/batch-run-actions.ts +24 -0
  64. package/src/components/execution/batch-timeline.test.ts +57 -0
  65. package/src/components/execution/batch-timeline.ts +46 -0
  66. package/src/components/execution/execution-definition.test.ts +208 -0
  67. package/src/components/execution/execution-definition.ts +245 -0
  68. package/src/components/gitops/ArgoResourceDiffLoader.tsx +23 -0
  69. package/src/components/gitops/GitOpsView.tsx +1042 -0
  70. package/src/components/gitops/RevisionMetaChip.tsx +63 -0
  71. package/src/components/helm/ChartBrowser.tsx +87 -31
  72. package/src/components/helm/HelmCompareRoute.tsx +1341 -0
  73. package/src/components/helm/HelmReleaseDrawer.test.ts +17 -0
  74. package/src/components/helm/HelmReleaseDrawer.tsx +1073 -102
  75. package/src/components/helm/HelmView.tsx +237 -96
  76. package/src/components/helm/InstallWizard.tsx +94 -38
  77. package/src/components/helm/ManifestDiffViewer.tsx +8 -27
  78. package/src/components/helm/OwnedResources.tsx +34 -59
  79. package/src/components/helm/RevisionHistory.tsx +52 -3
  80. package/src/components/helm/RoleGatedPanel.tsx +3 -3
  81. package/src/components/helm/TrackChartSourceDialog.tsx +185 -0
  82. package/src/components/helm/ValuesDiffPreview.tsx +17 -7
  83. package/src/components/helm/ValuesViewer.tsx +49 -53
  84. package/src/components/helm/helm-utils.ts +4 -0
  85. package/src/components/home/ActivitySummary.tsx +4 -1
  86. package/src/components/home/ClusterHealthCard.tsx +56 -42
  87. package/src/components/home/CostCard.tsx +21 -36
  88. package/src/components/home/GitOpsControllersCard.tsx +110 -0
  89. package/src/components/home/HelmSummary.tsx +3 -1
  90. package/src/components/home/HomeView.tsx +339 -105
  91. package/src/components/home/MCPSetupDialog.tsx +29 -87
  92. package/src/components/home/TrafficSummary.tsx +2 -2
  93. package/src/components/home/mcpToolCatalog.ts +333 -0
  94. package/src/components/issues/IssuesPane.tsx +151 -0
  95. package/src/components/logs/LogsViewer.tsx +4 -1
  96. package/src/components/logs/ScheduledWorkloadLogsViewer.tsx +135 -0
  97. package/src/components/logs/WorkloadLogsViewer.tsx +4 -1
  98. package/src/components/nav/PrimaryNavRail.tsx +285 -0
  99. package/src/components/portforward/PortForwardButton.tsx +118 -47
  100. package/src/components/portforward/PortForwardManager.tsx +253 -131
  101. package/src/components/resource/HPACharts.tsx +237 -0
  102. package/src/components/resource/PVCUsageBar.tsx +59 -0
  103. package/src/components/resource/PrometheusCharts.tsx +160 -584
  104. package/src/components/resource/PrometheusChartsGrid.tsx +270 -0
  105. package/src/components/resource/RestartChart.tsx +133 -0
  106. package/src/components/resource/RightsizingStrip.test.ts +109 -0
  107. package/src/components/resource/RightsizingStrip.tsx +363 -0
  108. package/src/components/resource-drawer/ResourceDrawer.tsx +3 -1
  109. package/src/components/resources/CompositeRenderer.tsx +101 -0
  110. package/src/components/resources/ImageFilesystemModal.tsx +19 -12
  111. package/src/components/resources/PodFilesystemModal.tsx +6 -5
  112. package/src/components/resources/ResourceDetailDrawer.tsx +13 -3
  113. package/src/components/resources/ResourcesView.tsx +194 -17
  114. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +1 -0
  115. package/src/components/resources/renderers/HPARenderer.tsx +20 -1
  116. package/src/components/resources/renderers/NamespaceRenderer.tsx +31 -0
  117. package/src/components/resources/renderers/NodeRenderer.tsx +10 -4
  118. package/src/components/resources/renderers/PVCRenderer.tsx +19 -1
  119. package/src/components/resources/renderers/PodRenderer.tsx +30 -6
  120. package/src/components/resources/renderers/RoleBindingRenderer.tsx +45 -1
  121. package/src/components/resources/renderers/RoleRenderer.tsx +27 -1
  122. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +28 -1
  123. package/src/components/resources/renderers/ServiceRenderer.tsx +81 -8
  124. package/src/components/resources/renderers/WorkloadRenderer.tsx +51 -4
  125. package/src/components/resources/renderers/index.ts +2 -0
  126. package/src/components/resources/resource-utils.ts +2 -1
  127. package/src/components/rightsizing/RightsizingScanView.tsx +938 -0
  128. package/src/components/rightsizing/copy.test.ts +56 -0
  129. package/src/components/rightsizing/model.test.ts +227 -0
  130. package/src/components/rightsizing/model.ts +158 -0
  131. package/src/components/rightsizing/presentation.test.ts +104 -0
  132. package/src/components/rightsizing/presentation.ts +94 -0
  133. package/src/components/settings/MyPermissionsDialog.tsx +241 -0
  134. package/src/components/settings/SettingsDialog.tsx +1505 -165
  135. package/src/components/shared/CreateResourceDialog.tsx +9 -2
  136. package/src/components/shared/LargeClusterNamespacePicker.tsx +3 -3
  137. package/src/components/timeline/LocalTimelineScrubber.tsx +212 -0
  138. package/src/components/timeline/RetainedTimelineScrubber.tsx +311 -0
  139. package/src/components/timeline/TimelineList.tsx +86 -13
  140. package/src/components/timeline/TimelineSwimlanes.tsx +9 -1299
  141. package/src/components/timeline/TimelineView.tsx +873 -24
  142. package/src/components/timeline/TimelineView.urlparams.test.ts +335 -0
  143. package/src/components/traffic/TrafficFilterSidebar.tsx +10 -45
  144. package/src/components/traffic/TrafficFlowList.tsx +29 -15
  145. package/src/components/traffic/TrafficGraph.tsx +42 -24
  146. package/src/components/traffic/TrafficView.tsx +32 -19
  147. package/src/components/ui/CommandPalette.tsx +8 -215
  148. package/src/components/ui/DiagnosticsOverlay.tsx +219 -9
  149. package/src/components/ui/Markdown.tsx +3 -3
  150. package/src/components/ui/Omnibar.tsx +602 -0
  151. package/src/components/ui/RadarOmnibar.tsx +52 -0
  152. package/src/components/ui/SearchSyntaxHelp.tsx +89 -0
  153. package/src/components/ui/ShortcutHelpOverlay.tsx +3 -2
  154. package/src/components/ui/UpdateNotification.tsx +48 -36
  155. package/src/components/ui/command-items.ts +178 -0
  156. package/src/components/workload/WorkloadView.tsx +1342 -158
  157. package/src/context/ConnectionContext.tsx +146 -21
  158. package/src/context/DiagnoseCustomization.tsx +93 -0
  159. package/src/context/NavCustomization.tsx +75 -0
  160. package/src/context/TimelineSource.tsx +50 -0
  161. package/src/contexts/CapabilitiesContext.tsx +32 -8
  162. package/src/filter/FilterLocationBridge.tsx +30 -0
  163. package/src/hooks/useClusterLoadState.ts +73 -0
  164. package/src/hooks/useDocumentTitle.ts +25 -0
  165. package/src/hooks/useEventSource.ts +6 -0
  166. package/src/hooks/useKeyboardShortcuts.tsx +1 -0
  167. package/src/hooks/useMediaQuery.ts +21 -0
  168. package/src/hooks/useNavRailPinned.ts +46 -0
  169. package/src/hooks/useRecentResources.ts +49 -0
  170. package/src/index.css +162 -1
  171. package/src/index.ts +73 -1
  172. package/src/main.tsx +7 -5
  173. package/src/types/clusterLoadState.ts +33 -0
  174. package/src/types.ts +2 -0
  175. package/src/utils/auditBadges.ts +53 -0
  176. package/src/utils/navigation.ts +64 -1
  177. package/src/components/ui/NamespaceSelector.tsx +0 -436
@@ -0,0 +1,204 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { AppWorkload } from '@skyhook-io/k8s-ui'
3
+ import { applicationCostWorkloads, getApplicationCostState } from './ApplicationCostTab'
4
+ import {
5
+ ApiError,
6
+ type OpenCostApplicationCostResponse,
7
+ type OpenCostApplicationCostTrendResponse,
8
+ } from '../../api/client'
9
+
10
+ describe('getApplicationCostState', () => {
11
+ it('keeps current app cost visible when historical owner metrics are missing', () => {
12
+ const current: OpenCostApplicationCostResponse = {
13
+ available: true,
14
+ partial: true,
15
+ totals: {
16
+ hourlyCost: 0.4,
17
+ cpuCost: 0.25,
18
+ memoryCost: 0.15,
19
+ replicas: 3,
20
+ cpuUsageAvailable: true,
21
+ memoryUsageAvailable: true,
22
+ cpuAllocationUse: 40,
23
+ memoryAllocationUse: 60,
24
+ },
25
+ coverage: {
26
+ total: 3,
27
+ included: 2,
28
+ unavailable: [
29
+ {
30
+ kind: 'Deployment',
31
+ namespace: 'prod',
32
+ name: 'worker',
33
+ reason: 'no_metrics',
34
+ },
35
+ ],
36
+ },
37
+ workloads: [],
38
+ }
39
+ const trend: OpenCostApplicationCostTrendResponse = {
40
+ available: false,
41
+ reason: 'no_metrics',
42
+ range: '24h',
43
+ coverage: { total: 3, included: 0 },
44
+ }
45
+
46
+ expect(
47
+ getApplicationCostState(current, trend, {
48
+ currentLoading: false,
49
+ trendLoading: false,
50
+ }),
51
+ ).toBe('partial_missing_history')
52
+ })
53
+
54
+ it('uses historical data when current app metrics are absent but history exists', () => {
55
+ const current: OpenCostApplicationCostResponse = {
56
+ available: false,
57
+ reason: 'no_metrics',
58
+ totals: {
59
+ hourlyCost: 0,
60
+ cpuCost: 0,
61
+ memoryCost: 0,
62
+ replicas: 0,
63
+ cpuUsageAvailable: false,
64
+ memoryUsageAvailable: false,
65
+ cpuAllocationUse: 0,
66
+ memoryAllocationUse: 0,
67
+ },
68
+ coverage: { total: 2, included: 0 },
69
+ }
70
+ const trend: OpenCostApplicationCostTrendResponse = {
71
+ available: true,
72
+ range: '7d',
73
+ windowTotalCost: 2,
74
+ dataPoints: [
75
+ { timestamp: 1700000000, value: 0.2 },
76
+ { timestamp: 1700003600, value: 0.3 },
77
+ ],
78
+ coverage: { total: 2, included: 2 },
79
+ }
80
+
81
+ expect(
82
+ getApplicationCostState(current, trend, {
83
+ currentLoading: false,
84
+ trendLoading: false,
85
+ }),
86
+ ).toBe('partial_missing_current')
87
+ })
88
+
89
+ it('treats all tracked workloads scaled to zero as valid zero state', () => {
90
+ const current: OpenCostApplicationCostResponse = {
91
+ available: true,
92
+ totals: {
93
+ hourlyCost: 0,
94
+ cpuCost: 0,
95
+ memoryCost: 0,
96
+ replicas: 0,
97
+ cpuUsageAvailable: false,
98
+ memoryUsageAvailable: false,
99
+ cpuAllocationUse: 0,
100
+ memoryAllocationUse: 0,
101
+ },
102
+ coverage: { total: 1, included: 1 },
103
+ workloads: [
104
+ {
105
+ kind: 'Deployment',
106
+ namespace: 'prod',
107
+ name: 'api',
108
+ available: true,
109
+ scaledToZero: true,
110
+ current: {
111
+ name: 'api',
112
+ kind: 'Deployment',
113
+ hourlyCost: 0,
114
+ cpuCost: 0,
115
+ memoryCost: 0,
116
+ replicas: 0,
117
+ cpuUsageAvailable: false,
118
+ memoryUsageAvailable: false,
119
+ cpuAllocationUse: 0,
120
+ memoryAllocationUse: 0,
121
+ },
122
+ },
123
+ ],
124
+ }
125
+
126
+ expect(
127
+ getApplicationCostState(current, undefined, {
128
+ currentLoading: false,
129
+ trendLoading: false,
130
+ }),
131
+ ).toBe('zero')
132
+ })
133
+
134
+ it('separates query load failures from absent app metrics', () => {
135
+ expect(getApplicationCostState(undefined, undefined, { currentError: true })).toBe('load_error')
136
+ })
137
+
138
+ it('preserves transport error specificity', () => {
139
+ expect(
140
+ getApplicationCostState(undefined, undefined, {
141
+ currentError: new ApiError('denied', 403),
142
+ }),
143
+ ).toBe('access_denied')
144
+ expect(
145
+ getApplicationCostState(undefined, undefined, {
146
+ trendError: new ApiError('missing', 404),
147
+ }),
148
+ ).toBe('not_found')
149
+ })
150
+
151
+ it('queries only steady-state workload kinds', () => {
152
+ const workloads = [
153
+ { kind: 'Deployment', namespace: 'prod', name: 'api' },
154
+ { kind: 'StatefulSet', namespace: 'prod', name: 'db' },
155
+ { kind: 'DaemonSet', namespace: 'ops', name: 'agent' },
156
+ { kind: 'Job', namespace: 'prod', name: 'migrate' },
157
+ { kind: 'CronJob', namespace: 'prod', name: 'cleanup' },
158
+ ] as AppWorkload[]
159
+
160
+ expect(applicationCostWorkloads(workloads).map((workload) => workload.kind)).toEqual([
161
+ 'Deployment',
162
+ 'StatefulSet',
163
+ 'DaemonSet',
164
+ ])
165
+ expect(applicationCostWorkloads(workloads.slice(3))).toEqual([])
166
+ })
167
+
168
+ it('surfaces app workload access and existence failures', () => {
169
+ const current: OpenCostApplicationCostResponse = {
170
+ available: false,
171
+ reason: 'access_denied',
172
+ totals: {
173
+ hourlyCost: 0,
174
+ cpuCost: 0,
175
+ memoryCost: 0,
176
+ replicas: 0,
177
+ cpuUsageAvailable: false,
178
+ memoryUsageAvailable: false,
179
+ cpuAllocationUse: 0,
180
+ memoryAllocationUse: 0,
181
+ },
182
+ coverage: {
183
+ total: 1,
184
+ included: 0,
185
+ unavailable: [
186
+ {
187
+ kind: 'Deployment',
188
+ namespace: 'prod',
189
+ name: 'api',
190
+ reason: 'access_denied',
191
+ },
192
+ ],
193
+ },
194
+ }
195
+
196
+ expect(
197
+ getApplicationCostState(current, undefined, {
198
+ currentLoading: false,
199
+ trendLoading: false,
200
+ }),
201
+ ).toBe('access_denied')
202
+ expect(getApplicationCostState(current, undefined, { trendError: true })).toBe('access_denied')
203
+ })
204
+ })