@skyhook-io/k8s-ui 1.8.11 → 1.8.13

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 (87) hide show
  1. package/package.json +4 -4
  2. package/src/components/applications/ApplicationDetail.test.tsx +136 -8
  3. package/src/components/applications/ApplicationDetail.tsx +1215 -487
  4. package/src/components/gitops/GitOpsDetailLayout.tsx +13 -3
  5. package/src/components/gitops/GitOpsTableView.tsx +10 -3
  6. package/src/components/gitops/SyncOptionsDialog.test.ts +48 -0
  7. package/src/components/gitops/SyncOptionsDialog.tsx +189 -45
  8. package/src/components/gitops/insights/ArgoResourceDiff.tsx +172 -0
  9. package/src/components/gitops/insights/GitOpsInsightViews.tsx +201 -21
  10. package/src/components/gitops/insights/index.ts +1 -0
  11. package/src/components/gitops/insights/insights-helpers.test.ts +16 -0
  12. package/src/components/gitops/insights/insights-helpers.ts +5 -0
  13. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +5 -0
  14. package/src/components/issues/IssuesView.tsx +55 -29
  15. package/src/components/issues/ResourceIssuesSection.test.tsx +33 -1
  16. package/src/components/issues/ResourceIssuesSection.tsx +21 -1
  17. package/src/components/issues/severity.ts +1 -0
  18. package/src/components/resources/ResourcesView.tsx +109 -19
  19. package/src/components/resources/column-filter-serialization.test.ts +79 -1
  20. package/src/components/resources/renderers/AWSMachineRenderer.tsx +3 -2
  21. package/src/components/resources/renderers/AWSManagedClusterRenderer.tsx +3 -2
  22. package/src/components/resources/renderers/AWSManagedControlPlaneRenderer.tsx +3 -2
  23. package/src/components/resources/renderers/AWSManagedMachinePoolRenderer.tsx +3 -2
  24. package/src/components/resources/renderers/AzureMachineRenderer.tsx +3 -2
  25. package/src/components/resources/renderers/AzureManagedControlPlaneRenderer.tsx +3 -2
  26. package/src/components/resources/renderers/AzureManagedMachinePoolRenderer.tsx +3 -2
  27. package/src/components/resources/renderers/CAPIClusterRenderer.tsx +3 -2
  28. package/src/components/resources/renderers/CAPIKubeadmControlPlaneRenderer.tsx +3 -2
  29. package/src/components/resources/renderers/CAPIMachineDeploymentRenderer.tsx +3 -2
  30. package/src/components/resources/renderers/CAPIMachineHealthCheckRenderer.tsx +3 -2
  31. package/src/components/resources/renderers/CAPIMachinePoolRenderer.tsx +3 -2
  32. package/src/components/resources/renderers/CAPIMachineRenderer.tsx +3 -2
  33. package/src/components/resources/renderers/CAPIMachineSetRenderer.tsx +3 -2
  34. package/src/components/resources/renderers/CertificateRenderer.tsx +3 -2
  35. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +3 -2
  36. package/src/components/resources/renderers/CompositeRenderer.tsx +3 -2
  37. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +3 -2
  38. package/src/components/resources/renderers/GCPMachineRenderer.tsx +3 -2
  39. package/src/components/resources/renderers/GCPManagedControlPlaneRenderer.tsx +3 -2
  40. package/src/components/resources/renderers/GCPManagedMachinePoolRenderer.tsx +3 -2
  41. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +7 -3
  42. package/src/components/resources/renderers/GatewayClassRenderer.tsx +3 -2
  43. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +7 -3
  44. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +3 -2
  45. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +3 -2
  46. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +3 -2
  47. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +3 -2
  48. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +3 -2
  49. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +3 -2
  50. package/src/components/resources/renderers/PVCRenderer.tsx +3 -2
  51. package/src/components/resources/renderers/SealedSecretRenderer.tsx +3 -2
  52. package/src/components/resources/renderers/SecretStoreRenderer.tsx +3 -2
  53. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +7 -3
  54. package/src/components/resources/resource-utils-argo.test.ts +18 -1
  55. package/src/components/resources/resource-utils-argo.ts +8 -0
  56. package/src/components/resources/resource-utils.ts +94 -25
  57. package/src/components/shared/ResourceActionsBar.tsx +54 -22
  58. package/src/components/shared/UnifiedDiff.tsx +51 -0
  59. package/src/components/shared/index.ts +1 -0
  60. package/src/components/timeline/TimelineList.tsx +7 -3
  61. package/src/components/timeline/TimelineToolbarState.test.tsx +24 -0
  62. package/src/components/topology/TopologyBreadcrumb.tsx +30 -0
  63. package/src/components/topology/TopologyControls.tsx +3 -1
  64. package/src/components/topology/TopologyGraph.tsx +76 -90
  65. package/src/components/topology/TopologyOverlayBar.tsx +30 -0
  66. package/src/components/topology/TopologySearch.tsx +23 -15
  67. package/src/components/topology/index.ts +2 -0
  68. package/src/components/ui/Badge.tsx +1 -1
  69. package/src/components/ui/SelectMenu.tsx +81 -0
  70. package/src/components/ui/Tooltip.test.tsx +21 -0
  71. package/src/components/ui/Tooltip.tsx +9 -12
  72. package/src/components/ui/drawer-components.tsx +9 -6
  73. package/src/components/ui/index.ts +2 -0
  74. package/src/components/workload/WorkloadView.tsx +24 -3
  75. package/src/theme/tailwind-theme.css +1 -0
  76. package/src/theme/variables.css +1 -0
  77. package/src/types/gitops-insights.ts +69 -1
  78. package/src/types/gitops.ts +3 -3
  79. package/src/utils/api-resources.test.ts +36 -1
  80. package/src/utils/api-resources.ts +16 -0
  81. package/src/utils/application-history.test.ts +538 -0
  82. package/src/utils/application-history.ts +257 -0
  83. package/src/utils/applications.test.ts +34 -0
  84. package/src/utils/applications.ts +25 -0
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/resource-hierarchy.test.ts +35 -1
  87. package/src/utils/resource-hierarchy.ts +20 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyhook-io/k8s-ui",
