@skyhook-io/k8s-ui 1.8.10 → 1.8.11

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 (116) hide show
  1. package/package.json +5 -4
  2. package/src/assets/gitops/argocd.png +0 -0
  3. package/src/assets/gitops/flux.svg +7 -0
  4. package/src/components/applications/AppChips.tsx +10 -0
  5. package/src/components/applications/ApplicationDetail.test.tsx +569 -0
  6. package/src/components/applications/ApplicationDetail.tsx +2517 -450
  7. package/src/components/applications/ApplicationsView.tsx +62 -10
  8. package/src/components/applications/applications-view.test.tsx +47 -0
  9. package/src/components/applications/index.ts +1 -1
  10. package/src/components/audit/AuditAlerts.tsx +14 -10
  11. package/src/components/checks/ChecksView.tsx +2 -3
  12. package/src/components/checks/severity.ts +14 -10
  13. package/src/components/cluster-switcher/ClusterSwitcher.tsx +2 -2
  14. package/src/components/compare/CompareResourcePicker.tsx +2 -2
  15. package/src/components/gitops/GitOpsGraphFilterRail.tsx +2 -1
  16. package/src/components/gitops/GitOpsTableView.tsx +3 -3
  17. package/src/components/gitops/ManagedResourcesList.tsx +8 -11
  18. package/src/components/gitops/SyncCountdown.tsx +26 -17
  19. package/src/components/gitops/SyncOptionsDialog.tsx +2 -2
  20. package/src/components/gitops/insights/GitOpsInsightViews.tsx +277 -104
  21. package/src/components/gitops/insights/insights-helpers.test.ts +86 -1
  22. package/src/components/gitops/insights/insights-helpers.ts +69 -1
  23. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +5 -2
  24. package/src/components/issues/IssuesView.tsx +51 -38
  25. package/src/components/issues/ResourceIssuesSection.test.tsx +6 -5
  26. package/src/components/issues/ResourceIssuesSection.tsx +28 -146
  27. package/src/components/issues/index.ts +3 -0
  28. package/src/components/issues/issue-timing.ts +53 -0
  29. package/src/components/issues/issues.test.ts +102 -1
  30. package/src/components/issues/severity.ts +2 -0
  31. package/src/components/logs/LogCore.tsx +14 -4
  32. package/src/components/logs/WorkloadLogsViewer.tsx +31 -6
  33. package/src/components/logs/useLogStream.ts +8 -1
  34. package/src/components/namespace-switcher/NamespacePicker.tsx +86 -107
  35. package/src/components/resources/ResourcesSidebar.test.tsx +71 -0
  36. package/src/components/resources/ResourcesSidebar.tsx +46 -46
  37. package/src/components/resources/ResourcesView.selected-kind.test.ts +143 -0
  38. package/src/components/resources/ResourcesView.tsx +233 -51
  39. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +2 -2
  40. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +99 -0
  41. package/src/components/resources/renderers/JobRenderer.tsx +3 -1
  42. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +2 -2
  43. package/src/components/resources/renderers/SbomReportRenderer.tsx +2 -2
  44. package/src/components/resources/renderers/SecretRenderer.tsx +2 -0
  45. package/src/components/resources/renderers/ServiceRenderer.tsx +58 -40
  46. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +2 -2
  47. package/src/components/resources/renderers/WorkflowRenderer.test.tsx +43 -0
  48. package/src/components/resources/renderers/WorkflowRenderer.tsx +60 -78
  49. package/src/components/resources/renderers/index.ts +1 -0
  50. package/src/components/resources/resource-utils-capi.ts +1 -1
  51. package/src/components/resources/resource-utils.ts +31 -0
  52. package/src/components/shared/DetailShell.tsx +2 -2
  53. package/src/components/shared/ResourceActionsBar.tsx +140 -108
  54. package/src/components/shared/ResourceRendererDispatch.tsx +33 -4
  55. package/src/components/timeline/TimelineList.tsx +371 -354
  56. package/src/components/timeline/TimelineStrip.test.tsx +194 -0
  57. package/src/components/timeline/TimelineStrip.tsx +836 -0
  58. package/src/components/timeline/TimelineSwimlanes.test.tsx +1028 -0
  59. package/src/components/timeline/TimelineSwimlanes.tsx +2498 -593
  60. package/src/components/timeline/TimelineToolbar.test.tsx +320 -0
  61. package/src/components/timeline/TimelineToolbar.tsx +759 -0
  62. package/src/components/timeline/TimelineToolbarState.test.tsx +64 -0
  63. package/src/components/timeline/index.ts +23 -0
  64. package/src/components/timeline/scrubber-math.test.ts +235 -0
  65. package/src/components/timeline/scrubber-math.ts +249 -0
  66. package/src/components/timeline/shared.test.tsx +219 -0
  67. package/src/components/timeline/shared.tsx +232 -447
  68. package/src/components/timeline/timeline-filters.test.ts +196 -0
  69. package/src/components/timeline/timeline-filters.ts +180 -0
  70. package/src/components/timeline/timeline-lane-sort.test.ts +97 -0
  71. package/src/components/timeline/timeline-lane-sort.ts +77 -0
  72. package/src/components/timeline/timeline-live.test.ts +131 -0
  73. package/src/components/timeline/timeline-live.ts +77 -0
  74. package/src/components/topology/GroupNode.tsx +9 -2
  75. package/src/components/topology/K8sResourceNode.test.ts +11 -0
  76. package/src/components/topology/K8sResourceNode.tsx +387 -243
  77. package/src/components/topology/TopologyFilterSidebar.tsx +9 -0
  78. package/src/components/topology/TopologyGraph.tsx +89 -16
  79. package/src/components/topology/TopologySearch.tsx +2 -2
  80. package/src/components/topology/layout.ts +10 -2
  81. package/src/components/topology/topology.css +0 -92
  82. package/src/components/ui/Badge.tsx +5 -0
  83. package/src/components/ui/CodeViewer.tsx +2 -2
  84. package/src/components/ui/Collapse.tsx +59 -0
  85. package/src/components/ui/ConfirmDialog.tsx +7 -3
  86. package/src/components/ui/DialogPortal.tsx +31 -9
  87. package/src/components/ui/Input.tsx +24 -0
  88. package/src/components/ui/MultiSelectPicker.test.tsx +101 -0
  89. package/src/components/ui/MultiSelectPicker.tsx +167 -0
  90. package/src/components/ui/PaneLoader.tsx +10 -2
  91. package/src/components/ui/ResourceBar.tsx +68 -25
  92. package/src/components/ui/SearchBox.tsx +18 -4
  93. package/src/components/ui/SearchPillInput.tsx +2 -2
  94. package/src/components/ui/drawer-components.tsx +39 -26
  95. package/src/components/ui/index.ts +4 -0
  96. package/src/components/ui/severity-tone.ts +11 -4
  97. package/src/components/workload/ResourceDetailDrawer.tsx +6 -2
  98. package/src/components/workload/WorkloadView.tsx +2682 -472
  99. package/src/components/workload/index.ts +1 -1
  100. package/src/theme/variables.css +1 -1
  101. package/src/types/core.ts +57 -4
  102. package/src/utils/application-topology.test.ts +198 -0
  103. package/src/utils/application-topology.ts +261 -0
  104. package/src/utils/applications.test.ts +167 -1
  105. package/src/utils/applications.ts +1157 -393
  106. package/src/utils/index.ts +2 -0
  107. package/src/utils/navigation.test.ts +32 -1
  108. package/src/utils/navigation.ts +70 -0
  109. package/src/utils/resource-hierarchy.test.ts +990 -1
  110. package/src/utils/resource-hierarchy.ts +905 -267
  111. package/src/utils/resource-icons.ts +2 -0
  112. package/src/utils/topology-neighborhood.test.ts +202 -1
  113. package/src/utils/topology-neighborhood.ts +194 -13
  114. package/src/utils/workflow-execution.test.ts +556 -0
  115. package/src/utils/workflow-execution.ts +814 -0
  116. package/src/utils/workload-colors.ts +2 -3
