@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.
- package/package.json +5 -4
- package/src/assets/gitops/argocd.png +0 -0
- package/src/assets/gitops/flux.svg +7 -0
- package/src/components/applications/AppChips.tsx +10 -0
- package/src/components/applications/ApplicationDetail.test.tsx +569 -0
- package/src/components/applications/ApplicationDetail.tsx +2517 -450
- package/src/components/applications/ApplicationsView.tsx +62 -10
- package/src/components/applications/applications-view.test.tsx +47 -0
- package/src/components/applications/index.ts +1 -1
- package/src/components/audit/AuditAlerts.tsx +14 -10
- package/src/components/checks/ChecksView.tsx +2 -3
- package/src/components/checks/severity.ts +14 -10
- package/src/components/cluster-switcher/ClusterSwitcher.tsx +2 -2
- package/src/components/compare/CompareResourcePicker.tsx +2 -2
- package/src/components/gitops/GitOpsGraphFilterRail.tsx +2 -1
- package/src/components/gitops/GitOpsTableView.tsx +3 -3
- package/src/components/gitops/ManagedResourcesList.tsx +8 -11
- package/src/components/gitops/SyncCountdown.tsx +26 -17
- package/src/components/gitops/SyncOptionsDialog.tsx +2 -2
- package/src/components/gitops/insights/GitOpsInsightViews.tsx +277 -104
- package/src/components/gitops/insights/insights-helpers.test.ts +86 -1
- package/src/components/gitops/insights/insights-helpers.ts +69 -1
- package/src/components/gitops/tree/GitOpsTreeGraph.tsx +5 -2
- package/src/components/issues/IssuesView.tsx +51 -38
- package/src/components/issues/ResourceIssuesSection.test.tsx +6 -5
- package/src/components/issues/ResourceIssuesSection.tsx +28 -146
- package/src/components/issues/index.ts +3 -0
- package/src/components/issues/issue-timing.ts +53 -0
- package/src/components/issues/issues.test.ts +102 -1
- package/src/components/issues/severity.ts +2 -0
- package/src/components/logs/LogCore.tsx +14 -4
- package/src/components/logs/WorkloadLogsViewer.tsx +31 -6
- package/src/components/logs/useLogStream.ts +8 -1
- package/src/components/namespace-switcher/NamespacePicker.tsx +86 -107
- package/src/components/resources/ResourcesSidebar.test.tsx +71 -0
- package/src/components/resources/ResourcesSidebar.tsx +46 -46
- package/src/components/resources/ResourcesView.selected-kind.test.ts +143 -0
- package/src/components/resources/ResourcesView.tsx +233 -51
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/CronWorkflowRenderer.tsx +99 -0
- package/src/components/resources/renderers/JobRenderer.tsx +3 -1
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +2 -2
- package/src/components/resources/renderers/SbomReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/SecretRenderer.tsx +2 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +58 -40
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +2 -2
- package/src/components/resources/renderers/WorkflowRenderer.test.tsx +43 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +60 -78
- package/src/components/resources/renderers/index.ts +1 -0
- package/src/components/resources/resource-utils-capi.ts +1 -1
- package/src/components/resources/resource-utils.ts +31 -0
- package/src/components/shared/DetailShell.tsx +2 -2
- package/src/components/shared/ResourceActionsBar.tsx +140 -108
- package/src/components/shared/ResourceRendererDispatch.tsx +33 -4
- package/src/components/timeline/TimelineList.tsx +371 -354
- package/src/components/timeline/TimelineStrip.test.tsx +194 -0
- package/src/components/timeline/TimelineStrip.tsx +836 -0
- package/src/components/timeline/TimelineSwimlanes.test.tsx +1028 -0
- package/src/components/timeline/TimelineSwimlanes.tsx +2498 -593
- package/src/components/timeline/TimelineToolbar.test.tsx +320 -0
- package/src/components/timeline/TimelineToolbar.tsx +759 -0
- package/src/components/timeline/TimelineToolbarState.test.tsx +64 -0
- package/src/components/timeline/index.ts +23 -0
- package/src/components/timeline/scrubber-math.test.ts +235 -0
- package/src/components/timeline/scrubber-math.ts +249 -0
- package/src/components/timeline/shared.test.tsx +219 -0
- package/src/components/timeline/shared.tsx +232 -447
- package/src/components/timeline/timeline-filters.test.ts +196 -0
- package/src/components/timeline/timeline-filters.ts +180 -0
- package/src/components/timeline/timeline-lane-sort.test.ts +97 -0
- package/src/components/timeline/timeline-lane-sort.ts +77 -0
- package/src/components/timeline/timeline-live.test.ts +131 -0
- package/src/components/timeline/timeline-live.ts +77 -0
- package/src/components/topology/GroupNode.tsx +9 -2
- package/src/components/topology/K8sResourceNode.test.ts +11 -0
- package/src/components/topology/K8sResourceNode.tsx +387 -243
- package/src/components/topology/TopologyFilterSidebar.tsx +9 -0
- package/src/components/topology/TopologyGraph.tsx +89 -16
- package/src/components/topology/TopologySearch.tsx +2 -2
- package/src/components/topology/layout.ts +10 -2
- package/src/components/topology/topology.css +0 -92
- package/src/components/ui/Badge.tsx +5 -0
- package/src/components/ui/CodeViewer.tsx +2 -2
- package/src/components/ui/Collapse.tsx +59 -0
- package/src/components/ui/ConfirmDialog.tsx +7 -3
- package/src/components/ui/DialogPortal.tsx +31 -9
- package/src/components/ui/Input.tsx +24 -0
- package/src/components/ui/MultiSelectPicker.test.tsx +101 -0
- package/src/components/ui/MultiSelectPicker.tsx +167 -0
- package/src/components/ui/PaneLoader.tsx +10 -2
- package/src/components/ui/ResourceBar.tsx +68 -25
- package/src/components/ui/SearchBox.tsx +18 -4
- package/src/components/ui/SearchPillInput.tsx +2 -2
- package/src/components/ui/drawer-components.tsx +39 -26
- package/src/components/ui/index.ts +4 -0
- package/src/components/ui/severity-tone.ts +11 -4
- package/src/components/workload/ResourceDetailDrawer.tsx +6 -2
- package/src/components/workload/WorkloadView.tsx +2682 -472
- package/src/components/workload/index.ts +1 -1
- package/src/theme/variables.css +1 -1
- package/src/types/core.ts +57 -4
- package/src/utils/application-topology.test.ts +198 -0
- package/src/utils/application-topology.ts +261 -0
- package/src/utils/applications.test.ts +167 -1
- package/src/utils/applications.ts +1157 -393
- package/src/utils/index.ts +2 -0
- package/src/utils/navigation.test.ts +32 -1
- package/src/utils/navigation.ts +70 -0
- package/src/utils/resource-hierarchy.test.ts +990 -1
- package/src/utils/resource-hierarchy.ts +905 -267
- package/src/utils/resource-icons.ts +2 -0
- package/src/utils/topology-neighborhood.test.ts +202 -1
- package/src/utils/topology-neighborhood.ts +194 -13
- package/src/utils/workflow-execution.test.ts +556 -0
- package/src/utils/workflow-execution.ts +814 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
+
})
|