@skyhook-io/k8s-ui 1.13.3 → 1.14.0
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 +4 -4
- package/src/components/applications/AppTooltips.tsx +13 -1
- package/src/components/applications/ApplicationDetail.test.tsx +25 -0
- package/src/components/applications/ApplicationDetail.tsx +39 -7
- package/src/components/applications/ApplicationsView.tsx +18 -3
- package/src/components/applications/ReadyBar.tsx +3 -2
- package/src/components/applications/applications-view.test.tsx +91 -0
- package/src/components/cluster-switcher/ClusterSwitcher.tsx +4 -1
- package/src/components/issues/IssuesView.tsx +40 -31
- package/src/components/issues/ResourceIssuesSection.tsx +3 -2
- package/src/components/issues/index.ts +3 -1
- package/src/components/issues/issue-timing.ts +123 -4
- package/src/components/issues/issues.test.ts +221 -10
- package/src/components/issues/types.ts +31 -5
- package/src/components/namespace-switcher/NamespacePicker.tsx +21 -13
- package/src/components/resources/ResourcesView.tsx +966 -98
- package/src/components/resources/column-settings-key.test.ts +98 -0
- package/src/components/resources/column-visibility-merge.test.ts +64 -0
- package/src/components/resources/curated-column-ownership.test.ts +236 -0
- package/src/components/resources/gateway-policy-status.test.ts +291 -0
- package/src/components/resources/gateway-policy-status.ts +237 -0
- package/src/components/resources/generic-status.test.ts +199 -0
- package/src/components/resources/generic-status.ts +171 -0
- package/src/components/resources/gpu-ecosystem-registry.test.ts +63 -0
- package/src/components/resources/index.ts +9 -1
- package/src/components/resources/istio-gateway-filter.test.ts +97 -0
- package/src/components/resources/kyverno-legacy-action.test.ts +100 -1
- package/src/components/resources/kyverno-modern-posture.test.ts +36 -0
- package/src/components/resources/printer-columns.test.ts +298 -0
- package/src/components/resources/printer-columns.ts +249 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +29 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +3 -2
- package/src/components/resources/renderers/CNPGClusterRenderer.test.tsx +69 -3
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +6 -2
- package/src/components/resources/renderers/EventRenderer.test.tsx +50 -1
- package/src/components/resources/renderers/EventRenderer.tsx +3 -5
- package/src/components/resources/renderers/GenericRenderer.tsx +18 -83
- package/src/components/resources/renderers/HPARenderer.test.tsx +28 -0
- package/src/components/resources/renderers/HPARenderer.tsx +6 -1
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +12 -7
- package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +2 -1
- package/src/components/resources/renderers/PVCRenderer.test.tsx +44 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +19 -2
- package/src/components/resources/renderers/PolicyCoverageSection.test.tsx +92 -1
- package/src/components/resources/renderers/PolicyCoverageSection.tsx +64 -8
- package/src/components/resources/renderers/RolloutRenderer.test.tsx +35 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +22 -3
- package/src/components/resources/renderers/VeleroBSLRenderer.test.tsx +47 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +16 -1
- package/src/components/resources/renderers/VeleroRestoreRenderer.test.tsx +88 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +44 -2
- package/src/components/resources/renderers/WorkloadRenderer.test.tsx +83 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +25 -65
- package/src/components/resources/renderers/amd-gpu-cells.tsx +36 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +12 -1
- package/src/components/resources/renderers/inference-gateway-cells.tsx +62 -0
- package/src/components/resources/renderers/jobset-lws-cells.tsx +82 -0
- package/src/components/resources/renderers/kai-cells.tsx +67 -0
- package/src/components/resources/renderers/kaito-cells.tsx +62 -0
- package/src/components/resources/renderers/kserve-cells.tsx +145 -0
- package/src/components/resources/renderers/kubeflow-training-cells.tsx +72 -0
- package/src/components/resources/renderers/kueue-cells.tsx +176 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +8 -4
- package/src/components/resources/renderers/nim-cells.tsx +81 -0
- package/src/components/resources/renderers/ray-cells.tsx +124 -0
- package/src/components/resources/renderers/volcano-cells.tsx +140 -0
- package/src/components/resources/resource-utils-amd-gpu.ts +61 -0
- package/src/components/resources/resource-utils-cnpg.golden.test.ts +13 -5
- package/src/components/resources/resource-utils-cnpg.test.ts +142 -2
- package/src/components/resources/resource-utils-cnpg.ts +132 -7
- package/src/components/resources/resource-utils-gpu-ecosystem.test.ts +236 -0
- package/src/components/resources/resource-utils-hpa.test.ts +4 -0
- package/src/components/resources/resource-utils-hpa.ts +6 -2
- package/src/components/resources/resource-utils-inference-gateway.ts +119 -0
- package/src/components/resources/resource-utils-jobset-lws.ts +117 -0
- package/src/components/resources/resource-utils-kai.ts +105 -0
- package/src/components/resources/resource-utils-kaito.ts +114 -0
- package/src/components/resources/resource-utils-kserve.ts +186 -0
- package/src/components/resources/resource-utils-kubeflow-training.ts +121 -0
- package/src/components/resources/resource-utils-kueue.ts +200 -0
- package/src/components/resources/resource-utils-kyverno-modern.ts +3 -1
- package/src/components/resources/resource-utils-kyverno.ts +51 -2
- package/src/components/resources/resource-utils-nim.ts +109 -0
- package/src/components/resources/resource-utils-ray.ts +214 -0
- package/src/components/resources/resource-utils-rollout.test.ts +183 -0
- package/src/components/resources/resource-utils-velero.test.ts +30 -0
- package/src/components/resources/resource-utils-velero.ts +32 -0
- package/src/components/resources/resource-utils-volcano.ts +176 -0
- package/src/components/resources/resource-utils.ts +156 -47
- package/src/components/resources/resources-column-filter.test.ts +27 -1
- package/src/components/resources/workload-rollout-golden.test.ts +55 -0
- package/src/components/shared/CreateResourceDialog.tsx +1 -0
- package/src/components/shared/EditableYamlView.tsx +4 -2
- package/src/components/shared/ResourceActionsBar.tsx +170 -25
- package/src/components/shared/ResourceRendererDispatch.test.tsx +206 -1
- package/src/components/shared/ResourceRendererDispatch.tsx +84 -40
- package/src/components/shared/SetImageDialog.test.ts +129 -0
- package/src/components/shared/SetImageDialog.tsx +577 -0
- package/src/components/shared/index.ts +1 -0
- package/src/components/shared/revision-role-badges.test.ts +56 -4
- package/src/components/timeline/TimelineList.tsx +19 -3
- package/src/components/timeline/TimelineSwimlanes.tsx +11 -3
- package/src/components/trace/ReachabilityView.tsx +1 -1
- package/src/components/ui/SelectMenu.tsx +10 -1
- package/src/components/ui/drawer-components.tsx +12 -0
- package/src/components/workload/WorkloadRolloutNotice.tsx +60 -0
- package/src/components/workload/WorkloadView.tsx +144 -81
- package/src/hooks/useProgressiveRefresh.ts +37 -0
- package/src/source-hygiene.test.ts +28 -0
- package/src/theme/tailwind-theme.css +4 -0
- package/src/types/core.ts +55 -0
- package/src/utils/api-resources.test.ts +40 -1
- package/src/utils/api-resources.ts +11 -1
- package/src/utils/applications.ts +50 -0
- package/src/utils/bulk-workload-actions.test.ts +20 -0
- package/src/utils/bulk-workload-actions.ts +15 -0
- package/src/utils/navigation.test.ts +31 -1
- package/src/utils/navigation.ts +21 -2
- package/src/utils/workload-rollout.ts +292 -0
|
@@ -30,7 +30,7 @@ import { isChangeEvent, isHistoricalEvent } from '../../types'
|
|
|
30
30
|
import { getHealthBadgeColor, SEVERITY_BADGE } from '../../utils/badge-colors'
|
|
31
31
|
import { ResourceRefBadge } from '../ui/drawer-components'
|
|
32
32
|
import type { NavigateToResource } from '../../utils/navigation'
|
|
33
|
-
import {
|
|
33
|
+
import { kindToPluralWithGroup, refToSelectedResource, apiVersionToGroup } from '../../utils/navigation'
|
|
34
34
|
import { pluralize } from '../../utils/pluralize'
|
|
35
35
|
|
|
36
36
|
/** Format resource age (e.g., "3d", "5h", "10m") */
|
|
@@ -604,7 +604,15 @@ function ActivityCard({ item, expanded, onToggle, onResourceClick, compact, sele
|
|
|
604
604
|
<button
|
|
605
605
|
onClick={(e) => {
|
|
606
606
|
e.stopPropagation()
|
|
607
|
-
onResourceClick?.({
|
|
607
|
+
onResourceClick?.({
|
|
608
|
+
kind: kindToPluralWithGroup(
|
|
609
|
+
item.kind,
|
|
610
|
+
apiVersionToGroup(item.apiVersion),
|
|
611
|
+
),
|
|
612
|
+
namespace: item.namespace,
|
|
613
|
+
name: item.name,
|
|
614
|
+
group: apiVersionToGroup(item.apiVersion),
|
|
615
|
+
})
|
|
608
616
|
}}
|
|
609
617
|
className="flex items-center gap-2 hover:bg-theme-elevated/50 rounded px-1 -ml-1 transition-colors group"
|
|
610
618
|
>
|
|
@@ -777,7 +785,15 @@ function AggregatedActivityCard({ first, last, count, reason, expanded, onToggle
|
|
|
777
785
|
<button
|
|
778
786
|
onClick={(e) => {
|
|
779
787
|
e.stopPropagation()
|
|
780
|
-
onResourceClick?.({
|
|
788
|
+
onResourceClick?.({
|
|
789
|
+
kind: kindToPluralWithGroup(
|
|
790
|
+
first.kind,
|
|
791
|
+
apiVersionToGroup(first.apiVersion),
|
|
792
|
+
),
|
|
793
|
+
namespace: first.namespace,
|
|
794
|
+
name: first.name,
|
|
795
|
+
group: apiVersionToGroup(first.apiVersion),
|
|
796
|
+
})
|
|
781
797
|
}}
|
|
782
798
|
className="flex items-center gap-2 hover:bg-theme-elevated/50 rounded px-1 -ml-1 transition-colors group"
|
|
783
799
|
>
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from 'lucide-react'
|
|
27
27
|
import type { TimelineEvent, Topology } from '../../types'
|
|
28
28
|
import type { NavigateToResource } from '../../utils/navigation'
|
|
29
|
-
import {
|
|
29
|
+
import { kindToPluralWithGroup, apiVersionToGroup } from '../../utils/navigation'
|
|
30
30
|
import { PaneLoader } from '../ui/PaneLoader'
|
|
31
31
|
import { TimelineToolbar } from './TimelineToolbar'
|
|
32
32
|
import { sortTimelineLanes, TIMELINE_SORT_DEFAULT, type TimelineSort } from './timeline-lane-sort'
|
|
@@ -770,7 +770,7 @@ export function TimelineSwimlanes({ events, isLoading, onResourceClick, viewMode
|
|
|
770
770
|
onNavigatePath(gitOpsPath)
|
|
771
771
|
return
|
|
772
772
|
}
|
|
773
|
-
onResourceClick?.({ kind:
|
|
773
|
+
onResourceClick?.({ kind: kindToPluralWithGroup(kind, group ?? ''), namespace, name, group })
|
|
774
774
|
}, [onNavigatePath, onResourceClick])
|
|
775
775
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
776
776
|
const [zoom, setZoom] = useState(1)
|
|
@@ -3097,7 +3097,15 @@ export function EventDetailPanel({ events, selectedId, onSelectId, onClose, onRe
|
|
|
3097
3097
|
// divider separates "the dot you clicked" from "what happened around it".
|
|
3098
3098
|
const neighborsFrom = events.length === 1 && railEvents.length > 1 ? 1 : -1
|
|
3099
3099
|
const openResource = () =>
|
|
3100
|
-
onResourceClick?.({
|
|
3100
|
+
onResourceClick?.({
|
|
3101
|
+
kind: kindToPluralWithGroup(
|
|
3102
|
+
selected.kind,
|
|
3103
|
+
apiVersionToGroup(selected.apiVersion),
|
|
3104
|
+
),
|
|
3105
|
+
namespace: selected.namespace,
|
|
3106
|
+
name: selected.name,
|
|
3107
|
+
group: apiVersionToGroup(selected.apiVersion),
|
|
3108
|
+
})
|
|
3101
3109
|
|
|
3102
3110
|
return (
|
|
3103
3111
|
<div
|
|
@@ -535,7 +535,7 @@ export function problemRows(
|
|
|
535
535
|
// entry can carry several findings, and one origin several failed routes.
|
|
536
536
|
// `k` is what `seen` just proved unique, so pairing them is what makes the
|
|
537
537
|
// React key safe rather than each caller having to get it right.
|
|
538
|
-
rows.push({ ...r, key: `${r.key}
|
|
538
|
+
rows.push({ ...r, key: `${r.key}\x00${k}` })
|
|
539
539
|
}
|
|
540
540
|
const refNode = (r?: ResourceRef) => (r ? `n:${r.kind}/${r.namespace ?? ''}/${r.name || 'pods'}` : '')
|
|
541
541
|
|
|
@@ -12,15 +12,21 @@ export function SelectMenu({
|
|
|
12
12
|
options,
|
|
13
13
|
onChange,
|
|
14
14
|
ariaLabel,
|
|
15
|
+
ariaDescribedBy,
|
|
15
16
|
className,
|
|
16
17
|
searchPlaceholder,
|
|
18
|
+
disabled = false,
|
|
19
|
+
id,
|
|
17
20
|
}: {
|
|
18
21
|
value: string
|
|
19
22
|
options: SelectMenuOption[]
|
|
20
23
|
onChange: (value: string) => void
|
|
21
24
|
ariaLabel: string
|
|
25
|
+
ariaDescribedBy?: string
|
|
22
26
|
className?: string
|
|
23
27
|
searchPlaceholder?: string
|
|
28
|
+
disabled?: boolean
|
|
29
|
+
id?: string
|
|
24
30
|
}) {
|
|
25
31
|
const [open, setOpen] = useState(false)
|
|
26
32
|
const [query, setQuery] = useState('')
|
|
@@ -109,8 +115,10 @@ export function SelectMenu({
|
|
|
109
115
|
>
|
|
110
116
|
<button
|
|
111
117
|
ref={triggerRef}
|
|
118
|
+
id={id}
|
|
112
119
|
type="button"
|
|
113
120
|
aria-label={ariaLabel}
|
|
121
|
+
aria-describedby={ariaDescribedBy}
|
|
114
122
|
aria-haspopup="listbox"
|
|
115
123
|
aria-expanded={open}
|
|
116
124
|
aria-controls={open ? listboxId : undefined}
|
|
@@ -125,7 +133,8 @@ export function SelectMenu({
|
|
|
125
133
|
}
|
|
126
134
|
setOpen(!open)
|
|
127
135
|
}}
|
|
128
|
-
|
|
136
|
+
disabled={disabled}
|
|
137
|
+
className="flex h-8 w-full items-center justify-between gap-2 rounded-md border border-theme-border bg-theme-elevated px-2.5 text-xs text-theme-text-primary transition-colors hover:bg-theme-hover disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-theme-elevated"
|
|
129
138
|
>
|
|
130
139
|
<span className="truncate">{selected?.label}</span>
|
|
131
140
|
<ChevronDown className={clsx('h-3.5 w-3.5 shrink-0 text-theme-text-tertiary transition-transform', open && 'rotate-180')} />
|
|
@@ -733,6 +733,18 @@ export function formatKindName(kind: string): string {
|
|
|
733
733
|
resourceclaims: 'ResourceClaim', resourceclaimtemplates: 'ResourceClaimTemplate',
|
|
734
734
|
deviceclasses: 'DeviceClass', resourceslices: 'ResourceSlice',
|
|
735
735
|
clusterpolicies: 'ClusterPolicy', nvidiadrivers: 'NVIDIADriver',
|
|
736
|
+
clusterqueues: 'ClusterQueue', localqueues: 'LocalQueue', resourceflavors: 'ResourceFlavor',
|
|
737
|
+
admissionchecks: 'AdmissionCheck', provisioningrequests: 'ProvisioningRequest',
|
|
738
|
+
rayclusters: 'RayCluster', rayjobs: 'RayJob', rayservices: 'RayService', raycronjobs: 'RayCronJob',
|
|
739
|
+
leaderworkersets: 'LeaderWorkerSet', jobsets: 'JobSet',
|
|
740
|
+
inferenceservices: 'InferenceService', servingruntimes: 'ServingRuntime',
|
|
741
|
+
clusterservingruntimes: 'ClusterServingRuntime', inferencegraphs: 'InferenceGraph',
|
|
742
|
+
trainedmodels: 'TrainedModel', llminferenceservices: 'LLMInferenceService',
|
|
743
|
+
inferencepools: 'InferencePool', inferenceobjectives: 'InferenceObjective',
|
|
744
|
+
jobflows: 'JobFlow', jobtemplates: 'JobTemplate', ragengines: 'RAGEngine',
|
|
745
|
+
nimservices: 'NIMService', nimcaches: 'NIMCache', nimpipelines: 'NIMPipeline',
|
|
746
|
+
deviceconfigs: 'DeviceConfig',
|
|
747
|
+
pytorchjobs: 'PyTorchJob', tfjobs: 'TFJob', mpijobs: 'MPIJob', trainjobs: 'TrainJob',
|
|
736
748
|
}
|
|
737
749
|
if (names[k]) return names[k]
|
|
738
750
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { AlertTriangle, Check, Clock3, Loader2, Pause } from 'lucide-react'
|
|
2
|
+
import { Badge, type BadgeSeverity } from '../ui/Badge'
|
|
3
|
+
import type { WorkloadRolloutActivity } from '../../utils/workload-rollout'
|
|
4
|
+
|
|
5
|
+
export function WorkloadRolloutNotice({
|
|
6
|
+
activity,
|
|
7
|
+
recentImageSave = false,
|
|
8
|
+
className = '',
|
|
9
|
+
}: {
|
|
10
|
+
activity: WorkloadRolloutActivity
|
|
11
|
+
recentImageSave?: boolean
|
|
12
|
+
className?: string
|
|
13
|
+
}) {
|
|
14
|
+
if (activity.phase === 'idle' && !recentImageSave) return null
|
|
15
|
+
const shown = activity.phase === 'idle' && recentImageSave
|
|
16
|
+
? { ...activity, phase: 'applying' as const, active: true, label: 'Waiting for controller', detail: 'The template change was accepted; waiting for live rollout status' }
|
|
17
|
+
: activity
|
|
18
|
+
const severity: BadgeSeverity = shown.phase === 'stalled'
|
|
19
|
+
? 'error'
|
|
20
|
+
: shown.phase === 'paused' || shown.manual
|
|
21
|
+
? 'warning'
|
|
22
|
+
: 'info'
|
|
23
|
+
const Icon = shown.phase === 'stalled'
|
|
24
|
+
? AlertTriangle
|
|
25
|
+
: shown.phase === 'paused'
|
|
26
|
+
? Pause
|
|
27
|
+
: shown.phase === 'waiting'
|
|
28
|
+
? Clock3
|
|
29
|
+
: Loader2
|
|
30
|
+
const warning = shown.phase === 'paused' || shown.manual
|
|
31
|
+
const containerTone = shown.phase === 'stalled'
|
|
32
|
+
? 'border-semantic-error/30 bg-semantic-error/5'
|
|
33
|
+
: warning
|
|
34
|
+
? 'border-semantic-warning/30 bg-semantic-warning/5'
|
|
35
|
+
: 'border-theme-border bg-accent-muted'
|
|
36
|
+
const iconTone = shown.phase === 'stalled'
|
|
37
|
+
? 'text-semantic-error'
|
|
38
|
+
: warning
|
|
39
|
+
? 'text-semantic-warning'
|
|
40
|
+
: 'text-accent-text'
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={`rounded-lg border px-3 py-2.5 shadow-theme-sm ${containerTone} ${className}`} role={shown.phase === 'stalled' ? 'alert' : 'status'}>
|
|
44
|
+
<div className="flex min-w-0 items-start gap-2.5">
|
|
45
|
+
<Icon className={`mt-0.5 h-4 w-4 shrink-0 ${iconTone} ${shown.active && (shown.phase === 'applying' || shown.phase === 'progressing') ? 'animate-spin' : ''}`} />
|
|
46
|
+
<div className="min-w-0 flex-1">
|
|
47
|
+
<div className="flex min-w-0 flex-wrap items-center gap-1.5">
|
|
48
|
+
{recentImageSave && (
|
|
49
|
+
<span className="inline-flex items-center gap-1 text-xs font-medium text-theme-text-secondary">
|
|
50
|
+
<Check className="h-3.5 w-3.5" /> Image saved <span aria-hidden>·</span>
|
|
51
|
+
</span>
|
|
52
|
+
)}
|
|
53
|
+
<Badge severity={severity}>{shown.label}</Badge>
|
|
54
|
+
</div>
|
|
55
|
+
{shown.detail && <div className="mt-1 text-xs leading-5 text-theme-text-secondary">{shown.detail}</div>}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|