@@ -0,0 +1,77 @@
1
+ // Live/paused (relative/absolute) selection model for the retained timeline.
2
+ //
3
+ // Pure helpers so the host (radar/web TimelineView) can derive the concrete
4
+ // selection each render, quantize the fetch window, and keep a latched lens
5
+ // tracking the live edge — all unit-testable without a DOM.
6
+
7
+ import type { ScrubberRange } from './scrubber-math'
8
+
9
+ // Live/paused indicator model for the retained timeline, surfaced as one chip in
10
+ // the scrubber header. LIVE = the selection tracks now; `latched` is whether the
11
+ // lens still rides the live edge (false once the user drags the lens into the
12
+ // past — the chip then offers a jump-to-now). FROZEN = an explicit range is
13
+ // pinned (`asOfMs` = freeze time, stamped when the selection freezes).
14
+ export type TimelineLiveState =
15
+ | { kind: 'live'; latched: boolean }
16
+ // `newEventCount` (optional) = approximate events recorded after the frozen
17
+ // edge, shown on the "Go live" CTA as a pull toward the fresh data.
18
+ | { kind: 'frozen'; asOfMs: number; newEventCount?: number }
19
+
20
+ // Cadence the host slides a live selection at. Coarse on purpose: the precise
21
+ // [from,to] is re-derived every tick, but the base fetch is quantized so the
22
+ // query key only churns every QUANTIZE step (see quantizeBaseWindow).
23
+ export const LIVE_TICK_MS = 30_000
24
+
25
+ // A frozen selection older than this reads as stale — the chip turns amber.
26
+ export const STALE_AMBER_AFTER_MS = 15 * 60_000
27
+
28
+ // The lens counts as "latched to the live edge" when its right edge is within
29
+ // one comfortable tick-plus-margin of the selection's right edge. Wider than
30
+ // LIVE_TICK_MS so a lens that just slid with the tick still reads as latched.
31
+ export const LENS_LATCH_EPSILON_MS = 60_000
32
+
33
+ // Base-fetch quantization step. The react-query key is keyed on the quantized
34
+ // window, so it only changes when the live edge crosses a 5-minute boundary —
35
+ // the seam between the quantized edge and now is covered by the 10-minute live
36
+ // poll (5min quantization lag < 10min poll window ⇒ no hole).
37
+ export const BASE_QUANTIZE_STEP_MS = 5 * 60_000
38
+
39
+ /** LIVE selection: a width pinned to now. */
40
+ export function deriveLiveSelection(widthMs: number, nowMs: number): ScrubberRange {
41
+ return { fromMs: nowMs - widthMs, toMs: nowMs }
42
+ }
43
+
44
+ /**
45
+ * Quantize a sliding [from,to] down to fixed steps so the value is stable across
46
+ * ticks within one step (identical output ⇒ stable react-query key). Both edges
47
+ * floor to the step; the trailing seam to `now` is filled by the live poll.
48
+ */
49
+ export function quantizeBaseWindow(
50
+ fromMs: number,
51
+ toMs: number,
52
+ stepMs: number = BASE_QUANTIZE_STEP_MS,
53
+ ): ScrubberRange {
54
+ return {
55
+ fromMs: Math.floor(fromMs / stepMs) * stepMs,
56
+ toMs: Math.floor(toMs / stepMs) * stepMs,
57
+ }
58
+ }
59
+
60
+ /**
61
+ * True when the lens rides the selection's live edge (so it should slide with
62
+ * the tick). A lens the user dragged into the past sits further than epsilon
63
+ * behind and stays put.
64
+ */
65
+ export function isLensLatched(
66
+ lens: ScrubberRange,
67
+ selection: ScrubberRange,
68
+ epsilonMs: number = LENS_LATCH_EPSILON_MS,
69
+ ): boolean {
70
+ return Math.abs(lens.toMs - selection.toMs) <= epsilonMs
71
+ }
72
+
73
+ /** Slide a latched lens to the new selection's right edge, preserving its width. */
74
+ export function advanceLatchedLens(lens: ScrubberRange, newSelection: ScrubberRange): ScrubberRange {
75
+ const width = lens.toMs - lens.fromMs
76
+ return { fromMs: newSelection.toMs - width, toMs: newSelection.toMs }
77
+ }
@@ -6,6 +6,7 @@ import type { HealthStatus } from '../../types'
6
6
  import { Tooltip } from '../ui/Tooltip'