3
- "version": "1.8.11",
3
+ "version": "1.8.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/skyhook-io/radar",
@@ -92,15 +92,15 @@
92
92
  "@xterm/addon-fit": "^0.11.0",
93
93
  "@xterm/addon-web-links": "^0.12.0",
94
94
  "@xterm/xterm": "^6.0.0",
95
- "@xyflow/react": "^12.10.1",
95
+ "@xyflow/react": "^12.11.2",
96
96
  "clsx": "^2.1.1",
97
97
  "diff": "^9.0.0",
98
98
  "elkjs": "^0.11.1",
99
- "lucide-react": "^1.23.0",
99
+ "lucide-react": "^1.24.0",
100
100
  "react": "^19.2.7",
101
101
  "react-dom": "^19.2.7",
102
102
  "typescript": "^6.0.2",
103
- "vitest": "^4.1.8",
103
+ "vitest": "^4.1.10",
104
104
  "yaml": "^2.9.0"
105
105
  }
106
106
  }
@@ -148,6 +148,33 @@ describe("ApplicationDetail shell", () => {
148
148
  expect(html).not.toContain('Application identity')
149
149
  })
150
150
 
151
+ it("renders the optional application cost view only when the host selects it", () => {
152
+ const withCostTab = renderDetail({
153
+ selectedView: "overview",
154
+ onSelectView: () => {},
155
+ selectedWorkloadKey: null,
156
+ onSelectWorkload: () => {},
157
+ renderCostView: () => <div>Application cost body</div>,
158
+ });
159
+
160
+ expect(withCostTab).toContain("Cost");
161
+ expect(withCostTab).not.toContain("Application cost body");
162
+
163
+ const selectedCost = renderDetail({
164
+ selectedView: "overview",
165
+ onSelectView: () => {},
166
+ selectedWorkloadKey: null,
167
+ onSelectWorkload: () => {},
168
+ renderCostView: () => <div>Application cost body</div>,
169
+ costViewSelected: true,
170
+ onSelectCostView: () => {},
171
+ });
172
+
173
+ expect(selectedCost).toContain("Cost");
174
+ expect(selectedCost).toContain("Application cost body");
175
+ expect(selectedCost).not.toContain("Source &amp; provenance");
176
+ });
177
+
151
178
  it("does not render a workload selector for a single-workload app", () => {
152
179
  const singleApp: AppRow = {
153
180
  ...app,
@@ -180,20 +207,112 @@ describe("ApplicationDetail shell", () => {
180
207
  expect(html).not.toContain("Application views");
181
208
  });
182
209
 
183
- it("renders application incidents in History", () => {
210
+ it("renders one filtered application chronology with workload and source actions", () => {
184
211
  const html = renderDetail({
185
212
  selectedView: "history",
186
213
  onSelectView: () => {},
187
214
  selectedWorkloadKey: null,
188
215
  onSelectWorkload: () => {},
216
+ historyMode: 'local',
217
+ historyRange: 'all',
218
+ historyRangeOptions: [{ value: 'all', label: 'All observed' }],
219
+ onOpenTimeline: () => {},
220
+ historyItems: [
221
+ {
222
+ id: 'source-sync',
223
+ category: 'deployment',
224
+ title: 'Argo CD sync',
225
+ timestamp: '2026-07-13T10:00:00.000Z',
226
+ sourceRef: { type: 'gitops', tool: 'argocd', kind: 'Application', namespace: 'argocd', name: 'checkout' },
227
+ },
228
+ {
229
+ id: 'runtime-change',
230
+ category: 'change',
231
+ title: 'Deployment updated',
232
+ timestamp: '2026-07-13T09:00:00.000Z',
233
+ resource: { kind: 'Deployment', namespace: 'prod', name: 'checkout-api' },
234
+ },
235
+ {
236
+ id: 'problem',
237
+ category: 'problem',
238
+ title: 'BackOff',
239
+ timestamp: '2026-07-13T08:00:00.000Z',
240
+ resource: { kind: 'Pod', namespace: 'prod', name: 'checkout-api-abc12' },
241
+ },
242
+ ],
243
+ onOpenSource: () => {},
189
244
  });
190
245
 
191
- expect(html).toContain("Current incidents");
192
- expect(html).toContain("BackOff on Deployment/checkout-api");
193
- expect(html).toContain("Deployment/checkout-api");
194
- expect(html).toContain("Open workload");
246
+ expect(html).toContain("Application history");
247
+ expect(html).toContain("Deployments");
248
+ expect(html).toContain("Changes");
249
+ expect(html).toContain("Problems");
250
+ expect(html).toContain("Open full Timeline");
251
+ expect(html).toContain("Deployment");
252
+ expect(html).toContain("prod");
253
+ expect(html).toContain("checkout-api");
254
+ expect(html).toContain("View Argo CD application");
255
+ expect(html).toContain("events retained by this Radar instance");
256
+ expect(html).not.toContain("Current incidents");
195
257
  });
196
258
 
259
+ it('reports retained event limits separately from recording gaps', () => {
260
+ const html = renderDetail({
261
+ selectedView: 'history',
262
+ onSelectView: () => {},
263
+ selectedWorkloadKey: null,
264
+ onSelectWorkload: () => {},
265
+ historyMode: 'retained',
266
+ historyRange: '7d',
267
+ historyRangeOptions: [{ value: '7d', label: '7 days' }],
268
+ historyRuntimeLimited: true,
269
+ historyItems: [{
270
+ id: 'runtime-change',
271
+ category: 'change',
272
+ title: 'Deployment updated',
273
+ timestamp: '2026-07-13T09:00:00.000Z',
274
+ }],
275
+ })
276
+
277
+ expect(html).toContain('Showing the 10,000 most recent events in these namespaces')
278
+ expect(html).not.toContain('Recording coverage is incomplete')
279
+ })
280
+
281
+ it('shows a single honest error state when runtime history fails without source history', () => {
282
+ const html = renderDetail({
283
+ selectedView: 'history',
284
+ onSelectView: () => {},
285
+ selectedWorkloadKey: null,
286
+ onSelectWorkload: () => {},
287
+ historyRuntimeError: true,
288
+ historyItems: [],
289
+ })
290
+
291
+ expect(html).toContain('Application changes could not be loaded.')
292
+ expect(html).not.toContain('Deployment-source history is still shown.')
293
+ expect(html).not.toContain('No application history in this range.')
294
+ })
295
+
296
+ it('marks retained runtime rows as stale when a refresh fails', () => {
297
+ const html = renderDetail({
298
+ selectedView: 'history',
299
+ onSelectView: () => {},
300
+ selectedWorkloadKey: null,
301
+ onSelectWorkload: () => {},
302
+ historyRuntimeError: true,
303
+ historyItems: [{
304
+ id: 'runtime-change',
305
+ category: 'change',
306
+ title: 'Deployment updated',
307
+ timestamp: '2026-07-13T09:00:00.000Z',
308
+ }],
309
+ })
310
+
311
+ expect(html).toContain('Application changes could not be refreshed.')
312
+ expect(html).toContain('Previously loaded changes may be stale.')
313
+ expect(html).toContain('Deployment updated')
314
+ })
315
+
197
316
  it("previews the latest retained deployment change in Overview", () => {
198
317
  const healthyApp: AppRow = { ...app, events: [] };
199
318
  const history: AppHistory = {
@@ -429,7 +548,7 @@ describe("ApplicationDetail shell", () => {
429
548
  expect(html).not.toContain('needs attention')
430
549
  })
431
550
 
432
- it("does not link ambiguous event objects to a workload", () => {
551
+ it("uses the resource namespace when linking a history item to a workload", () => {
433
552
  const ambiguousApp: AppRow = {
434
553
  ...app,
435
554
  workloads: [
@@ -453,10 +572,19 @@ describe("ApplicationDetail shell", () => {
453
572
  onSelectView: () => {},
454
573
  selectedWorkloadKey: null,
455
574
  onSelectWorkload: () => {},
575
+ historyItems: [{
576
+ id: 'prod-change',
577
+ category: 'change',
578
+ title: 'Deployment updated',
579
+ timestamp: '2026-07-13T09:00:00.000Z',
580
+ resource: { kind: 'Deployment', namespace: 'prod', name: 'checkout-api' },
581
+ }],
456
582
  });
457
583
 
458
- expect(html).toContain("Deployment/checkout-api");
459
- expect(html).not.toContain("Open workload");
584
+ expect(html).toContain("Deployment");
585
+ expect(html).toContain("prod");
586
+ expect(html).toContain("checkout-api");
587
+ expect(html).not.toContain("canary/checkout-api");
460
588
  });
461
589
 
462
590
  it("shows batch activity and injected operational issues on the application overview", () => {