@skyhook-io/k8s-ui 1.12.0 → 1.13.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/issues/severity.ts +1 -0
- package/src/components/resources/ResourcesView.empty-note.test.ts +41 -0
- package/src/components/resources/ResourcesView.tsx +410 -5
- package/src/components/resources/index.ts +27 -0
- package/src/components/resources/kyverno-legacy-action.test.ts +98 -0
- package/src/components/resources/renderers/AnalysisRunRenderer.test.tsx +241 -0
- package/src/components/resources/renderers/AnalysisRunRenderer.tsx +166 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +31 -2
- package/src/components/resources/renderers/CNPGClusterRenderer.test.tsx +33 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +47 -4
- package/src/components/resources/renderers/CNPGDeclarativeRenderer.tsx +243 -0
- package/src/components/resources/renderers/CNPGObjectStoreRenderer.test.tsx +99 -0
- package/src/components/resources/renderers/CNPGObjectStoreRenderer.tsx +235 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +23 -1
- package/src/components/resources/renderers/CNPGShared.tsx +27 -0
- package/src/components/resources/renderers/CalicoHostEndpointRenderer.tsx +71 -0
- package/src/components/resources/renderers/CalicoIPPoolRenderer.tsx +32 -0
- package/src/components/resources/renderers/CalicoNetworkPolicyDiagram.test.tsx +205 -0
- package/src/components/resources/renderers/CalicoNetworkPolicyDiagram.tsx +537 -0
- package/src/components/resources/renderers/CalicoNetworkPolicyRenderer.test.tsx +223 -0
- package/src/components/resources/renderers/CalicoNetworkPolicyRenderer.tsx +670 -0
- package/src/components/resources/renderers/CalicoTierRenderer.tsx +19 -0
- package/src/components/resources/renderers/KyvernoCELPolicyRenderers.tsx +13 -6
- package/src/components/resources/renderers/KyvernoExceptionRenderers.tsx +3 -2
- package/src/components/resources/renderers/KyvernoGlobalContextRenderer.test.ts +31 -0
- package/src/components/resources/renderers/KyvernoGlobalContextRenderer.tsx +124 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +28 -2
- package/src/components/resources/renderers/KyvernoQueueRenderers.tsx +303 -0
- package/src/components/resources/renderers/LookupFailureNote.test.tsx +60 -0
- package/src/components/resources/renderers/LookupFailureNote.tsx +42 -0
- package/src/components/resources/renderers/NetworkPolicyDiagram.tsx +27 -26
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +6 -3
- package/src/components/resources/renderers/PolicyCoverageSection.test.tsx +348 -0
- package/src/components/resources/renderers/PolicyCoverageSection.tsx +939 -0
- package/src/components/resources/renderers/PolicySection.test.tsx +59 -2
- package/src/components/resources/renderers/PolicySection.tsx +32 -5
- package/src/components/resources/renderers/RolloutRenderer.test.tsx +491 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +391 -92
- package/src/components/resources/renderers/VeleroBSLRenderer.test.tsx +374 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +179 -3
- package/src/components/resources/renderers/VeleroBackupRenderer.test.tsx +221 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +119 -6
- package/src/components/resources/renderers/VeleroBackupRepositoryRenderer.test.tsx +69 -0
- package/src/components/resources/renderers/VeleroBackupRepositoryRenderer.tsx +96 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.test.tsx +55 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +22 -4
- package/src/components/resources/renderers/VeleroRunMessages.test.tsx +152 -0
- package/src/components/resources/renderers/VeleroRunMessages.tsx +139 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.test.tsx +88 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +16 -6
- package/src/components/resources/renderers/calico-cells.tsx +177 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +100 -0
- package/src/components/resources/renderers/index.ts +16 -1
- package/src/components/resources/renderers/kyverno-cells.tsx +81 -0
- package/src/components/resources/renderers/network-policy-peer-styles.ts +25 -0
- package/src/components/resources/renderers/velero-cells.tsx +29 -7
- package/src/components/resources/renderers/velero-dead-ends.test.tsx +142 -0
- package/src/components/resources/resource-utils-calico.test.ts +215 -0
- package/src/components/resources/resource-utils-calico.ts +261 -0
- package/src/components/resources/resource-utils-cnpg-declarative.test.ts +104 -0
- package/src/components/resources/resource-utils-cnpg-objectstore.test.ts +122 -0
- package/src/components/resources/resource-utils-cnpg.test.ts +54 -0
- package/src/components/resources/resource-utils-cnpg.ts +264 -3
- package/src/components/resources/resource-utils-kyverno-modern.ts +24 -0
- package/src/components/resources/resource-utils-kyverno-queue.test.ts +164 -0
- package/src/components/resources/resource-utils-kyverno-queue.ts +198 -0
- package/src/components/resources/resource-utils-kyverno.ts +43 -7
- package/src/components/resources/resource-utils-velero.test.ts +26 -0
- package/src/components/resources/resource-utils-velero.ts +68 -0
- package/src/components/resources/resource-utils.ts +98 -0
- package/src/components/shared/ResourceActionsBar.tsx +101 -16
- package/src/components/shared/ResourceRendererDispatch.test.tsx +379 -3
- package/src/components/shared/ResourceRendererDispatch.tsx +199 -22
- package/src/components/shared/index.ts +1 -1
- package/src/components/shared/revision-role-badges.test.ts +120 -0
- package/src/components/topology/K8sResourceNode.test.ts +10 -0
- package/src/components/topology/K8sResourceNode.tsx +22 -0
- package/src/components/topology/TopologyFilterSidebar.test.tsx +31 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +5 -0
- package/src/components/topology/TopologyGraph.tsx +6 -6
- package/src/components/topology/TopologySearch.tsx +7 -0
- package/src/components/topology/layout.ts +3 -0
- package/src/components/trace/ReachabilityView.tsx +1 -0
- package/src/components/trace/TracePanel.tsx +12 -2
- package/src/components/trace/reachFixtures.ts +26 -1
- package/src/components/trace/reachGraphModel.test.ts +20 -0
- package/src/components/trace/reachGraphModel.ts +8 -1
- package/src/components/trace/reachOrigins.test.ts +31 -0
- package/src/components/trace/reachOrigins.ts +11 -1
- package/src/components/ui/Badge.tsx +10 -0
- package/src/components/ui/ScheduleValue.test.tsx +80 -0
- package/src/components/ui/ScheduleValue.tsx +85 -0
- package/src/components/ui/drawer-components.test.tsx +17 -1
- package/src/components/ui/drawer-components.tsx +9 -2
- package/src/components/ui/index.ts +2 -0
- package/src/components/workload/WorkloadView.tsx +3 -0
- package/src/types/core.ts +29 -0
- package/src/types/policy.ts +153 -2
- package/src/utils/navigation.test.ts +5 -0
- package/src/utils/navigation.ts +5 -0
- package/src/utils/resource-icons.test.ts +49 -2
- package/src/utils/resource-icons.ts +29 -2
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getNodeStatus,
|
|
11
11
|
getPVCStatus,
|
|
12
12
|
getRolloutStatus,
|
|
13
|
+
getAnalysisRunStatus,
|
|
13
14
|
getWorkflowStatus,
|
|
14
15
|
getCronWorkflowStatus,
|
|
15
16
|
getCertificateStatus,
|
|
@@ -51,6 +52,7 @@ import { getNodePoolStatus, getNodeClaimStatus, getEC2NodeClassStatus } from '..
|
|
|
51
52
|
import { getScaledObjectStatus, getScaledJobStatus } from '../resources/resource-utils-keda'
|
|
52
53
|
import { getServiceMonitorStatus, getPrometheusRuleStatus, getPodMonitorStatus } from '../resources/resource-utils-prometheus'
|
|
53
54
|
import { getPolicyReportStatus, getKyvernoPolicyStatus } from '../resources/resource-utils-kyverno'
|
|
55
|
+
import { getKyvernoRequestState, getKyvernoReportStatus } from '../resources/resource-utils-kyverno-queue'
|
|
54
56
|
import {
|
|
55
57
|
KYVERNO_MODERN_PLURALS,
|
|
56
58
|
getModernKyvernoPolicyStatus,
|
|
@@ -63,7 +65,7 @@ import {
|
|
|
63
65
|
} from '../resources/resource-utils-kyverno-exceptions'
|
|
64
66
|
import { getResourceClaimStatus, getResourceClaimTemplateStatus, getDeviceClassStatus, getResourceSliceStatus } from '../resources/resource-utils-dra'
|
|
65
67
|
import { getNvidiaClusterPolicyStatus, getNvidiaDriverStatus } from '../resources/resource-utils-nvidia'
|
|
66
|
-
import { getBackupStatus, getRestoreStatus, getScheduleStatus, getBSLStatus, isVeleroResource } from '../resources/resource-utils-velero'
|
|
68
|
+
import { getBackupStatus, getRestoreStatus, getScheduleStatus, getBSLStatus, getBackupRepositoryStatus, isVeleroResource } from '../resources/resource-utils-velero'
|
|
67
69
|
import {
|
|
68
70
|
getVirtualServiceStatus,
|
|
69
71
|
getDestinationRuleStatus,
|
|
@@ -72,13 +74,19 @@ import {
|
|
|
72
74
|
getPeerAuthenticationStatus,
|
|
73
75
|
getAuthorizationPolicyStatus,
|
|
74
76
|
} from '../resources/resource-utils-istio'
|
|
75
|
-
import { getCNPGClusterStatus, getCNPGBackupStatus, getCNPGScheduledBackupStatus, getCNPGPoolerStatus, isApiGroup, CNPG_GROUP } from '../resources/resource-utils-cnpg'
|
|
77
|
+
import { getCNPGClusterStatus, getCNPGBackupStatus, getCNPGScheduledBackupStatus, getCNPGPoolerStatus, getCNPGObjectStoreStatus, getCNPGDeclarativeStatus, isApiGroup, CNPG_GROUP } from '../resources/resource-utils-cnpg'
|
|
76
78
|
import { getExternalSecretStatus, getClusterExternalSecretStatus, getSecretStoreStatus, getClusterSecretStoreStatus } from '../resources/resource-utils-eso'
|
|
77
79
|
import {
|
|
78
80
|
getKnativeConditionStatus,
|
|
79
81
|
getRevisionStatus,
|
|
80
82
|
} from '../resources/resource-utils-knative'
|
|
81
83
|
import { getHTTPProxyStatus } from '../resources/resource-utils-contour'
|
|
84
|
+
import {
|
|
85
|
+
isCalicoApiVersion,
|
|
86
|
+
isCalicoPolicyKind,
|
|
87
|
+
isCalicoStagedKubernetesNetworkPolicyKind,
|
|
88
|
+
isCoreNetworkPolicyKind,
|
|
89
|
+
} from '../resources/resource-utils-calico'
|
|
82
90
|
import { getClusterStatus as getCAPIClusterStatus, getMachineStatus, getMachineDeploymentStatus, getMachineSetStatus, getMachinePoolStatus, getKCPStatus, getClusterClassStatus, getMachineHealthCheckStatus } from '../resources/resource-utils-capi'
|
|
83
91
|
import { getAWSMCPStatus, getAWSMMPStatus, getAWSMachineStatus, getAWSManagedClusterStatus } from '../resources/resource-utils-aws-capi'
|
|
84
92
|
import { getGCPMCPStatus, getGCPMMPStatus, getGCPMachineStatus, getGCPManagedClusterStatus } from '../resources/resource-utils-gcp-capi'
|
|
@@ -98,6 +106,7 @@ import {
|
|
|
98
106
|
NodeRenderer,
|
|
99
107
|
PVCRenderer,
|
|
100
108
|
RolloutRenderer,
|
|
109
|
+
AnalysisRunRenderer,
|
|
101
110
|
CertificateRenderer,
|
|
102
111
|
WorkflowRenderer,
|
|
103
112
|
PersistentVolumeRenderer,
|
|
@@ -155,12 +164,22 @@ import {
|
|
|
155
164
|
KyvernoMutatingPolicyRenderer,
|
|
156
165
|
KyvernoGeneratingPolicyRenderer,
|
|
157
166
|
KyvernoDeletingPolicyRenderer,
|
|
167
|
+
CNPGObjectStoreRenderer,
|
|
168
|
+
CNPGDatabaseRenderer,
|
|
169
|
+
CNPGPublicationRenderer,
|
|
170
|
+
CNPGSubscriptionRenderer,
|
|
171
|
+
CNPGImageCatalogRenderer,
|
|
172
|
+
KyvernoGlobalContextRenderer,
|
|
173
|
+
KyvernoUpdateRequestRenderer,
|
|
174
|
+
KyvernoEphemeralReportRenderer,
|
|
175
|
+
getKyvernoGlobalContextStatus,
|
|
158
176
|
KyvernoPolicyExceptionRenderer,
|
|
159
177
|
KyvernoCleanupPolicyRenderer,
|
|
160
178
|
VeleroBackupRenderer,
|
|
161
179
|
VeleroRestoreRenderer,
|
|
162
180
|
VeleroScheduleRenderer,
|
|
163
181
|
VeleroBSLRenderer,
|
|
182
|
+
VeleroBackupRepositoryRenderer,
|
|
164
183
|
VeleroVSLRenderer,
|
|
165
184
|
CNPGClusterRenderer,
|
|
166
185
|
CNPGBackupRenderer,
|
|
@@ -239,6 +258,10 @@ import {
|
|
|
239
258
|
ResourceSliceRenderer,
|
|
240
259
|
NvidiaClusterPolicyRenderer,
|
|
241
260
|
NvidiaDriverRenderer,
|
|
261
|
+
CalicoHostEndpointRenderer,
|
|
262
|
+
CalicoIPPoolRenderer,
|
|
263
|
+
CalicoNetworkPolicyRenderer,
|
|
264
|
+
CalicoTierRenderer,
|
|
242
265
|
} from '../resources/renderers'
|
|
243
266
|
import type { ComposedRefStatus } from '../resources/renderers/CompositeRenderer'
|
|
244
267
|
import {
|
|
@@ -295,6 +318,48 @@ export interface RendererOverrides {
|
|
|
295
318
|
onNavigate?: (ref: ResourceRef) => void
|
|
296
319
|
composedRefStatuses?: Map<string, ComposedRefStatus>
|
|
297
320
|
}>
|
|
321
|
+
// CNPG Publication / Subscription: the host resolves the PostgreSQL-side
|
|
322
|
+
// names in their spec back to the CRs that declare them. Database and
|
|
323
|
+
// ImageCatalog get the reverse lookup, which the API only models one way.
|
|
324
|
+
CNPGImageCatalogRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
325
|
+
CNPGDatabaseRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
326
|
+
CNPGPublicationRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
327
|
+
CNPGSubscriptionRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
328
|
+
// CNPG Cluster: the host wraps it to add the reverse lookup of declarative
|
|
329
|
+
// objects, which needs three list fetches.
|
|
330
|
+
CNPGClusterRenderer?: React.ComponentType<{
|
|
331
|
+
data: any
|
|
332
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
333
|
+
}>
|
|
334
|
+
// CNPG ObjectStore: the host wraps the package renderer to add the reverse
|
|
335
|
+
// lookup (which Clusters back up here), which needs a Cluster list fetch.
|
|
336
|
+
CNPGObjectStoreRenderer?: React.ComponentType<{
|
|
337
|
+
data: any
|
|
338
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
339
|
+
}>
|
|
340
|
+
/** Host-injected: adds the Backups-stored-here lookup to a storage location. */
|
|
341
|
+
VeleroBSLRenderer?: React.ComponentType<{
|
|
342
|
+
data: any
|
|
343
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
344
|
+
}>
|
|
345
|
+
/** Host-injected: adds the storage location's health to a backup, and the
|
|
346
|
+
* on-demand fetch for the messages behind its error/warning counts. */
|
|
347
|
+
VeleroBackupRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
348
|
+
/** Host-injected: adds the on-demand fetch for the messages behind a
|
|
349
|
+
* restore's error and warning counts. */
|
|
350
|
+
VeleroRestoreRenderer?: React.ComponentType<{ data: any; onNavigate?: (ref: ResourceRef) => void }>
|
|
351
|
+
// Kyverno policy coverage: the host fetches /api/policy/policies/... and
|
|
352
|
+
// renders the section, which the policy renderers accept as a slot. One
|
|
353
|
+
// override serves all six policy renderers — they differ in what the policy
|
|
354
|
+
// declares, not in what its results look like.
|
|
355
|
+
KyvernoPolicyCoverage?: React.ComponentType<{
|
|
356
|
+
data: any
|
|
357
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
358
|
+
}>
|
|
359
|
+
// Work a generate / mutate-existing policy has queued and not finished. The
|
|
360
|
+
// requests have their own page; the count belongs here because the failure
|
|
361
|
+
// this catches is a backlog, and nobody watches a page that is usually empty.
|
|
362
|
+
KyvernoPolicyQueued?: React.ComponentType<{ data: any }>
|
|
298
363
|
// ServiceAccount reverse-lookup: the host fetches /api/rbac/subject/... and
|
|
299
364
|
// feeds the result into the base renderer via this wrapper.
|
|
300
365
|
ServiceAccountRenderer?: React.ComponentType<{
|
|
@@ -334,6 +399,12 @@ export interface RendererOverrides {
|
|
|
334
399
|
data: any
|
|
335
400
|
onNavigate?: (ref: ResourceRef) => void
|
|
336
401
|
}>
|
|
402
|
+
// Rollout: host probes /api/rollouts/.../capabilities and wires the
|
|
403
|
+
// promote / abort / skip-step mutations into the action row.
|
|
404
|
+
RolloutRenderer?: React.ComponentType<{
|
|
405
|
+
data: any
|
|
406
|
+
onNavigate?: (ref: ResourceRef) => void
|
|
407
|
+
}>
|
|
337
408
|
}
|
|
338
409
|
|
|
339
410
|
// Known resource types with specific renderers (module-level to avoid re-allocation)
|
|
@@ -341,11 +412,15 @@ const KNOWN_KINDS = new Set([
|
|
|
341
412
|
'pods', 'deployments', 'statefulsets', 'daemonsets', 'replicasets',
|
|
342
413
|
'services', 'endpointslices', 'ingresses', 'configmaps', 'secrets', 'jobs', 'cronjobs', 'cronworkflows',
|
|
343
414
|
'hpas', 'horizontalpodautoscalers', 'nodes', 'persistentvolumeclaims',
|
|
344
|
-
'rollouts', 'certificates', 'workflows', 'persistentvolumes',
|
|
415
|
+
'rollouts', 'analysisruns', 'certificates', 'workflows', 'persistentvolumes',
|
|
345
416
|
'storageclasses', 'certificaterequests', 'clusterissuers', 'issuers',
|
|
346
417
|
'orders', 'challenges',
|
|
347
418
|
'gateways', 'gatewayclasses', 'httproutes', 'grpcroutes', 'tcproutes', 'tlsroutes', 'sealedsecrets', 'workflowtemplates', 'clusterworkflowtemplates',
|
|
348
419
|
'networkpolicies', 'networkpolicy',
|
|
420
|
+
'globalnetworkpolicies', 'globalnetworkpolicy',
|
|
421
|
+
'stagednetworkpolicies', 'stagednetworkpolicy',
|
|
422
|
+
'stagedglobalnetworkpolicies', 'stagedglobalnetworkpolicy',
|
|
423
|
+
'stagedkubernetesnetworkpolicies', 'stagedkubernetesnetworkpolicy',
|
|
349
424
|
'ciliumnetworkpolicies', 'ciliumnetworkpolicy', 'ciliumclusterwidenetworkpolicies', 'ciliumclusterwidenetworkpolicy',
|
|
350
425
|
'clusternetworkpolicies', 'clusternetworkpolicy',
|
|
351
426
|
'poddisruptionbudgets', 'serviceaccounts', 'namespaces',
|
|
@@ -356,6 +431,10 @@ const KNOWN_KINDS = new Set([
|
|
|
356
431
|
'triggerauthentications', 'clustertriggerauthentications',
|
|
357
432
|
'servicemonitors', 'prometheusrules', 'podmonitors',
|
|
358
433
|
'policyreports', 'clusterpolicyreports', 'kyvernopolicies', 'clusterpolicies',
|
|
434
|
+
// The API serves the legacy namespaced kind as `policies`. `kyvernopolicies`
|
|
435
|
+
// is Radar's internal alias for it and is NOT a servable plural, so a URL
|
|
436
|
+
// built from it 400s — the drawer has to know the real one.
|
|
437
|
+
'policies',
|
|
359
438
|
// Kyverno modern CEL family (policies.kyverno.io) + its namespaced twins.
|
|
360
439
|
'validatingpolicies', 'namespacedvalidatingpolicies',
|
|
361
440
|
'imagevalidatingpolicies', 'namespacedimagevalidatingpolicies',
|
|
@@ -365,14 +444,18 @@ const KNOWN_KINDS = new Set([
|
|
|
365
444
|
'policyexceptions', 'cleanuppolicies', 'clustercleanuppolicies',
|
|
366
445
|
'resourceclaims', 'resourceclaimtemplates', 'deviceclasses', 'resourceslices',
|
|
367
446
|
'nvidiadrivers',
|
|
447
|
+
'hostendpoints', 'ippools', 'tiers',
|
|
368
448
|
'vulnerabilityreports', 'configauditreports', 'exposedsecretreports',
|
|
369
449
|
'rbacassessmentreports', 'clusterrbacassessmentreports',
|
|
370
450
|
'clustercompliancereports', 'sbomreports', 'clustersbomreports',
|
|
371
451
|
'infraassessmentreports', 'clusterinfraassessmentreports',
|
|
372
452
|
'verticalpodautoscalers',
|
|
373
453
|
'backups', 'restores', 'schedules', 'backupstoragelocations', 'volumesnapshotlocations',
|
|
454
|
+
'backuprepositories',
|
|
374
455
|
'externalsecrets', 'clusterexternalsecrets', 'secretstores', 'clustersecretstores',
|
|
375
|
-
'clusters', 'scheduledbackups', 'poolers',
|
|
456
|
+
'clusters', 'scheduledbackups', 'poolers', 'objectstores',
|
|
457
|
+
'globalcontextentries', 'updaterequests', 'ephemeralreports', 'clusterephemeralreports',
|
|
458
|
+
'databases', 'publications', 'imagecatalogs', 'clusterimagecatalogs',
|
|
376
459
|
'virtualservices', 'destinationrules', 'serviceentries',
|
|
377
460
|
'peerauthentications', 'authorizationpolicies',
|
|
378
461
|
'mutatingwebhookconfigurations', 'validatingwebhookconfigurations',
|
|
@@ -544,6 +627,7 @@ export function ResourceRendererDispatch({
|
|
|
544
627
|
const isVeleroCollisionGatedKind =
|
|
545
628
|
kind === 'restores' || kind === 'schedules'
|
|
546
629
|
|| kind === 'backupstoragelocations' || kind === 'volumesnapshotlocations'
|
|
630
|
+
|| kind === 'backuprepositories'
|
|
547
631
|
const veleroCollisionFallthrough = isVeleroCollisionGatedKind && !isVeleroResource(data)
|
|
548
632
|
|
|
549
633
|
// Same rule as the Crossplane block above, for the plurals shared by two
|
|
@@ -551,15 +635,43 @@ export function ResourceRendererDispatch({
|
|
|
551
635
|
// and friends in the wild) and `backups` (CNPG / Velero). Both render lines
|
|
552
636
|
// are positively apiVersion-gated, so a third CRD with the plural matches
|
|
553
637
|
// neither and needs an explicit fall-through or the drawer renders blank.
|
|
638
|
+
//
|
|
639
|
+
// The CNPG declarative kinds and the barman-cloud ObjectStore extend the same
|
|
640
|
+
// list: `databases`, `publications` and `subscriptions` are shipped by several
|
|
641
|
+
// database operators, `objectstores` is a generic enough plural for any of
|
|
642
|
+
// them, and `subscriptions` is Knative's as well. Adding a kind to KNOWN_KINDS
|
|
643
|
+
// with a positively-gated render line and forgetting this list is what makes a
|
|
644
|
+
// foreign CRD render a BLANK drawer rather than the generic one.
|
|
554
645
|
const isGroupGatedKind =
|
|
555
646
|
kind === 'clusters' || kind === 'backups' || kind === 'scheduledbackups' || kind === 'poolers'
|
|
647
|
+
|| kind === 'objectstores' || kind === 'databases' || kind === 'publications'
|
|
648
|
+
|| kind === 'subscriptions' || kind === 'imagecatalogs' || kind === 'clusterimagecatalogs'
|
|
649
|
+
|| kind === 'policies'
|
|
556
650
|
const isCNPGApiVersion = isApiGroup(data?.apiVersion, CNPG_GROUP)
|
|
557
651
|
const groupGatedMatched =
|
|
558
652
|
(kind === 'clusters' && (isCNPGApiVersion || isApiGroup(data?.apiVersion, 'cluster.x-k8s.io')))
|
|
559
653
|
|| (kind === 'backups' && (isCNPGApiVersion || isApiGroup(data?.apiVersion, 'velero.io')))
|
|
560
654
|
|| ((kind === 'scheduledbackups' || kind === 'poolers') && isCNPGApiVersion)
|
|
655
|
+
|| (kind === 'objectstores' && isApiGroup(data?.apiVersion, 'barmancloud.cnpg.io'))
|
|
656
|
+
|| ((kind === 'databases' || kind === 'publications' || kind === 'imagecatalogs'
|
|
657
|
+
|| kind === 'clusterimagecatalogs') && isCNPGApiVersion)
|
|
658
|
+
|| (kind === 'subscriptions'
|
|
659
|
+
&& (isCNPGApiVersion || isApiGroup(data?.apiVersion, 'messaging.knative.dev')))
|
|
660
|
+
|| (kind === 'policies' && isApiGroup(data?.apiVersion, 'kyverno.io'))
|
|
561
661
|
const groupGatedFallthrough = isGroupGatedKind && !groupGatedMatched
|
|
562
662
|
|
|
663
|
+
const calicoApiVersionMatched = isCalicoApiVersion(data?.apiVersion)
|
|
664
|
+
const isCalicoPolicy = isCalicoPolicyKind(kind) && calicoApiVersionMatched
|
|
665
|
+
const isCalicoStagedKubernetesPolicy =
|
|
666
|
+
isCalicoPolicy && isCalicoStagedKubernetesNetworkPolicyKind(kind)
|
|
667
|
+
const isCoreNetworkPolicy = isCoreNetworkPolicyKind(kind, data?.apiVersion, resource.group)
|
|
668
|
+
const isCalicoHostEndpoint = kind === 'hostendpoints' && calicoApiVersionMatched
|
|
669
|
+
const isCalicoIPPool = kind === 'ippools' && calicoApiVersionMatched
|
|
670
|
+
const isCalicoTier = kind === 'tiers' && calicoApiVersionMatched
|
|
671
|
+
const calicoCollisionFallthrough = (
|
|
672
|
+
isCalicoPolicyKind(kind) || kind === 'hostendpoints' || kind === 'ippools' || kind === 'tiers'
|
|
673
|
+
) && !isCoreNetworkPolicy && !((isCalicoPolicy || isCalicoHostEndpoint || isCalicoIPPool || isCalicoTier))
|
|
674
|
+
|
|
563
675
|
const isKnownKind = KNOWN_KINDS.has(kind) || isCrossplaneMR || isCrossplaneClaim || isCrossplaneXR
|
|
564
676
|
|
|
565
677
|
const PodComp = rendererOverrides?.PodRenderer ?? PodRenderer
|
|
@@ -568,12 +680,28 @@ export function ResourceRendererDispatch({
|
|
|
568
680
|
const NodeComp = rendererOverrides?.NodeRenderer ?? NodeRenderer
|
|
569
681
|
const ServiceComp = rendererOverrides?.ServiceRenderer ?? ServiceRenderer
|
|
570
682
|
const CompositeComp = rendererOverrides?.CompositeRenderer ?? CompositeRenderer
|
|
683
|
+
const CNPGClusterComp = rendererOverrides?.CNPGClusterRenderer ?? CNPGClusterRenderer
|
|
684
|
+
const CNPGImageCatalogComp = rendererOverrides?.CNPGImageCatalogRenderer ?? CNPGImageCatalogRenderer
|
|
685
|
+
const CNPGDatabaseComp = rendererOverrides?.CNPGDatabaseRenderer ?? CNPGDatabaseRenderer
|
|
686
|
+
const CNPGPublicationComp = rendererOverrides?.CNPGPublicationRenderer ?? CNPGPublicationRenderer
|
|
687
|
+
const CNPGSubscriptionComp = rendererOverrides?.CNPGSubscriptionRenderer ?? CNPGSubscriptionRenderer
|
|
688
|
+
const CNPGObjectStoreComp = rendererOverrides?.CNPGObjectStoreRenderer ?? CNPGObjectStoreRenderer
|
|
689
|
+
const VeleroBSLComp = rendererOverrides?.VeleroBSLRenderer ?? VeleroBSLRenderer
|
|
690
|
+
const VeleroBackupComp = rendererOverrides?.VeleroBackupRenderer ?? VeleroBackupRenderer
|
|
691
|
+
const VeleroRestoreComp = rendererOverrides?.VeleroRestoreRenderer ?? VeleroRestoreRenderer
|
|
692
|
+
const KyvernoCoverageComp = rendererOverrides?.KyvernoPolicyCoverage
|
|
693
|
+
const kyvernoCoverage = KyvernoCoverageComp ? (
|
|
694
|
+
<KyvernoCoverageComp data={data} onNavigate={onNavigate} />
|
|
695
|
+
) : undefined
|
|
696
|
+
const KyvernoQueuedComp = rendererOverrides?.KyvernoPolicyQueued
|
|
697
|
+
const kyvernoQueued = KyvernoQueuedComp ? <KyvernoQueuedComp data={data} /> : undefined
|
|
571
698
|
const ServiceAccountComp = rendererOverrides?.ServiceAccountRenderer ?? ServiceAccountRenderer
|
|
572
699
|
const RoleComp = rendererOverrides?.RoleRenderer ?? RoleRenderer
|
|
573
700
|
const RoleBindingComp = rendererOverrides?.RoleBindingRenderer ?? RoleBindingRenderer
|
|
574
701
|
const NamespaceComp = rendererOverrides?.NamespaceRenderer ?? NamespaceRenderer
|
|
575
702
|
const HPAComp = rendererOverrides?.HPARenderer ?? HPARenderer
|
|
576
703
|
const PVCComp = rendererOverrides?.PVCRenderer ?? PVCRenderer
|
|
704
|
+
const RolloutComp = rendererOverrides?.RolloutRenderer ?? RolloutRenderer
|
|
577
705
|
const scaleBlockedBy = replicaScalers(relationships?.scalers)
|
|
578
706
|
|
|
579
707
|
const sidebarContent = showCommonSections && (
|
|
@@ -613,7 +741,8 @@ export function ResourceRendererDispatch({
|
|
|
613
741
|
{(kind === 'hpas' || kind === 'horizontalpodautoscalers') && <HPAComp data={data} onNavigate={onNavigate} hpaDiagnosis={hpaDiagnosis} />}
|
|
614
742
|
{kind === 'nodes' && <NodeComp data={data} relationships={relationships} />}
|
|
615
743
|
{kind === 'persistentvolumeclaims' && <PVCComp data={data} onNavigate={onNavigate} />}
|
|
616
|
-
{kind === 'rollouts' && <
|
|
744
|
+
{kind === 'rollouts' && <RolloutComp data={data} onNavigate={onNavigate} />}
|
|
745
|
+
{kind === 'analysisruns' && <AnalysisRunRenderer data={data} onNavigate={onNavigate} />}
|
|
617
746
|
{kind === 'certificates' && !data?.apiVersion?.includes('networking.internal.knative.dev') && <CertificateRenderer data={data} />}
|
|
618
747
|
{kind === 'workflows' && <WorkflowRenderer data={data} onNavigate={onNavigate} />}
|
|
619
748
|
{kind === 'persistentvolumes' && <PersistentVolumeRenderer data={data} onNavigate={onNavigate} />}
|
|
@@ -631,7 +760,9 @@ export function ResourceRendererDispatch({
|
|
|
631
760
|
{kind === 'tlsroutes' && <SimpleRouteRenderer data={data} kind="TLSRoute" onNavigate={onNavigate} />}
|
|
632
761
|
{kind === 'sealedsecrets' && <SealedSecretRenderer data={data} onNavigate={onNavigate} />}
|
|
633
762
|
{(kind === 'workflowtemplates' || kind === 'clusterworkflowtemplates') && <WorkflowTemplateRenderer data={data} />}
|
|
634
|
-
{
|
|
763
|
+
{isCoreNetworkPolicy && <NetworkPolicyRenderer data={data} />}
|
|
764
|
+
{isCalicoStagedKubernetesPolicy && <NetworkPolicyRenderer data={data} staged />}
|
|
765
|
+
{isCalicoPolicy && !isCalicoStagedKubernetesPolicy && <CalicoNetworkPolicyRenderer data={data} onNavigate={onNavigate} />}
|
|
635
766
|
{(kind === 'ciliumnetworkpolicies' || kind === 'ciliumnetworkpolicy' || kind === 'ciliumclusterwidenetworkpolicies' || kind === 'ciliumclusterwidenetworkpolicy') && <CiliumNetworkPolicyRenderer data={data} />}
|
|
636
767
|
{(kind === 'clusternetworkpolicies' || kind === 'clusternetworkpolicy') && <ClusterNetworkPolicyRenderer data={data} />}
|
|
637
768
|
{kind === 'poddisruptionbudgets' && <PodDisruptionBudgetRenderer data={data} />}
|
|
@@ -664,33 +795,47 @@ export function ResourceRendererDispatch({
|
|
|
664
795
|
{kind === 'prometheusrules' && <PrometheusRuleRenderer data={data} />}
|
|
665
796
|
{kind === 'podmonitors' && <PodMonitorRenderer data={data} />}
|
|
666
797
|
{(kind === 'policyreports' || kind === 'clusterpolicyreports') && <PolicyReportRenderer data={data} />}
|
|
667
|
-
{(kind === 'kyvernopolicies'
|
|
798
|
+
{(kind === 'kyvernopolicies'
|
|
799
|
+
|| (kind === 'policies' && isApiGroup(data?.apiVersion, 'kyverno.io'))
|
|
800
|
+
|| (kind === 'clusterpolicies' && !data?.apiVersion?.startsWith('nvidia.com/'))) && <KyvernoPolicyRenderer data={data} coverage={kyvernoCoverage} queued={kyvernoQueued} />}
|
|
668
801
|
{(kind === 'clusterpolicies' && data?.apiVersion?.startsWith('nvidia.com/')) && <NvidiaClusterPolicyRenderer data={data} />}
|
|
669
802
|
{/* Kyverno modern CEL family. Each Namespaced* twin shares its
|
|
670
803
|
cluster-scoped counterpart's renderer — same spec, narrower scope. */}
|
|
671
|
-
{kyvernoModernMatched && (kind === 'validatingpolicies' || kind === 'namespacedvalidatingpolicies') && <KyvernoValidatingPolicyRenderer data={data} />}
|
|
672
|
-
{kyvernoModernMatched && (kind === 'imagevalidatingpolicies' || kind === 'namespacedimagevalidatingpolicies') && <KyvernoImageValidatingPolicyRenderer data={data} />}
|
|
673
|
-
{kyvernoModernMatched && (kind === 'mutatingpolicies' || kind === 'namespacedmutatingpolicies') && <KyvernoMutatingPolicyRenderer data={data} />}
|
|
674
|
-
{kyvernoModernMatched && (kind === 'generatingpolicies' || kind === 'namespacedgeneratingpolicies') && <KyvernoGeneratingPolicyRenderer data={data} />}
|
|
675
|
-
{kyvernoModernMatched && (kind === 'deletingpolicies' || kind === 'namespaceddeletingpolicies') && <KyvernoDeletingPolicyRenderer data={data} />}
|
|
804
|
+
{kyvernoModernMatched && (kind === 'validatingpolicies' || kind === 'namespacedvalidatingpolicies') && <KyvernoValidatingPolicyRenderer data={data} coverage={kyvernoCoverage} />}
|
|
805
|
+
{kyvernoModernMatched && (kind === 'imagevalidatingpolicies' || kind === 'namespacedimagevalidatingpolicies') && <KyvernoImageValidatingPolicyRenderer data={data} coverage={kyvernoCoverage} />}
|
|
806
|
+
{kyvernoModernMatched && (kind === 'mutatingpolicies' || kind === 'namespacedmutatingpolicies') && <KyvernoMutatingPolicyRenderer data={data} coverage={kyvernoCoverage} />}
|
|
807
|
+
{kyvernoModernMatched && (kind === 'generatingpolicies' || kind === 'namespacedgeneratingpolicies') && <KyvernoGeneratingPolicyRenderer data={data} coverage={kyvernoCoverage} />}
|
|
808
|
+
{kyvernoModernMatched && (kind === 'deletingpolicies' || kind === 'namespaceddeletingpolicies') && <KyvernoDeletingPolicyRenderer data={data} coverage={kyvernoCoverage} />}
|
|
809
|
+
{kind === 'globalcontextentries' && <KyvernoGlobalContextRenderer data={data} onNavigate={onNavigate} />}
|
|
810
|
+
{kind === 'updaterequests' && <KyvernoUpdateRequestRenderer data={data} onNavigate={onNavigate} />}
|
|
811
|
+
{(kind === 'ephemeralreports' || kind === 'clusterephemeralreports') && <KyvernoEphemeralReportRenderer data={data} onNavigate={onNavigate} />}
|
|
676
812
|
{policyExceptionMatched && <KyvernoPolicyExceptionRenderer data={data} />}
|
|
677
813
|
{kyvernoLegacyExtraMatched && <KyvernoCleanupPolicyRenderer data={data} />}
|
|
678
814
|
{kind === 'nvidiadrivers' && <NvidiaDriverRenderer data={data} />}
|
|
815
|
+
{isCalicoHostEndpoint && <CalicoHostEndpointRenderer data={data} onNavigate={onNavigate} />}
|
|
816
|
+
{isCalicoIPPool && <CalicoIPPoolRenderer data={data} />}
|
|
817
|
+
{isCalicoTier && <CalicoTierRenderer data={data} />}
|
|
679
818
|
{/* DRA (resource.k8s.io) */}
|
|
680
819
|
{kind === 'resourceclaims' && <ResourceClaimRenderer data={data} onNavigate={onNavigate} />}
|
|
681
820
|
{kind === 'resourceclaimtemplates' && <ResourceClaimTemplateRenderer data={data} />}
|
|
682
821
|
{kind === 'deviceclasses' && <DeviceClassRenderer data={data} />}
|
|
683
822
|
{kind === 'resourceslices' && <ResourceSliceRenderer data={data} onNavigate={onNavigate} />}
|
|
823
|
+
{kind === 'objectstores' && isApiGroup(data.apiVersion, 'barmancloud.cnpg.io') && <CNPGObjectStoreComp data={data} onNavigate={onNavigate} />}
|
|
824
|
+
{kind === 'databases' && isApiGroup(data.apiVersion, CNPG_GROUP) && <CNPGDatabaseComp data={data} onNavigate={onNavigate} />}
|
|
825
|
+
{kind === 'publications' && isApiGroup(data.apiVersion, CNPG_GROUP) && <CNPGPublicationComp data={data} onNavigate={onNavigate} />}
|
|
826
|
+
{kind === 'subscriptions' && isApiGroup(data.apiVersion, CNPG_GROUP) && <CNPGSubscriptionComp data={data} onNavigate={onNavigate} />}
|
|
827
|
+
{(kind === 'imagecatalogs' || kind === 'clusterimagecatalogs') && isApiGroup(data.apiVersion, CNPG_GROUP) && <CNPGImageCatalogComp data={data} onNavigate={onNavigate} />}
|
|
684
828
|
{kind === 'backups' && isApiGroup(data.apiVersion, CNPG_GROUP) && <CNPGBackupRenderer data={data} onNavigate={onNavigate} />}
|
|
685
|
-
{kind === 'backups' && isApiGroup(data.apiVersion, 'velero.io') && <
|
|
686
|
-
{kind === 'restores' && isVeleroResource(data) && <
|
|
687
|
-
{kind === 'schedules' && isVeleroResource(data) && <VeleroScheduleRenderer data={data} />}
|
|
688
|
-
{kind === 'backupstoragelocations' && isVeleroResource(data) && <
|
|
829
|
+
{kind === 'backups' && isApiGroup(data.apiVersion, 'velero.io') && <VeleroBackupComp data={data} onNavigate={onNavigate} />}
|
|
830
|
+
{kind === 'restores' && isVeleroResource(data) && <VeleroRestoreComp data={data} onNavigate={onNavigate} />}
|
|
831
|
+
{kind === 'schedules' && isVeleroResource(data) && <VeleroScheduleRenderer data={data} onNavigate={onNavigate} />}
|
|
832
|
+
{kind === 'backupstoragelocations' && isVeleroResource(data) && <VeleroBSLComp data={data} onNavigate={onNavigate} />}
|
|
833
|
+
{kind === 'backuprepositories' && isVeleroResource(data) && <VeleroBackupRepositoryRenderer data={data} onNavigate={onNavigate} />}
|
|
689
834
|
{kind === 'volumesnapshotlocations' && isVeleroResource(data) && <VeleroVSLRenderer data={data} />}
|
|
690
835
|
{kind === 'externalsecrets' && <ExternalSecretRenderer data={data} onNavigate={onNavigate} />}
|
|
691
836
|
{kind === 'clusterexternalsecrets' && <ClusterExternalSecretRenderer data={data} onNavigate={onNavigate} />}
|
|
692
837
|
{(kind === 'secretstores' || kind === 'clustersecretstores') && <SecretStoreRenderer data={data} />}
|
|
693
|
-
{kind === 'clusters' && isApiGroup(data?.apiVersion, CNPG_GROUP) && <
|
|
838
|
+
{kind === 'clusters' && isApiGroup(data?.apiVersion, CNPG_GROUP) && <CNPGClusterComp data={data} onNavigate={onNavigate} />}
|
|
694
839
|
{kind === 'clusters' && isApiGroup(data?.apiVersion, 'cluster.x-k8s.io') && <CAPIClusterRenderer data={data} onNavigate={onNavigate} />}
|
|
695
840
|
{kind === 'scheduledbackups' && isApiGroup(data?.apiVersion, CNPG_GROUP) && <CNPGScheduledBackupRenderer data={data} onNavigate={onNavigate} />}
|
|
696
841
|
{kind === 'poolers' && isApiGroup(data?.apiVersion, CNPG_GROUP) && <CNPGPoolerRenderer data={data} onNavigate={onNavigate} />}
|
|
@@ -757,7 +902,9 @@ export function ResourceRendererDispatch({
|
|
|
757
902
|
{kind === 'eventtypes' && <EventTypeRenderer data={data} />}
|
|
758
903
|
{kind === 'channels' && <ChannelRenderer data={data} onNavigate={onNavigate} />}
|
|
759
904
|
{kind === 'inmemorychannels' && <InMemoryChannelRenderer data={data} onNavigate={onNavigate} />}
|
|
760
|
-
{
|
|
905
|
+
{/* Group-guarded: CNPG serves a `subscriptions` plural too, and without
|
|
906
|
+
this an unrelated PostgreSQL Subscription rendered Knative's sections. */}
|
|
907
|
+
{kind === 'subscriptions' && isApiGroup(data.apiVersion, 'messaging.knative.dev') && <SubscriptionRenderer data={data} onNavigate={onNavigate} />}
|
|
761
908
|
{kind === 'sequences' && <SequenceRenderer data={data} onNavigate={onNavigate} />}
|
|
762
909
|
{kind === 'parallels' && <ParallelRenderer data={data} onNavigate={onNavigate} />}
|
|
763
910
|
|
|
@@ -787,7 +934,7 @@ export function ResourceRendererDispatch({
|
|
|
787
934
|
for known-plural collisions where no apiVersion-gated renderer
|
|
788
935
|
matched (e.g. a Knative Configuration sharing the `configurations`
|
|
789
936
|
plural with Crossplane Configuration). */}
|
|
790
|
-
{(!isKnownKind || crossplaneCollisionFallthrough || kyvernoCollisionFallthrough || veleroCollisionFallthrough || groupGatedFallthrough) && <GenericRenderer data={data} />}
|
|
937
|
+
{(!isKnownKind || crossplaneCollisionFallthrough || kyvernoCollisionFallthrough || veleroCollisionFallthrough || groupGatedFallthrough || calicoCollisionFallthrough) && <GenericRenderer data={data} />}
|
|
791
938
|
|
|
792
939
|
{/* Common sections - can be disabled when parent handles them separately */}
|
|
793
940
|
{showCommonSections && (
|
|
@@ -865,6 +1012,7 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
865
1012
|
if (k === 'nodes') return getNodeStatus(data)
|
|
866
1013
|
if (k === 'persistentvolumeclaims') return getPVCStatus(data)
|
|
867
1014
|
if (k === 'rollouts') return getRolloutStatus(data)
|
|
1015
|
+
if (k === 'analysisruns') return getAnalysisRunStatus(data)
|
|
868
1016
|
if (k === 'workflows') return getWorkflowStatus(data)
|
|
869
1017
|
if (k === 'cronworkflows') return getCronWorkflowStatus(data)
|
|
870
1018
|
if (k === 'certificates') {
|
|
@@ -910,7 +1058,8 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
910
1058
|
if (k === 'clustercompliancereports') return getClusterComplianceReportStatus(data)
|
|
911
1059
|
if (k === 'sbomreports' || k === 'clustersbomreports') return getSbomReportStatus(data)
|
|
912
1060
|
if (k === 'policyreports' || k === 'clusterpolicyreports') return getPolicyReportStatus(data)
|
|
913
|
-
if (k === 'kyvernopolicies' || k === 'clusterpolicies'
|
|
1061
|
+
if (k === 'kyvernopolicies' || k === 'clusterpolicies'
|
|
1062
|
+
|| (k === 'policies' && isApiGroup(data.apiVersion, 'kyverno.io'))) {
|
|
914
1063
|
if (data?.apiVersion?.startsWith('nvidia.com/')) return getNvidiaClusterPolicyStatus(data)
|
|
915
1064
|
return getKyvernoPolicyStatus(data)
|
|
916
1065
|
}
|
|
@@ -934,9 +1083,28 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
934
1083
|
if (isApiGroup(data.apiVersion, CNPG_GROUP)) return getCNPGBackupStatus(data)
|
|
935
1084
|
if (isApiGroup(data.apiVersion, 'velero.io')) return getBackupStatus(data)
|
|
936
1085
|
}
|
|
1086
|
+
// Group-guarded: `objectstores` is a generic plural another operator could
|
|
1087
|
+
// claim, and a foreign CR must not borrow CNPG's recovery-window semantics.
|
|
1088
|
+
if (k === 'objectstores' && isApiGroup(data.apiVersion, 'barmancloud.cnpg.io')) {
|
|
1089
|
+
return getCNPGObjectStoreStatus(data)
|
|
1090
|
+
}
|
|
1091
|
+
// Group-guarded for the same reason as the renderers: these plurals are
|
|
1092
|
+
// generic enough that another operator can serve them.
|
|
1093
|
+
if ((k === 'databases' || k === 'publications' || k === 'subscriptions') && isApiGroup(data.apiVersion, CNPG_GROUP)) {
|
|
1094
|
+
return getCNPGDeclarativeStatus(data)
|
|
1095
|
+
}
|
|
1096
|
+
if (k === 'globalcontextentries') return getKyvernoGlobalContextStatus(data)
|
|
1097
|
+
if (k === 'updaterequests') return getKyvernoRequestState(data)
|
|
1098
|
+
if (k === 'ephemeralreports' || k === 'clusterephemeralreports') return getKyvernoReportStatus(data)
|
|
937
1099
|
if (k === 'restores' && isVeleroResource(data)) return getRestoreStatus(data)
|
|
938
1100
|
if (k === 'schedules' && isVeleroResource(data)) return getScheduleStatus(data)
|
|
939
1101
|
if (k === 'backupstoragelocations' && isVeleroResource(data)) return getBSLStatus(data)
|
|
1102
|
+
// Repositories have table columns and raise their own issue, but had no branch
|
|
1103
|
+
// here — so the drawer header fell through to the raw phase and showed
|
|
1104
|
+
// "NotReady" beside a table cell reading "Not ready". Same object, two
|
|
1105
|
+
// spellings. Deliberately NOT added to KNOWN_KINDS: there is no detail
|
|
1106
|
+
// renderer for this kind, and listing it there suppresses GenericRenderer.
|
|
1107
|
+
if (k === 'backuprepositories' && isVeleroResource(data)) return getBackupRepositoryStatus(data)
|
|
940
1108
|
if (k === 'externalsecrets') return getExternalSecretStatus(data)
|
|
941
1109
|
if (k === 'clusterexternalsecrets') return getClusterExternalSecretStatus(data)
|
|
942
1110
|
if (k === 'secretstores') return getSecretStoreStatus(data)
|
|
@@ -1007,11 +1175,20 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
1007
1175
|
'knativeservices', 'knativeconfigurations', 'knativeroutes',
|
|
1008
1176
|
'brokers', 'triggers',
|
|
1009
1177
|
'pingsources', 'apiserversources', 'containersources', 'sinkbindings',
|
|
1010
|
-
'channels', 'inmemorychannels',
|
|
1178
|
+
'channels', 'inmemorychannels',
|
|
1011
1179
|
'sequences', 'parallels',
|
|
1012
1180
|
'domainmappings', 'knativeingresses', 'knativecertificates', 'serverlessservices',
|
|
1013
1181
|
]
|
|
1014
|
-
|
|
1182
|
+
// `subscriptions` is shared with CNPG (handled above) and with any number of
|
|
1183
|
+
// other operators, so it is matched by group rather than by name — reading a
|
|
1184
|
+
// foreign CRD's conditions as Knative's is the status half of the same
|
|
1185
|
+
// collision the renderers guard.
|
|
1186
|
+
const isKnativeSubscription = k === 'subscriptions' && isApiGroup(data.apiVersion, 'messaging.knative.dev')
|
|
1187
|
+
if (
|
|
1188
|
+
knativeConditionKinds.includes(k)
|
|
1189
|
+
|| isKnativeSubscription
|
|
1190
|
+
|| (k === 'ingresses' && data.apiVersion?.includes('networking.internal.knative.dev'))
|
|
1191
|
+
) {
|
|
1015
1192
|
const status = getKnativeConditionStatus(data)
|
|
1016
1193
|
return { text: status.text, color: status.color }
|
|
1017
1194
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ResourceRendererDispatch, getResourceStatus, type RendererOverrides } from './ResourceRendererDispatch'
|
|
2
2
|
export { EditableYamlView, SaveSuccessAnimation } from './EditableYamlView'
|
|
3
|
-
export { ResourceActionsBar, RevisionHistoryDialog } from './ResourceActionsBar'
|
|
3
|
+
export { ResourceActionsBar, RevisionHistoryDialog, isRolloutKind } from './ResourceActionsBar'
|
|
4
4
|
export { CreateResourceDialog, type CreateResourceDialogProps, type ApplyResult } from './CreateResourceDialog'
|
|
5
5
|
export { HelmManagedByChip, ManagedByChip, type HelmOwnerRef } from './ManagedByChip'
|
|
6
6
|
export { DetailShell, type DetailShellProps, type DetailShellTab } from './DetailShell'
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
completePromoteAfterRollback,
|
|
4
|
+
offersPromoteAfterRollback,
|
|
5
|
+
revisionRoleBadges,
|
|
6
|
+
} from './ResourceActionsBar'
|
|
7
|
+
import type { WorkloadRevision } from '../../types/core'
|
|
8
|
+
|
|
9
|
+
describe('offersPromoteAfterRollback', () => {
|
|
10
|
+
it('offers the option for both promotion styles — rollback alone lands neither', () => {
|
|
11
|
+
expect(offersPromoteAfterRollback('rollouts', true)).toBe(true)
|
|
12
|
+
expect(offersPromoteAfterRollback('Rollout', true)).toBe(true)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('withholds it when the host reports promote-full is denied', () => {
|
|
16
|
+
expect(offersPromoteAfterRollback('rollouts', false)).toBe(false)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('never offers it for plain workloads, whose rollback lands immediately', () => {
|
|
20
|
+
for (const kind of ['deployments', 'statefulsets', 'daemonsets']) {
|
|
21
|
+
expect(offersPromoteAfterRollback(kind, true)).toBe(false)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
function revision(overrides: Partial<WorkloadRevision>): WorkloadRevision {
|
|
27
|
+
return { number: 1, image: 'web:v1', createdAt: '2026-08-07T00:00:00Z', ...overrides }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('revisionRoleBadges', () => {
|
|
31
|
+
it('labels a Deployment revision Current in the healthy tone', () => {
|
|
32
|
+
expect(revisionRoleBadges(revision({ isCurrent: true }), false)).toEqual([
|
|
33
|
+
{ label: 'Current', tone: 'status-healthy' },
|
|
34
|
+
])
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('gives a non-current revision no badge', () => {
|
|
38
|
+
expect(revisionRoleBadges(revision({}), false)).toEqual([])
|
|
39
|
+
expect(revisionRoleBadges(revision({}), true)).toEqual([])
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('splits Rolling out from Stable while a canary is mid-flight', () => {
|
|
43
|
+
const rolling = revisionRoleBadges(revision({ number: 5, isCurrent: true, isStable: false }), true)
|
|
44
|
+
expect(rolling).toEqual([{ label: 'Rolling out', tone: 'status-degraded' }])
|
|
45
|
+
|
|
46
|
+
const stable = revisionRoleBadges(revision({ number: 4, isStable: true }), true)
|
|
47
|
+
expect(stable).toEqual([
|
|
48
|
+
{ label: 'Stable', tone: 'status-healthy', tip: 'Serving stable traffic — an abort reverts here' },
|
|
49
|
+
])
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('collapses to a single Current badge once the canary stabilizes', () => {
|
|
53
|
+
expect(revisionRoleBadges(revision({ isCurrent: true, isStable: true }), true)).toEqual([
|
|
54
|
+
{ label: 'Current', tone: 'status-healthy' },
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// A Rollout paused at step 0 reports current and stable as the same revision.
|
|
59
|
+
it('never emits both Stable and Rolling out for one revision', () => {
|
|
60
|
+
for (const isStable of [true, false, undefined]) {
|
|
61
|
+
const labels = revisionRoleBadges(revision({ isCurrent: true, isStable }), true).map((b) => b.label)
|
|
62
|
+
expect(labels).not.toContain('Stable')
|
|
63
|
+
expect(labels).toHaveLength(1)
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('completePromoteAfterRollback', () => {
|
|
69
|
+
it('does not resolve until promote-full settles', async () => {
|
|
70
|
+
let release: () => void = () => {}
|
|
71
|
+
const gate = new Promise<void>((resolve) => {
|
|
72
|
+
release = resolve
|
|
73
|
+
})
|
|
74
|
+
const pending: boolean[] = []
|
|
75
|
+
|
|
76
|
+
let done = false
|
|
77
|
+
const run = completePromoteAfterRollback(
|
|
78
|
+
() => gate,
|
|
79
|
+
(p) => pending.push(p),
|
|
80
|
+
).then(() => {
|
|
81
|
+
done = true
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Yield the microtask queue: if it did not await, done would already be true.
|
|
85
|
+
await Promise.resolve()
|
|
86
|
+
expect(done).toBe(false)
|
|
87
|
+
expect(pending).toEqual([true])
|
|
88
|
+
|
|
89
|
+
release()
|
|
90
|
+
await run
|
|
91
|
+
expect(done).toBe(true)
|
|
92
|
+
expect(pending).toEqual([true, false])
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// A rejected promote must not stop the dialog from closing — the rollback itself
|
|
96
|
+
// already succeeded, and the failure is reported by the mutation's toast.
|
|
97
|
+
it('swallows a promote-full rejection and clears the pending flag', async () => {
|
|
98
|
+
const pending: boolean[] = []
|
|
99
|
+
await expect(
|
|
100
|
+
completePromoteAfterRollback(
|
|
101
|
+
() => Promise.reject(new Error('403 forbidden')),
|
|
102
|
+
(p) => pending.push(p),
|
|
103
|
+
),
|
|
104
|
+
).resolves.toBeUndefined()
|
|
105
|
+
expect(pending).toEqual([true, false])
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('supports a void-returning callback', async () => {
|
|
109
|
+
const pending: boolean[] = []
|
|
110
|
+
let called = false
|
|
111
|
+
await completePromoteAfterRollback(
|
|
112
|
+
() => {
|
|
113
|
+
called = true
|
|
114
|
+
},
|
|
115
|
+
(p) => pending.push(p),
|
|
116
|
+
)
|
|
117
|
+
expect(called).toBe(true)
|
|
118
|
+
expect(pending).toEqual([true, false])
|
|
119
|
+
})
|
|
120
|
+
})
|
|
@@ -8,4 +8,14 @@ describe('baseSubtitle', () => {
|
|
|
8
8
|
expect(baseSubtitle('ServiceAccount', {})).toBe('Workload identity')
|
|
9
9
|
expect(baseSubtitle('ServiceMonitor', { endpointCount: 1 })).toBe('1 scrape endpoint')
|
|
10
10
|
})
|
|
11
|
+
|
|
12
|
+
it('describes a Calico staged deletion as a removal, not as selecting everything', () => {
|
|
13
|
+
// A staged deletion carries no selector, because the Calico API forbids one.
|
|
14
|
+
// Falling through to the empty-selector default would label the broadest
|
|
15
|
+
// possible protection onto a policy that is being taken away.
|
|
16
|
+
expect(baseSubtitle('CalicoStagedNetworkPolicy', { stagedAction: 'Delete' })).toBe('staged deletion')
|
|
17
|
+
expect(baseSubtitle('CalicoStagedGlobalNetworkPolicy', { stagedAction: 'Delete' })).toBe('staged deletion')
|
|
18
|
+
expect(baseSubtitle('CalicoStagedNetworkPolicy', { stagedAction: 'Set', selector: "app == 'web'" })).toBe("app == 'web'")
|
|
19
|
+
expect(baseSubtitle('CalicoNetworkPolicy', {})).toBe('all workloads')
|
|
20
|
+
})
|
|
11
21
|
})
|
|
@@ -249,6 +249,11 @@ export const NODE_DIMENSIONS: Record<
|
|
|
249
249
|
KubeadmControlPlane: { width: 300, height: 84 },
|
|
250
250
|
ClusterClass: { width: 280, height: 84 },
|
|
251
251
|
MachineHealthCheck: { width: 300, height: 84 },
|
|
252
|
+
CalicoNetworkPolicy: { width: 300, height: 84 },
|
|
253
|
+
CalicoGlobalNetworkPolicy: { width: 300, height: 84 },
|
|
254
|
+
CalicoStagedNetworkPolicy: { width: 300, height: 84 },
|
|
255
|
+
CalicoStagedGlobalNetworkPolicy: { width: 300, height: 84 },
|
|
256
|
+
CalicoStagedKubernetesNetworkPolicy: { width: 300, height: 84 },
|
|
252
257
|
};
|
|
253
258
|
|
|
254
259
|
// Status indicator color (for dot and left bar) - uses centralized severity colors
|
|
@@ -367,6 +372,18 @@ export function baseSubtitle(kind: NodeKind, nodeData: Record<string, unknown>):
|
|
|
367
372
|
const port = nodeData.port;
|
|
368
373
|
return port ? `${svcType} :${port}` : svcType;
|
|
369
374
|
}
|
|
375
|
+
case "CalicoNetworkPolicy":
|
|
376
|
+
case "CalicoGlobalNetworkPolicy":
|
|
377
|
+
case "CalicoStagedNetworkPolicy":
|
|
378
|
+
case "CalicoStagedGlobalNetworkPolicy":
|
|
379
|
+
case "CalicoStagedKubernetesNetworkPolicy": {
|
|
380
|
+
// A staged deletion carries no selector; reading that as "all workloads"
|
|
381
|
+
// would show a removal as the broadest possible protection.
|
|
382
|
+
if (String(nodeData.stagedAction ?? "").toLowerCase() === "delete") {
|
|
383
|
+
return "staged deletion";
|
|
384
|
+
}
|
|
385
|
+
return (nodeData.selector as string) || "all workloads";
|
|
386
|
+
}
|
|
370
387
|
case "Ingress":
|
|
371
388
|
return (nodeData.hostname as string) || "No host";
|
|
372
389
|
case "Gateway": {
|
|
@@ -443,6 +460,11 @@ export function baseSubtitle(kind: NodeKind, nodeData: Record<string, unknown>):
|
|
|
443
460
|
const instanceType = nodeData.instanceType as string;
|
|
444
461
|
return instanceType || "";
|
|
445
462
|
}
|
|
463
|
+
case "AnalysisRun": {
|
|
464
|
+
const phase = (nodeData.phase as string) || "Unknown";
|
|
465
|
+
const trigger = nodeData.trigger as string;
|
|
466
|
+
return trigger ? `${trigger} • ${phase}` : phase;
|
|
467
|
+
}
|
|
446
468
|
case "Internet":
|
|
447
469
|
return "";
|
|
448
470
|
default:
|