7
7
  import type { WorkloadCard, GroupDisplayLevel } from './layout'
8
8
  import { pluralize } from '../../utils/pluralize'
9
+ import { getTopologyIcon } from '../../utils/resource-icons'
9
10
 
10
11
  interface GroupNodeData {
11
12
  type: 'namespace' | 'app' | 'label'
@@ -195,7 +196,10 @@ export const GroupNode = memo(function GroupNode({
195
196
  <div className="flex flex-wrap gap-1 mt-1.5">
196
197
  {kindPills.map(([kind, count]) => (
197
198
  <div key={kind} className="flex items-center gap-1 bg-theme-surface/50 rounded px-1.5 py-0.5">
198
- <span className={`topology-icon topology-icon-${kind.toLowerCase()}`} style={{ width: 10, height: 10, fontSize: 6, borderRadius: 2 }} />
199
+ {(() => {
200
+ const KindIcon = getTopologyIcon(kind)
201
+ return <KindIcon className="h-2.5 w-2.5 shrink-0 text-theme-text-tertiary" aria-hidden />
202
+ })()}
199
203
  <span className="text-[10px] text-theme-text-secondary">{pluralize(count, kind)}</span>
200
204
  </div>
201
205
  ))}
@@ -254,7 +258,10 @@ export const GroupNode = memo(function GroupNode({
254
258
  onClick={(e) => { e.stopPropagation(); onCardClick?.(card.id) }}
255
259
  >
256
260
  <div className="grid-card-header">
257
- <span className={`topology-icon topology-icon-${card.kind.toLowerCase()}`} />
261
+ {(() => {
262
+ const KindIcon = getTopologyIcon(card.kind)
263
+ return <KindIcon className="h-3.5 w-3.5 shrink-0 text-theme-text-tertiary" aria-hidden />
264
+ })()}
258
265
  <span className="grid-card-kind">{card.kind}</span>
259
266
  <span className="grid-card-count">{card.resourceCount}</span>
260
267
  </div>
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { baseSubtitle } from './K8sResourceNode'
3
+
4
+ describe('baseSubtitle', () => {
5
+ it('describes workflow templates without dropping newer topology kinds', () => {
6
+ expect(baseSubtitle('WorkflowTemplate', { entrypoint: 'main', templateCount: 3 })).toBe('main • 3 templates')
7
+ expect(baseSubtitle('ClusterWorkflowTemplate', { templateCount: 2 })).toBe('2 templates')
8
+ expect(baseSubtitle('ServiceAccount', {})).toBe('Workload identity')
9
+ expect(baseSubtitle('ServiceMonitor', { endpointCount: 1 })).toBe('1 scrape endpoint')
10
+ })
11
+ })