@skyhook-io/k8s-ui 1.13.3 → 1.13.4
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 +1 -1
- 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 +964 -96
- 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/printer-columns.test.ts +298 -0
- package/src/components/resources/printer-columns.ts +249 -0
- 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/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/RolloutRenderer.test.tsx +35 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +22 -3
- 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/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/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-gpu-ecosystem.test.ts +222 -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 +198 -0
- 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-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/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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react'
|
|
2
|
-
import { Server, ExternalLink, Scale, Minus, Plus,
|
|
2
|
+
import { Server, ExternalLink, Scale, Minus, Plus, Shield } from 'lucide-react'
|
|
3
3
|
import { clsx } from 'clsx'
|
|
4
4
|
import { PolicySection } from './PolicySection'
|
|
5
5
|
import type { PolicyResourceResponse } from '../../../types/policy'
|
|
@@ -7,7 +7,7 @@ import { Section, PropertyList, Property, ConditionsSection, PodTemplateSection,
|
|
|
7
7
|
import { DialogPortal } from '../../ui/DialogPortal'
|
|
8
8
|
import { Tooltip } from '../../ui/Tooltip'
|
|
9
9
|
import { Badge, type BadgeSeverity } from '../../ui/Badge'
|
|
10
|
-
import type { RBACSubjectResponse, RBACPolicyRule, ResourceRef, HPADiagnosis } from '../../../types'
|
|
10
|
+
import type { RBACSubjectResponse, RBACPolicyRule, ResourceRef, HPADiagnosis, WorkloadPodInfo } from '../../../types'
|
|
11
11
|
import { detectBlastRadius, rulePermissivenessScore } from '../../../utils/rbac-blast-radius'
|
|
12
12
|
import { RBACErrorSection, isRBACUnavailable } from './RBACErrorSection'
|
|
13
13
|
import { hpaStateLabel, hpaStateLevel } from '../resource-utils-hpa'
|
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
rbacResourceBadgeClass,
|
|
17
17
|
rbacApiGroupBadgeClass,
|
|
18
18
|
} from '../../../utils/rbac-badges'
|
|
19
|
+
import { getWorkloadRolloutActivity } from '../../../utils/workload-rollout'
|
|
20
|
+
import { useProgressiveRefresh } from '../../../hooks/useProgressiveRefresh'
|
|
21
|
+
import { WorkloadRolloutNotice } from '../../workload/WorkloadRolloutNotice'
|
|
19
22
|
|
|
20
23
|
export interface ScalerDiagnosis {
|
|
21
24
|
ref: ResourceRef
|
|
@@ -33,6 +36,7 @@ interface WorkloadRendererProps {
|
|
|
33
36
|
isScalePending?: boolean
|
|
34
37
|
scaleBlockedBy?: ResourceRef[]
|
|
35
38
|
scalerDiagnostics?: ScalerDiagnosis[]
|
|
39
|
+
workloadPods?: WorkloadPodInfo[]
|
|
36
40
|
onRequestRefresh?: () => void
|
|
37
41
|
/**
|
|
38
42
|
* RBAC reverse-lookup for the workload's pod-template ServiceAccount.
|
|
@@ -52,21 +56,13 @@ interface WorkloadRendererProps {
|
|
|
52
56
|
policyError?: Error | null
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
// Check if the workload is actively progressing (scaling, rolling update)
|
|
56
|
-
function isWorkloadProgressing(status: any): boolean {
|
|
57
|
-
const conditions = status.conditions || []
|
|
58
|
-
const progressing = conditions.find((c: any) => c.type === 'Progressing')
|
|
59
|
-
return progressing?.status === 'True' && progressing?.reason !== 'ProgressDeadlineExceeded'
|
|
60
|
-
}
|
|
61
|
-
|
|
62
59
|
// Extract real problems from workload status (excludes normal rollout progress)
|
|
63
|
-
function getWorkloadProblems(status: any, spec: any, kind: string): string[] {
|
|
60
|
+
function getWorkloadProblems(status: any, spec: any, kind: string, rolloutExplainsShortfall: boolean): string[] {
|
|
64
61
|
const problems: string[] = []
|
|
65
|
-
const progressing = isWorkloadProgressing(status)
|
|
66
62
|
const isDaemonSet = kind === 'daemonsets'
|
|
67
63
|
|
|
68
64
|
// Check replica/pod counts — only flag as problem if NOT actively progressing
|
|
69
|
-
if (!
|
|
65
|
+
if (!rolloutExplainsShortfall) {
|
|
70
66
|
if (isDaemonSet) {
|
|
71
67
|
const ready = status.numberReady || 0
|
|
72
68
|
const desired = status.desiredNumberScheduled || 0
|
|
@@ -78,7 +74,7 @@ function getWorkloadProblems(status: any, spec: any, kind: string): string[] {
|
|
|
78
74
|
}
|
|
79
75
|
} else {
|
|
80
76
|
const ready = status.readyReplicas || 0
|
|
81
|
-
const desired = spec.replicas
|
|
77
|
+
const desired = spec.replicas ?? 1
|
|
82
78
|
if (desired > 0 && ready < desired) {
|
|
83
79
|
problems.push(`${desired - ready} of ${desired} replicas are not ready`)
|
|
84
80
|
}
|
|
@@ -96,7 +92,7 @@ function getWorkloadProblems(status: any, spec: any, kind: string): string[] {
|
|
|
96
92
|
}
|
|
97
93
|
// Show condition failures, but skip Available=False during active rollout (that's expected)
|
|
98
94
|
if (cond.status === 'False' && cond.message) {
|
|
99
|
-
if (
|
|
95
|
+
if (rolloutExplainsShortfall && cond.type === 'Available') continue
|
|
100
96
|
problems.push(`${cond.type}: ${cond.message}`)
|
|
101
97
|
}
|
|
102
98
|
}
|
|
@@ -104,27 +100,6 @@ function getWorkloadProblems(status: any, spec: any, kind: string): string[] {
|
|
|
104
100
|
return problems
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
// Get progress info for active rollouts
|
|
108
|
-
function getWorkloadProgress(status: any, spec: any, kind: string): string | null {
|
|
109
|
-
if (!isWorkloadProgressing(status)) return null
|
|
110
|
-
|
|
111
|
-
const isDaemonSet = kind === 'daemonsets'
|
|
112
|
-
if (isDaemonSet) {
|
|
113
|
-
const ready = status.numberReady || 0
|
|
114
|
-
const desired = status.desiredNumberScheduled || 0
|
|
115
|
-
if (desired > 0 && ready < desired) {
|
|
116
|
-
return `${ready} of ${desired} pods ready`
|
|
117
|
-
}
|
|
118
|
-
} else {
|
|
119
|
-
const ready = status.readyReplicas || 0
|
|
120
|
-
const desired = spec.replicas || 0
|
|
121
|
-
if (desired > 0 && ready < desired) {
|
|
122
|
-
return `${ready} of ${desired} replicas ready`
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return null
|
|
126
|
-
}
|
|
127
|
-
|
|
128
103
|
function formatScalerLabel(ref: ResourceRef): string {
|
|
129
104
|
const prefix = ref.namespace ? `${ref.namespace}/` : ''
|
|
130
105
|
return `${ref.kind} ${prefix}${ref.name}`
|
|
@@ -150,7 +125,7 @@ function compactHPASummary(diagnosis: HPADiagnosis): string {
|
|
|
150
125
|
return diagnosis.summary
|
|
151
126
|
}
|
|
152
127
|
|
|
153
|
-
export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale, isScalePending, scaleBlockedBy, scalerDiagnostics, onRequestRefresh, rbacData, rbacLoading, rbacError, policyData, policyLoading, policyError }: WorkloadRendererProps) {
|
|
128
|
+
export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale, isScalePending, scaleBlockedBy, scalerDiagnostics, workloadPods, onRequestRefresh, rbacData, rbacLoading, rbacError, policyData, policyLoading, policyError }: WorkloadRendererProps) {
|
|
154
129
|
const status = data.status || {}
|
|
155
130
|
const spec = data.spec || {}
|
|
156
131
|
const metadata = data.metadata || {}
|
|
@@ -165,7 +140,7 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
165
140
|
|
|
166
141
|
// Scale dialog state
|
|
167
142
|
const [showScaleDialog, setShowScaleDialog] = useState(false)
|
|
168
|
-
const [targetReplicas, setTargetReplicas] = useState(spec.replicas
|
|
143
|
+
const [targetReplicas, setTargetReplicas] = useState(spec.replicas ?? 1)
|
|
169
144
|
const [scaledTo, setScaledTo] = useState<number | null>(null)
|
|
170
145
|
|
|
171
146
|
// Clear scaledTo once the backend data catches up
|
|
@@ -179,19 +154,15 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
179
154
|
// Issues section is shown — it carries the workload's own issues plus its pods'
|
|
180
155
|
// (richer, with cause/action), so the workload-status problems would duplicate.
|
|
181
156
|
const operationalIssuesShown = useOperationalIssuesShown()
|
|
182
|
-
const
|
|
157
|
+
const rolloutActivity = getWorkloadRolloutActivity(data, kind, workloadPods)
|
|
158
|
+
const rolloutExplainsShortfall = rolloutActivity.phase === 'applying' || rolloutActivity.phase === 'progressing'
|
|
159
|
+
const problems = operationalIssuesShown ? [] : getWorkloadProblems(status, spec, kind, rolloutExplainsShortfall)
|
|
183
160
|
const hasProblems = problems.length > 0
|
|
184
|
-
const
|
|
161
|
+
const displayedActivity = scaledTo !== null && rolloutActivity.phase === 'idle'
|
|
162
|
+
? { ...rolloutActivity, phase: 'applying' as const, active: true, label: 'Scaling workload', detail: `Waiting for the controller to apply ${scaledTo} replicas` }
|
|
163
|
+
: rolloutActivity
|
|
185
164
|
|
|
186
|
-
|
|
187
|
-
const isScaling = scaledTo !== null || progressMessage !== null
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
if (!isScaling || !onRequestRefresh) return
|
|
190
|
-
const interval = setInterval(() => {
|
|
191
|
-
onRequestRefresh()
|
|
192
|
-
}, 2000)
|
|
193
|
-
return () => clearInterval(interval)
|
|
194
|
-
}, [isScaling, onRequestRefresh])
|
|
165
|
+
useProgressiveRefresh(scaledTo !== null, onRequestRefresh)
|
|
195
166
|
|
|
196
167
|
useEffect(() => {
|
|
197
168
|
if (isScaleBlocked) {
|
|
@@ -211,24 +182,13 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
211
182
|
}
|
|
212
183
|
|
|
213
184
|
const openScaleDialog = () => {
|
|
214
|
-
setTargetReplicas(spec.replicas
|
|
185
|
+
setTargetReplicas(spec.replicas ?? 1)
|
|
215
186
|
setShowScaleDialog(true)
|
|
216
187
|
}
|
|
217
188
|
|
|
218
189
|
return (
|
|
219
190
|
<>
|
|
220
|
-
{
|
|
221
|
-
attention state, not an info note (it may be a stuck rollout). */}
|
|
222
|
-
{(scaledTo !== null || progressMessage) && !hasProblems && (
|
|
223
|
-
<div className="mb-4 p-3 bg-amber-500/10 border border-amber-500/30 rounded-lg">
|
|
224
|
-
<div className="flex items-center gap-2">
|
|
225
|
-
<Loader2 className="w-4 h-4 text-amber-500 animate-spin shrink-0" />
|
|
226
|
-
<div className="text-sm text-amber-700 dark:text-amber-300">
|
|
227
|
-
{progressMessage || `Scaling to ${scaledTo} replicas...`}
|
|
228
|
-
</div>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
)}
|
|
191
|
+
{(!hasProblems || displayedActivity.phase === 'stalled') && <WorkloadRolloutNotice activity={displayedActivity} className="mb-4" />}
|
|
232
192
|
|
|
233
193
|
{/* Problems alert - shown at top when there are real issues */}
|
|
234
194
|
{hasProblems && (
|
|
@@ -262,7 +222,7 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
262
222
|
</>
|
|
263
223
|
) : (
|
|
264
224
|
<>
|
|
265
|
-
<Property label="Replicas" value={`${status.readyReplicas || 0}/${spec.replicas
|
|
225
|
+
<Property label="Replicas" value={`${status.readyReplicas || 0}/${spec.replicas ?? 1}`} />
|
|
266
226
|
{scaleBlockedBy && scaleBlockedBy.length > 0 && (
|
|
267
227
|
<Property
|
|
268
228
|
label="Controlled by"
|
|
@@ -357,8 +317,8 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
357
317
|
</div>
|
|
358
318
|
|
|
359
319
|
<div className="text-xs text-theme-text-tertiary text-center mb-4">
|
|
360
|
-
Current: {spec.replicas
|
|
361
|
-
{targetReplicas !== (spec.replicas
|
|
320
|
+
Current: {spec.replicas ?? 1} replicas
|
|
321
|
+
{targetReplicas !== (spec.replicas ?? 1) && (
|
|
362
322
|
<span className="text-theme-text-secondary">
|
|
363
323
|
{' '}→ {targetReplicas}
|
|
364
324
|
</span>
|
|
@@ -374,7 +334,7 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
|
|
|
374
334
|
</button>
|
|
375
335
|
<button
|
|
376
336
|
onClick={handleScale}
|
|
377
|
-
disabled={isScalePending || targetReplicas === (spec.replicas
|
|
337
|
+
disabled={isScalePending || targetReplicas === (spec.replicas ?? 1)}
|
|
378
338
|
className="flex-1 px-3 py-2 text-sm btn-brand disabled:cursor-not-allowed rounded-lg"
|
|
379
339
|
>
|
|
380
340
|
{isScalePending ? 'Scaling...' : 'Apply'}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// AMD GPU Operator cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getAMDDeviceConfigStatus,
|
|
6
|
+
getAMDDeviceConfigDriver,
|
|
7
|
+
getAMDDeviceConfigDevicePluginImage,
|
|
8
|
+
getAMDDeviceConfigNodeCount,
|
|
9
|
+
} from '../resource-utils-amd-gpu'
|
|
10
|
+
|
|
11
|
+
export function AMDDeviceConfigCell({ resource, column }: { resource: any; column: string }) {
|
|
12
|
+
switch (column) {
|
|
13
|
+
case 'status': {
|
|
14
|
+
const status = getAMDDeviceConfigStatus(resource)
|
|
15
|
+
return (
|
|
16
|
+
<span className={clsx('badge', status.color)}>
|
|
17
|
+
{status.text}
|
|
18
|
+
</span>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
case 'driver': {
|
|
22
|
+
const driver = getAMDDeviceConfigDriver(resource)
|
|
23
|
+
return <span className="text-sm text-theme-text-secondary">{driver}</span>
|
|
24
|
+
}
|
|
25
|
+
case 'devicePluginImage': {
|
|
26
|
+
const image = getAMDDeviceConfigDevicePluginImage(resource)
|
|
27
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{image}</span>
|
|
28
|
+
}
|
|
29
|
+
case 'nodes': {
|
|
30
|
+
const nodes = getAMDDeviceConfigNodeCount(resource)
|
|
31
|
+
return <span className="text-sm text-theme-text-secondary">{nodes}</span>
|
|
32
|
+
}
|
|
33
|
+
default:
|
|
34
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Gateway API Inference Extension cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getInferencePoolStatus,
|
|
6
|
+
getInferencePoolSelector,
|
|
7
|
+
getInferencePoolTargetPorts,
|
|
8
|
+
getInferencePoolExtensionRef,
|
|
9
|
+
getInferenceObjectiveStatus,
|
|
10
|
+
getInferenceObjectivePoolRef,
|
|
11
|
+
getInferenceObjectivePriority,
|
|
12
|
+
} from '../resource-utils-inference-gateway'
|
|
13
|
+
|
|
14
|
+
export function InferencePoolCell({ resource, column }: { resource: any; column: string }) {
|
|
15
|
+
switch (column) {
|
|
16
|
+
case 'status': {
|
|
17
|
+
const status = getInferencePoolStatus(resource)
|
|
18
|
+
return (
|
|
19
|
+
<span className={clsx('badge', status.color)}>
|
|
20
|
+
{status.text}
|
|
21
|
+
</span>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
case 'selector': {
|
|
25
|
+
const selector = getInferencePoolSelector(resource)
|
|
26
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{selector}</span>
|
|
27
|
+
}
|
|
28
|
+
case 'targetPorts': {
|
|
29
|
+
const ports = getInferencePoolTargetPorts(resource)
|
|
30
|
+
return <span className="text-sm text-theme-text-secondary">{ports}</span>
|
|
31
|
+
}
|
|
32
|
+
case 'extensionRef': {
|
|
33
|
+
const ref = getInferencePoolExtensionRef(resource)
|
|
34
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{ref}</span>
|
|
35
|
+
}
|
|
36
|
+
default:
|
|
37
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function InferenceObjectiveCell({ resource, column }: { resource: any; column: string }) {
|
|
42
|
+
switch (column) {
|
|
43
|
+
case 'status': {
|
|
44
|
+
const status = getInferenceObjectiveStatus(resource)
|
|
45
|
+
return (
|
|
46
|
+
<span className={clsx('badge', status.color)}>
|
|
47
|
+
{status.text}
|
|
48
|
+
</span>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
case 'poolRef': {
|
|
52
|
+
const poolRef = getInferenceObjectivePoolRef(resource)
|
|
53
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{poolRef}</span>
|
|
54
|
+
}
|
|
55
|
+
case 'priority': {
|
|
56
|
+
const priority = getInferenceObjectivePriority(resource)
|
|
57
|
+
return <span className="text-sm text-theme-text-secondary">{priority}</span>
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// LeaderWorkerSet and JobSet cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getLeaderWorkerSetStatus,
|
|
6
|
+
getLeaderWorkerSetReplicas,
|
|
7
|
+
getLeaderWorkerSetSize,
|
|
8
|
+
getLeaderWorkerSetReady,
|
|
9
|
+
getLeaderWorkerSetUpdated,
|
|
10
|
+
getJobSetStatus,
|
|
11
|
+
getJobSetReplicatedJobs,
|
|
12
|
+
getJobSetReadyJobs,
|
|
13
|
+
getJobSetSucceededJobs,
|
|
14
|
+
getJobSetFailedJobs,
|
|
15
|
+
getJobSetRestarts,
|
|
16
|
+
} from '../resource-utils-jobset-lws'
|
|
17
|
+
|
|
18
|
+
export function LeaderWorkerSetCell({ resource, column }: { resource: any; column: string }) {
|
|
19
|
+
switch (column) {
|
|
20
|
+
case 'status': {
|
|
21
|
+
const status = getLeaderWorkerSetStatus(resource)
|
|
22
|
+
return (
|
|
23
|
+
<span className={clsx('badge', status.color)}>
|
|
24
|
+
{status.text}
|
|
25
|
+
</span>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
case 'replicas': {
|
|
29
|
+
const replicas = getLeaderWorkerSetReplicas(resource)
|
|
30
|
+
return <span className="text-sm text-theme-text-secondary">{replicas}</span>
|
|
31
|
+
}
|
|
32
|
+
case 'size': {
|
|
33
|
+
const size = getLeaderWorkerSetSize(resource)
|
|
34
|
+
return <span className="text-sm text-theme-text-secondary">{size}</span>
|
|
35
|
+
}
|
|
36
|
+
case 'ready': {
|
|
37
|
+
const ready = getLeaderWorkerSetReady(resource)
|
|
38
|
+
return <span className="text-sm text-theme-text-secondary">{ready}</span>
|
|
39
|
+
}
|
|
40
|
+
case 'updated': {
|
|
41
|
+
const updated = getLeaderWorkerSetUpdated(resource)
|
|
42
|
+
return <span className="text-sm text-theme-text-secondary">{updated}</span>
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function JobSetCell({ resource, column }: { resource: any; column: string }) {
|
|
50
|
+
switch (column) {
|
|
51
|
+
case 'status': {
|
|
52
|
+
const status = getJobSetStatus(resource)
|
|
53
|
+
return (
|
|
54
|
+
<span className={clsx('badge', status.color)}>
|
|
55
|
+
{status.text}
|
|
56
|
+
</span>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
case 'replicatedJobs': {
|
|
60
|
+
const count = getJobSetReplicatedJobs(resource)
|
|
61
|
+
return <span className="text-sm text-theme-text-secondary">{count}</span>
|
|
62
|
+
}
|
|
63
|
+
case 'ready': {
|
|
64
|
+
const ready = getJobSetReadyJobs(resource)
|
|
65
|
+
return <span className="text-sm text-theme-text-secondary">{ready}</span>
|
|
66
|
+
}
|
|
67
|
+
case 'succeeded': {
|
|
68
|
+
const succeeded = getJobSetSucceededJobs(resource)
|
|
69
|
+
return <span className="text-sm text-theme-text-secondary">{succeeded}</span>
|
|
70
|
+
}
|
|
71
|
+
case 'failed': {
|
|
72
|
+
const failed = getJobSetFailedJobs(resource)
|
|
73
|
+
return <span className={clsx('text-sm', failed > 0 ? 'text-theme-text-primary' : 'text-theme-text-secondary')}>{failed}</span>
|
|
74
|
+
}
|
|
75
|
+
case 'restarts': {
|
|
76
|
+
const restarts = getJobSetRestarts(resource)
|
|
77
|
+
return <span className="text-sm text-theme-text-secondary">{restarts}</span>
|
|
78
|
+
}
|
|
79
|
+
default:
|
|
80
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// KAI Scheduler cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getKaiQueueStatus,
|
|
6
|
+
getKaiQueueParent,
|
|
7
|
+
getKaiQueuePriority,
|
|
8
|
+
getKaiQueueQuota,
|
|
9
|
+
getKaiQueueAllocated,
|
|
10
|
+
getKaiPodGroupStatus,
|
|
11
|
+
getKaiPodGroupQueue,
|
|
12
|
+
getKaiPodGroupMinMember,
|
|
13
|
+
} from '../resource-utils-kai'
|
|
14
|
+
|
|
15
|
+
export function KaiQueueCell({ resource, column }: { resource: any; column: string }) {
|
|
16
|
+
switch (column) {
|
|
17
|
+
case 'status': {
|
|
18
|
+
const status = getKaiQueueStatus(resource)
|
|
19
|
+
return (
|
|
20
|
+
<span className={clsx('badge', status.color)}>
|
|
21
|
+
{status.text}
|
|
22
|
+
</span>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
case 'parentQueue': {
|
|
26
|
+
const parent = getKaiQueueParent(resource)
|
|
27
|
+
return <span className="text-sm text-theme-text-secondary">{parent}</span>
|
|
28
|
+
}
|
|
29
|
+
case 'priority': {
|
|
30
|
+
const priority = getKaiQueuePriority(resource)
|
|
31
|
+
return <span className="text-sm text-theme-text-secondary">{priority}</span>
|
|
32
|
+
}
|
|
33
|
+
case 'quota': {
|
|
34
|
+
const quota = getKaiQueueQuota(resource)
|
|
35
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{quota}</span>
|
|
36
|
+
}
|
|
37
|
+
case 'allocated': {
|
|
38
|
+
const allocated = getKaiQueueAllocated(resource)
|
|
39
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{allocated}</span>
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function KaiPodGroupCell({ resource, column }: { resource: any; column: string }) {
|
|
47
|
+
switch (column) {
|
|
48
|
+
case 'status': {
|
|
49
|
+
const status = getKaiPodGroupStatus(resource)
|
|
50
|
+
return (
|
|
51
|
+
<span className={clsx('badge', status.color)}>
|
|
52
|
+
{status.text}
|
|
53
|
+
</span>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
case 'queue': {
|
|
57
|
+
const queue = getKaiPodGroupQueue(resource)
|
|
58
|
+
return <span className="text-sm text-theme-text-secondary">{queue}</span>
|
|
59
|
+
}
|
|
60
|
+
case 'minMember': {
|
|
61
|
+
const minMember = getKaiPodGroupMinMember(resource)
|
|
62
|
+
return <span className="text-sm text-theme-text-secondary">{minMember}</span>
|
|
63
|
+
}
|
|
64
|
+
default:
|
|
65
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// KAITO cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getKaitoWorkspaceStatus,
|
|
6
|
+
getKaitoWorkspaceInstanceType,
|
|
7
|
+
getKaitoWorkspacePreset,
|
|
8
|
+
getKaitoWorkspaceNodeCount,
|
|
9
|
+
getRAGEngineStatus,
|
|
10
|
+
getRAGEngineEmbeddingModel,
|
|
11
|
+
getRAGEngineInstanceType,
|
|
12
|
+
} from '../resource-utils-kaito'
|
|
13
|
+
|
|
14
|
+
export function KaitoWorkspaceCell({ resource, column }: { resource: any; column: string }) {
|
|
15
|
+
switch (column) {
|
|
16
|
+
case 'status': {
|
|
17
|
+
const status = getKaitoWorkspaceStatus(resource)
|
|
18
|
+
return (
|
|
19
|
+
<span className={clsx('badge', status.color)}>
|
|
20
|
+
{status.text}
|
|
21
|
+
</span>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
case 'instanceType': {
|
|
25
|
+
const instanceType = getKaitoWorkspaceInstanceType(resource)
|
|
26
|
+
return <span className="text-sm text-theme-text-secondary">{instanceType}</span>
|
|
27
|
+
}
|
|
28
|
+
case 'preset': {
|
|
29
|
+
const preset = getKaitoWorkspacePreset(resource)
|
|
30
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{preset}</span>
|
|
31
|
+
}
|
|
32
|
+
case 'nodes': {
|
|
33
|
+
const nodes = getKaitoWorkspaceNodeCount(resource)
|
|
34
|
+
return <span className="text-sm text-theme-text-secondary">{nodes}</span>
|
|
35
|
+
}
|
|
36
|
+
default:
|
|
37
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function RAGEngineCell({ resource, column }: { resource: any; column: string }) {
|
|
42
|
+
switch (column) {
|
|
43
|
+
case 'status': {
|
|
44
|
+
const status = getRAGEngineStatus(resource)
|
|
45
|
+
return (
|
|
46
|
+
<span className={clsx('badge', status.color)}>
|
|
47
|
+
{status.text}
|
|
48
|
+
</span>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
case 'embedding': {
|
|
52
|
+
const model = getRAGEngineEmbeddingModel(resource)
|
|
53
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{model}</span>
|
|
54
|
+
}
|
|
55
|
+
case 'instanceType': {
|
|
56
|
+
const instanceType = getRAGEngineInstanceType(resource)
|
|
57
|
+
return <span className="text-sm text-theme-text-secondary">{instanceType}</span>
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// KServe cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getInferenceServiceStatus,
|
|
6
|
+
getInferenceServiceUrl,
|
|
7
|
+
getInferenceServiceModelFormat,
|
|
8
|
+
getInferenceServiceRuntime,
|
|
9
|
+
getInferenceServiceDeploymentMode,
|
|
10
|
+
getServingRuntimeStatus,
|
|
11
|
+
getServingRuntimeModelFormats,
|
|
12
|
+
getServingRuntimeImage,
|
|
13
|
+
getInferenceGraphStatus,
|
|
14
|
+
getInferenceGraphNodeCount,
|
|
15
|
+
getTrainedModelStatus,
|
|
16
|
+
getTrainedModelFramework,
|
|
17
|
+
getTrainedModelStorageUri,
|
|
18
|
+
getTrainedModelInferenceService,
|
|
19
|
+
getLLMInferenceServiceStatus,
|
|
20
|
+
getLLMInferenceServiceModel,
|
|
21
|
+
getLLMInferenceServiceReplicas,
|
|
22
|
+
} from '../resource-utils-kserve'
|
|
23
|
+
|
|
24
|
+
export function InferenceServiceCell({ resource, column }: { resource: any; column: string }) {
|
|
25
|
+
switch (column) {
|
|
26
|
+
case 'status': {
|
|
27
|
+
const status = getInferenceServiceStatus(resource)
|
|
28
|
+
return (
|
|
29
|
+
<span className={clsx('badge', status.color)}>
|
|
30
|
+
{status.text}
|
|
31
|
+
</span>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
case 'url': {
|
|
35
|
+
const url = getInferenceServiceUrl(resource)
|
|
36
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{url}</span>
|
|
37
|
+
}
|
|
38
|
+
case 'modelFormat': {
|
|
39
|
+
const format = getInferenceServiceModelFormat(resource)
|
|
40
|
+
return <span className="text-sm text-theme-text-secondary">{format}</span>
|
|
41
|
+
}
|
|
42
|
+
case 'runtime': {
|
|
43
|
+
const runtime = getInferenceServiceRuntime(resource)
|
|
44
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{runtime}</span>
|
|
45
|
+
}
|
|
46
|
+
case 'deploymentMode': {
|
|
47
|
+
const mode = getInferenceServiceDeploymentMode(resource)
|
|
48
|
+
return <span className="text-sm text-theme-text-secondary">{mode}</span>
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function ServingRuntimeCell({ resource, column }: { resource: any; column: string }) {
|
|
56
|
+
switch (column) {
|
|
57
|
+
case 'status': {
|
|
58
|
+
const status = getServingRuntimeStatus(resource)
|
|
59
|
+
return (
|
|
60
|
+
<span className={clsx('badge', status.color)}>
|
|
61
|
+
{status.text}
|
|
62
|
+
</span>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
case 'modelFormats': {
|
|
66
|
+
const formats = getServingRuntimeModelFormats(resource)
|
|
67
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{formats}</span>
|
|
68
|
+
}
|
|
69
|
+
case 'image': {
|
|
70
|
+
const image = getServingRuntimeImage(resource)
|
|
71
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{image}</span>
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function InferenceGraphCell({ resource, column }: { resource: any; column: string }) {
|
|
79
|
+
switch (column) {
|
|
80
|
+
case 'status': {
|
|
81
|
+
const status = getInferenceGraphStatus(resource)
|
|
82
|
+
return (
|
|
83
|
+
<span className={clsx('badge', status.color)}>
|
|
84
|
+
{status.text}
|
|
85
|
+
</span>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
case 'nodes': {
|
|
89
|
+
const count = getInferenceGraphNodeCount(resource)
|
|
90
|
+
return <span className="text-sm text-theme-text-secondary">{count > 0 ? count : '-'}</span>
|
|
91
|
+
}
|
|
92
|
+
default:
|
|
93
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function TrainedModelCell({ resource, column }: { resource: any; column: string }) {
|
|
98
|
+
switch (column) {
|
|
99
|
+
case 'status': {
|
|
100
|
+
const status = getTrainedModelStatus(resource)
|
|
101
|
+
return (
|
|
102
|
+
<span className={clsx('badge', status.color)}>
|
|
103
|
+
{status.text}
|
|
104
|
+
</span>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
case 'framework': {
|
|
108
|
+
const framework = getTrainedModelFramework(resource)
|
|
109
|
+
return <span className="text-sm text-theme-text-secondary">{framework}</span>
|
|
110
|
+
}
|
|
111
|
+
case 'storageUri': {
|
|
112
|
+
const uri = getTrainedModelStorageUri(resource)
|
|
113
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{uri}</span>
|
|
114
|
+
}
|
|
115
|
+
case 'inferenceService': {
|
|
116
|
+
const parent = getTrainedModelInferenceService(resource)
|
|
117
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{parent}</span>
|
|
118
|
+
}
|
|
119
|
+
default:
|
|
120
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function LLMInferenceServiceCell({ resource, column }: { resource: any; column: string }) {
|
|
125
|
+
switch (column) {
|
|
126
|
+
case 'status': {
|
|
127
|
+
const status = getLLMInferenceServiceStatus(resource)
|
|
128
|
+
return (
|
|
129
|
+
<span className={clsx('badge', status.color)}>
|
|
130
|
+
{status.text}
|
|
131
|
+
</span>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
case 'model': {
|
|
135
|
+
const model = getLLMInferenceServiceModel(resource)
|
|
136
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{model}</span>
|
|
137
|
+
}
|
|
138
|
+
case 'replicas': {
|
|
139
|
+
const replicas = getLLMInferenceServiceReplicas(resource)
|
|
140
|
+
return <span className="text-sm text-theme-text-secondary">{replicas}</span>
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
144
|
+
}
|
|
145
|
+
}
|