@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.
Files changed (119) hide show
  1. package/package.json +4 -4
  2. package/src/components/applications/AppTooltips.tsx +13 -1
  3. package/src/components/applications/ApplicationDetail.test.tsx +25 -0
  4. package/src/components/applications/ApplicationDetail.tsx +39 -7
  5. package/src/components/applications/ApplicationsView.tsx +18 -3
  6. package/src/components/applications/ReadyBar.tsx +3 -2
  7. package/src/components/applications/applications-view.test.tsx +91 -0
  8. package/src/components/cluster-switcher/ClusterSwitcher.tsx +4 -1
  9. package/src/components/issues/IssuesView.tsx +40 -31
  10. package/src/components/issues/ResourceIssuesSection.tsx +3 -2
  11. package/src/components/issues/index.ts +3 -1
  12. package/src/components/issues/issue-timing.ts +123 -4
  13. package/src/components/issues/issues.test.ts +221 -10
  14. package/src/components/issues/types.ts +31 -5
  15. package/src/components/namespace-switcher/NamespacePicker.tsx +21 -13
  16. package/src/components/resources/ResourcesView.tsx +966 -98
  17. package/src/components/resources/column-settings-key.test.ts +98 -0
  18. package/src/components/resources/column-visibility-merge.test.ts +64 -0
  19. package/src/components/resources/curated-column-ownership.test.ts +236 -0
  20. package/src/components/resources/gateway-policy-status.test.ts +291 -0
  21. package/src/components/resources/gateway-policy-status.ts +237 -0
  22. package/src/components/resources/generic-status.test.ts +199 -0
  23. package/src/components/resources/generic-status.ts +171 -0
  24. package/src/components/resources/gpu-ecosystem-registry.test.ts +63 -0
  25. package/src/components/resources/index.ts +9 -1
  26. package/src/components/resources/istio-gateway-filter.test.ts +97 -0
  27. package/src/components/resources/kyverno-legacy-action.test.ts +100 -1
  28. package/src/components/resources/kyverno-modern-posture.test.ts +36 -0
  29. package/src/components/resources/printer-columns.test.ts +298 -0
  30. package/src/components/resources/printer-columns.ts +249 -0
  31. package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +29 -0
  32. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +3 -2
  33. package/src/components/resources/renderers/CNPGClusterRenderer.test.tsx +69 -3
  34. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +6 -2
  35. package/src/components/resources/renderers/EventRenderer.test.tsx +50 -1
  36. package/src/components/resources/renderers/EventRenderer.tsx +3 -5
  37. package/src/components/resources/renderers/GenericRenderer.tsx +18 -83
  38. package/src/components/resources/renderers/HPARenderer.test.tsx +28 -0
  39. package/src/components/resources/renderers/HPARenderer.tsx +6 -1
  40. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +12 -7
  41. package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +2 -1
  42. package/src/components/resources/renderers/PVCRenderer.test.tsx +44 -0
  43. package/src/components/resources/renderers/PVCRenderer.tsx +19 -2
  44. package/src/components/resources/renderers/PolicyCoverageSection.test.tsx +92 -1
  45. package/src/components/resources/renderers/PolicyCoverageSection.tsx +64 -8
  46. package/src/components/resources/renderers/RolloutRenderer.test.tsx +35 -0
  47. package/src/components/resources/renderers/RolloutRenderer.tsx +22 -3
  48. package/src/components/resources/renderers/VeleroBSLRenderer.test.tsx +47 -0
  49. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +16 -1
  50. package/src/components/resources/renderers/VeleroRestoreRenderer.test.tsx +88 -0
  51. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +44 -2
  52. package/src/components/resources/renderers/WorkloadRenderer.test.tsx +83 -0
  53. package/src/components/resources/renderers/WorkloadRenderer.tsx +25 -65
  54. package/src/components/resources/renderers/amd-gpu-cells.tsx +36 -0
  55. package/src/components/resources/renderers/cnpg-cells.tsx +12 -1
  56. package/src/components/resources/renderers/inference-gateway-cells.tsx +62 -0
  57. package/src/components/resources/renderers/jobset-lws-cells.tsx +82 -0
  58. package/src/components/resources/renderers/kai-cells.tsx +67 -0
  59. package/src/components/resources/renderers/kaito-cells.tsx +62 -0
  60. package/src/components/resources/renderers/kserve-cells.tsx +145 -0
  61. package/src/components/resources/renderers/kubeflow-training-cells.tsx +72 -0
  62. package/src/components/resources/renderers/kueue-cells.tsx +176 -0
  63. package/src/components/resources/renderers/kyverno-cells.tsx +8 -4
  64. package/src/components/resources/renderers/nim-cells.tsx +81 -0
  65. package/src/components/resources/renderers/ray-cells.tsx +124 -0
  66. package/src/components/resources/renderers/volcano-cells.tsx +140 -0
  67. package/src/components/resources/resource-utils-amd-gpu.ts +61 -0
  68. package/src/components/resources/resource-utils-cnpg.golden.test.ts +13 -5
  69. package/src/components/resources/resource-utils-cnpg.test.ts +142 -2
  70. package/src/components/resources/resource-utils-cnpg.ts +132 -7
  71. package/src/components/resources/resource-utils-gpu-ecosystem.test.ts +236 -0
  72. package/src/components/resources/resource-utils-hpa.test.ts +4 -0
  73. package/src/components/resources/resource-utils-hpa.ts +6 -2
  74. package/src/components/resources/resource-utils-inference-gateway.ts +119 -0
  75. package/src/components/resources/resource-utils-jobset-lws.ts +117 -0
  76. package/src/components/resources/resource-utils-kai.ts +105 -0
  77. package/src/components/resources/resource-utils-kaito.ts +114 -0
  78. package/src/components/resources/resource-utils-kserve.ts +186 -0
  79. package/src/components/resources/resource-utils-kubeflow-training.ts +121 -0
  80. package/src/components/resources/resource-utils-kueue.ts +200 -0
  81. package/src/components/resources/resource-utils-kyverno-modern.ts +3 -1
  82. package/src/components/resources/resource-utils-kyverno.ts +51 -2
  83. package/src/components/resources/resource-utils-nim.ts +109 -0
  84. package/src/components/resources/resource-utils-ray.ts +214 -0
  85. package/src/components/resources/resource-utils-rollout.test.ts +183 -0
  86. package/src/components/resources/resource-utils-velero.test.ts +30 -0
  87. package/src/components/resources/resource-utils-velero.ts +32 -0
  88. package/src/components/resources/resource-utils-volcano.ts +176 -0
  89. package/src/components/resources/resource-utils.ts +156 -47
  90. package/src/components/resources/resources-column-filter.test.ts +27 -1
  91. package/src/components/resources/workload-rollout-golden.test.ts +55 -0
  92. package/src/components/shared/CreateResourceDialog.tsx +1 -0
  93. package/src/components/shared/EditableYamlView.tsx +4 -2
  94. package/src/components/shared/ResourceActionsBar.tsx +170 -25
  95. package/src/components/shared/ResourceRendererDispatch.test.tsx +206 -1
  96. package/src/components/shared/ResourceRendererDispatch.tsx +84 -40
  97. package/src/components/shared/SetImageDialog.test.ts +129 -0
  98. package/src/components/shared/SetImageDialog.tsx +577 -0
  99. package/src/components/shared/index.ts +1 -0
  100. package/src/components/shared/revision-role-badges.test.ts +56 -4
  101. package/src/components/timeline/TimelineList.tsx +19 -3
  102. package/src/components/timeline/TimelineSwimlanes.tsx +11 -3
  103. package/src/components/trace/ReachabilityView.tsx +1 -1
  104. package/src/components/ui/SelectMenu.tsx +10 -1
  105. package/src/components/ui/drawer-components.tsx +12 -0
  106. package/src/components/workload/WorkloadRolloutNotice.tsx +60 -0
  107. package/src/components/workload/WorkloadView.tsx +144 -81
  108. package/src/hooks/useProgressiveRefresh.ts +37 -0
  109. package/src/source-hygiene.test.ts +28 -0
  110. package/src/theme/tailwind-theme.css +4 -0
  111. package/src/types/core.ts +55 -0
  112. package/src/utils/api-resources.test.ts +40 -1
  113. package/src/utils/api-resources.ts +11 -1
  114. package/src/utils/applications.ts +50 -0
  115. package/src/utils/bulk-workload-actions.test.ts +20 -0
  116. package/src/utils/bulk-workload-actions.ts +15 -0
  117. package/src/utils/navigation.test.ts +31 -1
  118. package/src/utils/navigation.ts +21 -2
  119. 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 { kindToPlural, refToSelectedResource, apiVersionToGroup } from '../../utils/navigation'
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?.({ kind: kindToPlural(item.kind), namespace: item.namespace, name: item.name, group: apiVersionToGroup(item.apiVersion) })
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?.({ kind: kindToPlural(first.kind), namespace: first.namespace, name: first.name, group: apiVersionToGroup(first.apiVersion) })
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 { kindToPlural, apiVersionToGroup } from '../../utils/navigation'
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: kindToPlural(kind), namespace, name, group })
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?.({ kind: kindToPlural(selected.kind), namespace: selected.namespace, name: selected.name, group: apiVersionToGroup(selected.apiVersion) })
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}${k}` })
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
- 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"
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
+ }