@skyhook-io/k8s-ui 1.0.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 +63 -0
- package/src/components/dock/BottomDock.tsx +204 -0
- package/src/components/dock/DockContext.tsx +212 -0
- package/src/components/dock/TerminalTab.tsx +333 -0
- package/src/components/dock/index.ts +3 -0
- package/src/components/gitops/GitOpsActions.tsx +227 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
- package/src/components/gitops/ManagedResourcesList.tsx +210 -0
- package/src/components/gitops/SyncCountdown.tsx +146 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/logs/JsonLogLine.tsx +90 -0
- package/src/components/logs/LogCore.tsx +553 -0
- package/src/components/logs/LogToolbarSelects.tsx +74 -0
- package/src/components/logs/LogsViewer.tsx +146 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
- package/src/components/logs/index.ts +13 -0
- package/src/components/logs/useLogBuffer.ts +138 -0
- package/src/components/logs/useLogSearch.ts +151 -0
- package/src/components/logs/useLogStream.ts +61 -0
- package/src/components/resources/ResourcesView.tsx +5494 -0
- package/src/components/resources/index.ts +17 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
- package/src/components/resources/renderers/EventRenderer.tsx +175 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
- package/src/components/resources/renderers/HPARenderer.tsx +164 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
- package/src/components/resources/renderers/JobRenderer.tsx +103 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
- package/src/components/resources/renderers/PodRenderer.tsx +677 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
- package/src/components/resources/renderers/VPARenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
- package/src/components/resources/renderers/argo-cells.tsx +118 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
- package/src/components/resources/renderers/eso-cells.tsx +115 -0
- package/src/components/resources/renderers/flux-cells.tsx +253 -0
- package/src/components/resources/renderers/index.ts +105 -0
- package/src/components/resources/renderers/istio-cells.tsx +210 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
- package/src/components/resources/renderers/keda-cells.tsx +94 -0
- package/src/components/resources/renderers/knative-cells.tsx +396 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
- package/src/components/resources/renderers/traefik-cells.tsx +120 -0
- package/src/components/resources/renderers/trivy-cells.tsx +153 -0
- package/src/components/resources/renderers/trivy-shared.tsx +67 -0
- package/src/components/resources/renderers/velero-cells.tsx +164 -0
- package/src/components/resources/resource-utils-argo.ts +155 -0
- package/src/components/resources/resource-utils-certmanager.ts +198 -0
- package/src/components/resources/resource-utils-cnpg.ts +344 -0
- package/src/components/resources/resource-utils-eso.ts +385 -0
- package/src/components/resources/resource-utils-flux.ts +186 -0
- package/src/components/resources/resource-utils-istio.ts +372 -0
- package/src/components/resources/resource-utils-karpenter.ts +150 -0
- package/src/components/resources/resource-utils-keda.ts +203 -0
- package/src/components/resources/resource-utils-knative.ts +218 -0
- package/src/components/resources/resource-utils-kyverno.ts +224 -0
- package/src/components/resources/resource-utils-prometheus.ts +159 -0
- package/src/components/resources/resource-utils-traefik.ts +180 -0
- package/src/components/resources/resource-utils-trivy.ts +146 -0
- package/src/components/resources/resource-utils-velero.ts +293 -0
- package/src/components/resources/resource-utils.ts +1558 -0
- package/src/components/shared/EditableYamlView.tsx +302 -0
- package/src/components/shared/ResourceActionsBar.tsx +924 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/shared.tsx +614 -0
- package/src/components/topology/GroupNode.tsx +198 -0
- package/src/components/topology/K8sResourceNode.tsx +440 -0
- package/src/components/topology/TopologyControls.tsx +62 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
- package/src/components/topology/TopologyGraph.tsx +748 -0
- package/src/components/topology/TopologySearch.tsx +304 -0
- package/src/components/topology/index.ts +7 -0
- package/src/components/topology/layout.ts +734 -0
- package/src/components/topology/layout.worker.ts +272 -0
- package/src/components/topology/topology.css +129 -0
- package/src/components/ui/CodeViewer.tsx +451 -0
- package/src/components/ui/ConfirmDialog.tsx +188 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
- package/src/components/ui/HealthRing.tsx +72 -0
- package/src/components/ui/MetricsChart.tsx +259 -0
- package/src/components/ui/ResourceBar.tsx +68 -0
- package/src/components/ui/Toast.tsx +225 -0
- package/src/components/ui/Tooltip.tsx +165 -0
- package/src/components/ui/YamlEditor.tsx +280 -0
- package/src/components/ui/drawer-components.tsx +792 -0
- package/src/components/ui/index.ts +10 -0
- package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
- package/src/components/workload/WorkloadView.tsx +1109 -0
- package/src/components/workload/index.ts +2 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAnimatedUnmount.ts +30 -0
- package/src/hooks/useKeyboardShortcuts.tsx +336 -0
- package/src/hooks/useRefreshAnimation.ts +58 -0
- package/src/index.ts +35 -0
- package/src/types/core.ts +894 -0
- package/src/types/gitops.ts +458 -0
- package/src/types/index.ts +2 -0
- package/src/utils/animation.ts +40 -0
- package/src/utils/api-resources.ts +185 -0
- package/src/utils/badge-colors.ts +399 -0
- package/src/utils/context-name.ts +72 -0
- package/src/utils/download.ts +19 -0
- package/src/utils/format.ts +233 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/log-format.ts +300 -0
- package/src/utils/navigation.ts +119 -0
- package/src/utils/resource-hierarchy.ts +630 -0
- package/src/utils/resource-icons.ts +206 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Traefik cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { Shield } from 'lucide-react'
|
|
4
|
+
import { Tooltip } from '../../ui/Tooltip'
|
|
5
|
+
import {
|
|
6
|
+
getIngressRouteEntryPoints,
|
|
7
|
+
getIngressRouteHosts,
|
|
8
|
+
getIngressRouteRoutesSummary,
|
|
9
|
+
hasIngressRouteTLS,
|
|
10
|
+
getIngressRouteMiddlewareCount,
|
|
11
|
+
getMiddlewareType,
|
|
12
|
+
getTraefikServiceType,
|
|
13
|
+
getTraefikServiceTargets,
|
|
14
|
+
getServersTransportInsecure,
|
|
15
|
+
getServersTransportServerName,
|
|
16
|
+
getTLSOptionMinVersion,
|
|
17
|
+
} from '../resource-utils-traefik'
|
|
18
|
+
|
|
19
|
+
export function IngressRouteCell({ resource, column }: { resource: any; column: string }) {
|
|
20
|
+
switch (column) {
|
|
21
|
+
case 'entrypoints': {
|
|
22
|
+
const eps = getIngressRouteEntryPoints(resource)
|
|
23
|
+
return <span className="text-sm text-theme-text-secondary">{eps}</span>
|
|
24
|
+
}
|
|
25
|
+
case 'hosts': {
|
|
26
|
+
const hosts = getIngressRouteHosts(resource)
|
|
27
|
+
return (
|
|
28
|
+
<Tooltip content={hosts}>
|
|
29
|
+
<span className="text-sm text-theme-text-secondary truncate">{hosts}</span>
|
|
30
|
+
</Tooltip>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
case 'routes': {
|
|
34
|
+
const summary = getIngressRouteRoutesSummary(resource)
|
|
35
|
+
return (
|
|
36
|
+
<Tooltip content={summary}>
|
|
37
|
+
<span className="text-sm text-theme-text-secondary truncate">{summary}</span>
|
|
38
|
+
</Tooltip>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
case 'tls': {
|
|
42
|
+
const hasTLS = hasIngressRouteTLS(resource)
|
|
43
|
+
return hasTLS ? (
|
|
44
|
+
<Tooltip content="TLS Enabled">
|
|
45
|
+
<span>
|
|
46
|
+
<Shield className="w-4 h-4 text-green-400" />
|
|
47
|
+
</span>
|
|
48
|
+
</Tooltip>
|
|
49
|
+
) : (
|
|
50
|
+
<span className="text-sm text-theme-text-tertiary">-</span>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
case 'middlewares': {
|
|
54
|
+
const count = getIngressRouteMiddlewareCount(resource)
|
|
55
|
+
return <span className="text-sm text-theme-text-secondary">{count > 0 ? count : '-'}</span>
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function MiddlewareCell({ resource, column }: { resource: any; column: string }) {
|
|
63
|
+
switch (column) {
|
|
64
|
+
case 'type': {
|
|
65
|
+
const type = getMiddlewareType(resource)
|
|
66
|
+
return <span className="text-sm text-theme-text-secondary">{type}</span>
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function TraefikServiceCell({ resource, column }: { resource: any; column: string }) {
|
|
74
|
+
switch (column) {
|
|
75
|
+
case 'type': {
|
|
76
|
+
const type = getTraefikServiceType(resource)
|
|
77
|
+
return <span className="text-sm text-theme-text-secondary">{type}</span>
|
|
78
|
+
}
|
|
79
|
+
case 'targets': {
|
|
80
|
+
const targets = getTraefikServiceTargets(resource)
|
|
81
|
+
return (
|
|
82
|
+
<Tooltip content={targets}>
|
|
83
|
+
<span className="text-sm text-theme-text-secondary truncate">{targets}</span>
|
|
84
|
+
</Tooltip>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function ServersTransportCell({ resource, column }: { resource: any; column: string }) {
|
|
93
|
+
switch (column) {
|
|
94
|
+
case 'insecure': {
|
|
95
|
+
const insecure = getServersTransportInsecure(resource)
|
|
96
|
+
return (
|
|
97
|
+
<span className={`text-sm ${insecure ? 'text-yellow-400' : 'text-theme-text-secondary'}`}>
|
|
98
|
+
{insecure ? 'Yes' : 'No'}
|
|
99
|
+
</span>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
case 'serverName': {
|
|
103
|
+
const name = getServersTransportServerName(resource)
|
|
104
|
+
return <span className="text-sm text-theme-text-secondary truncate">{name || '-'}</span>
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function TLSOptionCell({ resource, column }: { resource: any; column: string }) {
|
|
112
|
+
switch (column) {
|
|
113
|
+
case 'minVersion': {
|
|
114
|
+
const v = getTLSOptionMinVersion(resource)
|
|
115
|
+
return <span className="text-sm text-theme-text-secondary">{v || '-'}</span>
|
|
116
|
+
}
|
|
117
|
+
default:
|
|
118
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Trivy Operator cell components for ResourcesView table — extracted from ResourcesView.tsx
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import { Tooltip } from '../../ui/Tooltip'
|
|
5
|
+
import {
|
|
6
|
+
getVulnerabilityReportSummary,
|
|
7
|
+
getVulnerabilityReportContainer,
|
|
8
|
+
getVulnerabilityReportImage,
|
|
9
|
+
getConfigAuditReportSummary,
|
|
10
|
+
getConfigAuditReportStatus,
|
|
11
|
+
getExposedSecretReportSummary,
|
|
12
|
+
getExposedSecretReportContainer,
|
|
13
|
+
getExposedSecretReportImage,
|
|
14
|
+
getRbacAssessmentReportSummary,
|
|
15
|
+
getRbacAssessmentReportStatus,
|
|
16
|
+
getClusterComplianceReportStatus,
|
|
17
|
+
getSbomReportStatus,
|
|
18
|
+
getSbomReportContainer,
|
|
19
|
+
} from '../resource-utils'
|
|
20
|
+
|
|
21
|
+
// Shared severity count cell
|
|
22
|
+
export function TrivySeverityCell({ summary, column }: { summary: { critical: number; high: number; medium: number; low: number }; column: string }) {
|
|
23
|
+
switch (column) {
|
|
24
|
+
case 'critical':
|
|
25
|
+
return <span className={clsx('text-sm font-medium', summary.critical > 0 ? 'text-red-400' : 'text-theme-text-tertiary')}>{summary.critical}</span>
|
|
26
|
+
case 'high':
|
|
27
|
+
return <span className={clsx('text-sm font-medium', summary.high > 0 ? 'text-orange-400' : 'text-theme-text-tertiary')}>{summary.high}</span>
|
|
28
|
+
case 'medium':
|
|
29
|
+
return <span className={clsx('text-sm font-medium', summary.medium > 0 ? 'text-yellow-400' : 'text-theme-text-tertiary')}>{summary.medium}</span>
|
|
30
|
+
case 'low':
|
|
31
|
+
return <span className={clsx('text-sm font-medium', summary.low > 0 ? 'text-blue-400' : 'text-theme-text-tertiary')}>{summary.low}</span>
|
|
32
|
+
default:
|
|
33
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function VulnerabilityReportCell({ resource, column }: { resource: any; column: string }) {
|
|
38
|
+
const summary = getVulnerabilityReportSummary(resource)
|
|
39
|
+
if (['critical', 'high', 'medium', 'low'].includes(column)) return <TrivySeverityCell summary={summary} column={column} />
|
|
40
|
+
switch (column) {
|
|
41
|
+
case 'container':
|
|
42
|
+
return <span className="text-sm text-theme-text-secondary">{getVulnerabilityReportContainer(resource)}</span>
|
|
43
|
+
case 'image': {
|
|
44
|
+
const image = getVulnerabilityReportImage(resource)
|
|
45
|
+
return (
|
|
46
|
+
<Tooltip content={image}>
|
|
47
|
+
<span className="text-sm text-theme-text-secondary truncate block">{image}</span>
|
|
48
|
+
</Tooltip>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
default:
|
|
52
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function ConfigAuditReportCell({ resource, column }: { resource: any; column: string }) {
|
|
57
|
+
const summary = getConfigAuditReportSummary(resource)
|
|
58
|
+
if (['critical', 'high', 'medium', 'low'].includes(column)) return <TrivySeverityCell summary={summary} column={column} />
|
|
59
|
+
switch (column) {
|
|
60
|
+
case 'status': {
|
|
61
|
+
const status = getConfigAuditReportStatus(resource)
|
|
62
|
+
return (
|
|
63
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
64
|
+
{status.text}
|
|
65
|
+
</span>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function ExposedSecretReportCell({ resource, column }: { resource: any; column: string }) {
|
|
74
|
+
const summary = getExposedSecretReportSummary(resource)
|
|
75
|
+
if (['critical', 'high', 'medium', 'low'].includes(column)) return <TrivySeverityCell summary={summary} column={column} />
|
|
76
|
+
switch (column) {
|
|
77
|
+
case 'container':
|
|
78
|
+
return <span className="text-sm text-theme-text-secondary">{getExposedSecretReportContainer(resource)}</span>
|
|
79
|
+
case 'image': {
|
|
80
|
+
const image = getExposedSecretReportImage(resource)
|
|
81
|
+
return (
|
|
82
|
+
<Tooltip content={image}>
|
|
83
|
+
<span className="text-sm text-theme-text-secondary truncate block">{image}</span>
|
|
84
|
+
</Tooltip>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function RbacAssessmentReportCell({ resource, column }: { resource: any; column: string }) {
|
|
93
|
+
const summary = getRbacAssessmentReportSummary(resource)
|
|
94
|
+
if (['critical', 'high', 'medium', 'low'].includes(column)) return <TrivySeverityCell summary={summary} column={column} />
|
|
95
|
+
switch (column) {
|
|
96
|
+
case 'status': {
|
|
97
|
+
const status = getRbacAssessmentReportStatus(resource)
|
|
98
|
+
return (
|
|
99
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
100
|
+
{status.text}
|
|
101
|
+
</span>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
default:
|
|
105
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function ClusterComplianceReportCell({ resource, column }: { resource: any; column: string }) {
|
|
110
|
+
switch (column) {
|
|
111
|
+
case 'title':
|
|
112
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{resource.spec?.compliance?.title || '-'}</span>
|
|
113
|
+
case 'status': {
|
|
114
|
+
const status = getClusterComplianceReportStatus(resource)
|
|
115
|
+
return (
|
|
116
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
117
|
+
{status.text}
|
|
118
|
+
</span>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
case 'pass': {
|
|
122
|
+
const count = resource.status?.summary?.passCount ?? null
|
|
123
|
+
return <span className={clsx('text-sm font-medium', count != null && count > 0 ? 'text-green-400' : 'text-theme-text-tertiary')}>{count != null ? count : '-'}</span>
|
|
124
|
+
}
|
|
125
|
+
case 'fail': {
|
|
126
|
+
const count = resource.status?.summary?.failCount ?? null
|
|
127
|
+
return <span className={clsx('text-sm font-medium', count != null && count > 0 ? 'text-red-400' : 'text-theme-text-tertiary')}>{count != null ? count : '-'}</span>
|
|
128
|
+
}
|
|
129
|
+
default:
|
|
130
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function SbomReportCell({ resource, column }: { resource: any; column: string }) {
|
|
135
|
+
switch (column) {
|
|
136
|
+
case 'container':
|
|
137
|
+
return <span className="text-sm text-theme-text-secondary">{getSbomReportContainer(resource)}</span>
|
|
138
|
+
case 'components': {
|
|
139
|
+
const count = resource.report?.summary?.componentsCount ?? null
|
|
140
|
+
return <span className="text-sm text-theme-text-secondary">{count != null ? count : '-'}</span>
|
|
141
|
+
}
|
|
142
|
+
case 'status': {
|
|
143
|
+
const status = getSbomReportStatus(resource)
|
|
144
|
+
return (
|
|
145
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
146
|
+
{status.text}
|
|
147
|
+
</span>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
default:
|
|
151
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { AlertBanner } from '../../ui/drawer-components'
|
|
2
|
+
|
|
3
|
+
// Shared severity color maps for all Trivy report renderers
|
|
4
|
+
|
|
5
|
+
export const SEVERITY_BADGE_COLORS: Record<string, string> = {
|
|
6
|
+
CRITICAL: 'bg-red-500/20 text-red-400',
|
|
7
|
+
HIGH: 'bg-orange-500/20 text-orange-400',
|
|
8
|
+
MEDIUM: 'bg-yellow-500/20 text-yellow-400',
|
|
9
|
+
LOW: 'bg-blue-500/20 text-blue-400',
|
|
10
|
+
UNKNOWN: 'bg-gray-500/20 text-gray-400',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const SEVERITY_BAR_COLORS: Record<string, string> = {
|
|
14
|
+
CRITICAL: 'bg-red-500',
|
|
15
|
+
HIGH: 'bg-orange-500',
|
|
16
|
+
MEDIUM: 'bg-yellow-500',
|
|
17
|
+
LOW: 'bg-blue-500',
|
|
18
|
+
UNKNOWN: 'bg-gray-500',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const SEVERITY_TEXT_COLORS: Record<string, string> = {
|
|
22
|
+
CRITICAL: 'text-red-400',
|
|
23
|
+
HIGH: 'text-orange-400',
|
|
24
|
+
MEDIUM: 'text-yellow-400',
|
|
25
|
+
LOW: 'text-blue-400',
|
|
26
|
+
UNKNOWN: 'text-gray-400',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const SEVERITY_ORDER: Record<string, number> = {
|
|
30
|
+
CRITICAL: 0,
|
|
31
|
+
HIGH: 1,
|
|
32
|
+
MEDIUM: 2,
|
|
33
|
+
LOW: 3,
|
|
34
|
+
UNKNOWN: 4,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Build a full image string from a Trivy report's artifact and registry fields. */
|
|
38
|
+
export function formatTrivyImage(report: any): string {
|
|
39
|
+
const artifact = report.artifact || {}
|
|
40
|
+
const registry = report.registry?.server || ''
|
|
41
|
+
if (!artifact.repository) return '-'
|
|
42
|
+
const repo = registry ? `${registry}/${artifact.repository}` : artifact.repository
|
|
43
|
+
return artifact.tag ? `${repo}:${artifact.tag}` : repo
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Reusable alert banner shown at top of Trivy report renderers
|
|
47
|
+
export function TrivyAlertBanner({ critical, high, noun }: { critical: number; high: number; noun: string }) {
|
|
48
|
+
if (critical > 0) {
|
|
49
|
+
return (
|
|
50
|
+
<AlertBanner
|
|
51
|
+
variant="error"
|
|
52
|
+
title={`${critical} critical ${noun}${critical !== 1 ? 's' : ''}`}
|
|
53
|
+
message="Critical issues should be addressed immediately."
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
if (high > 0) {
|
|
58
|
+
return (
|
|
59
|
+
<AlertBanner
|
|
60
|
+
variant="warning"
|
|
61
|
+
title={`${high} high-severity ${noun}${high !== 1 ? 's' : ''}`}
|
|
62
|
+
message="Consider addressing these issues to improve security posture."
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Velero cell components for ResourcesView table
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx'
|
|
4
|
+
import {
|
|
5
|
+
getBackupStatus,
|
|
6
|
+
getBackupStorageLocation,
|
|
7
|
+
getBackupIncludedNamespaces,
|
|
8
|
+
getBackupDuration,
|
|
9
|
+
getBackupExpiry,
|
|
10
|
+
getBackupErrors,
|
|
11
|
+
getBackupWarnings,
|
|
12
|
+
getRestoreStatus,
|
|
13
|
+
getRestoreBackupName,
|
|
14
|
+
getRestoreIncludedNamespaces,
|
|
15
|
+
getRestoreDuration,
|
|
16
|
+
getRestoreErrors,
|
|
17
|
+
getScheduleStatus,
|
|
18
|
+
getScheduleCron,
|
|
19
|
+
getScheduleLastBackup,
|
|
20
|
+
getSchedulePaused,
|
|
21
|
+
getBSLStatus,
|
|
22
|
+
getBSLProvider,
|
|
23
|
+
getBSLBucket,
|
|
24
|
+
getBSLDefault,
|
|
25
|
+
getBSLLastValidation,
|
|
26
|
+
} from '../resource-utils-velero'
|
|
27
|
+
|
|
28
|
+
export function BackupCell({ resource, column }: { resource: any; column: string }) {
|
|
29
|
+
switch (column) {
|
|
30
|
+
case 'status': {
|
|
31
|
+
const status = getBackupStatus(resource)
|
|
32
|
+
return (
|
|
33
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
34
|
+
{status.text}
|
|
35
|
+
</span>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
case 'storageLocation': {
|
|
39
|
+
const loc = getBackupStorageLocation(resource)
|
|
40
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{loc}</span>
|
|
41
|
+
}
|
|
42
|
+
case 'namespaces': {
|
|
43
|
+
const ns = getBackupIncludedNamespaces(resource)
|
|
44
|
+
return <span className="text-sm text-theme-text-secondary">{ns.length > 0 ? ns.length : '*'}</span>
|
|
45
|
+
}
|
|
46
|
+
case 'duration': {
|
|
47
|
+
const dur = getBackupDuration(resource)
|
|
48
|
+
return <span className="text-sm text-theme-text-secondary">{dur}</span>
|
|
49
|
+
}
|
|
50
|
+
case 'expiry': {
|
|
51
|
+
const exp = getBackupExpiry(resource)
|
|
52
|
+
const isExpired = exp === 'Expired'
|
|
53
|
+
return <span className={clsx('text-sm', isExpired ? 'text-red-400' : 'text-theme-text-secondary')}>{exp}</span>
|
|
54
|
+
}
|
|
55
|
+
case 'errors': {
|
|
56
|
+
const errors = getBackupErrors(resource)
|
|
57
|
+
const warnings = getBackupWarnings(resource)
|
|
58
|
+
if (errors === 0 && warnings === 0) {
|
|
59
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
60
|
+
}
|
|
61
|
+
return (
|
|
62
|
+
<span className="text-sm">
|
|
63
|
+
{errors > 0 && <span className="text-red-400">{errors}E</span>}
|
|
64
|
+
{errors > 0 && warnings > 0 && <span className="text-theme-text-tertiary"> / </span>}
|
|
65
|
+
{warnings > 0 && <span className="text-yellow-400">{warnings}W</span>}
|
|
66
|
+
</span>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function RestoreCell({ resource, column }: { resource: any; column: string }) {
|
|
75
|
+
switch (column) {
|
|
76
|
+
case 'status': {
|
|
77
|
+
const status = getRestoreStatus(resource)
|
|
78
|
+
return (
|
|
79
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
80
|
+
{status.text}
|
|
81
|
+
</span>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
case 'backupName': {
|
|
85
|
+
const name = getRestoreBackupName(resource)
|
|
86
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{name}</span>
|
|
87
|
+
}
|
|
88
|
+
case 'namespaces': {
|
|
89
|
+
const ns = getRestoreIncludedNamespaces(resource)
|
|
90
|
+
return <span className="text-sm text-theme-text-secondary">{ns.length > 0 ? ns.length : '*'}</span>
|
|
91
|
+
}
|
|
92
|
+
case 'duration': {
|
|
93
|
+
const dur = getRestoreDuration(resource)
|
|
94
|
+
return <span className="text-sm text-theme-text-secondary">{dur}</span>
|
|
95
|
+
}
|
|
96
|
+
case 'errors': {
|
|
97
|
+
const errors = getRestoreErrors(resource)
|
|
98
|
+
if (errors === 0) {
|
|
99
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
100
|
+
}
|
|
101
|
+
return <span className="text-sm text-red-400">{errors}</span>
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function ScheduleCell({ resource, column }: { resource: any; column: string }) {
|
|
109
|
+
switch (column) {
|
|
110
|
+
case 'status': {
|
|
111
|
+
const status = getScheduleStatus(resource)
|
|
112
|
+
return (
|
|
113
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
114
|
+
{status.text}
|
|
115
|
+
</span>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
case 'schedule': {
|
|
119
|
+
const cron = getScheduleCron(resource)
|
|
120
|
+
return <span className="text-sm text-theme-text-secondary font-mono">{cron}</span>
|
|
121
|
+
}
|
|
122
|
+
case 'lastBackup': {
|
|
123
|
+
const last = getScheduleLastBackup(resource)
|
|
124
|
+
return <span className="text-sm text-theme-text-secondary">{last}</span>
|
|
125
|
+
}
|
|
126
|
+
case 'paused': {
|
|
127
|
+
const paused = getSchedulePaused(resource)
|
|
128
|
+
return <span className={clsx('text-sm', paused ? 'text-yellow-400' : 'text-theme-text-tertiary')}>{paused ? 'Yes' : '-'}</span>
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function BackupStorageLocationCell({ resource, column }: { resource: any; column: string }) {
|
|
136
|
+
switch (column) {
|
|
137
|
+
case 'status': {
|
|
138
|
+
const status = getBSLStatus(resource)
|
|
139
|
+
return (
|
|
140
|
+
<span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
|
|
141
|
+
{status.text}
|
|
142
|
+
</span>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
case 'provider': {
|
|
146
|
+
const provider = getBSLProvider(resource)
|
|
147
|
+
return <span className="text-sm text-theme-text-secondary">{provider}</span>
|
|
148
|
+
}
|
|
149
|
+
case 'bucket': {
|
|
150
|
+
const bucket = getBSLBucket(resource)
|
|
151
|
+
return <span className="text-sm text-theme-text-secondary truncate block">{bucket}</span>
|
|
152
|
+
}
|
|
153
|
+
case 'default': {
|
|
154
|
+
const isDefault = getBSLDefault(resource)
|
|
155
|
+
return <span className={clsx('text-sm', isDefault ? 'text-blue-400' : 'text-theme-text-tertiary')}>{isDefault ? 'Yes' : '-'}</span>
|
|
156
|
+
}
|
|
157
|
+
case 'lastValidation': {
|
|
158
|
+
const lastVal = getBSLLastValidation(resource)
|
|
159
|
+
return <span className="text-sm text-theme-text-secondary">{lastVal}</span>
|
|
160
|
+
}
|
|
161
|
+
default:
|
|
162
|
+
return <span className="text-sm text-theme-text-tertiary">-</span>
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// ArgoCD CRD utility functions — extracted from resource-utils.ts
|
|
2
|
+
|
|
3
|
+
import type { StatusBadge } from './resource-utils'
|
|
4
|
+
import { healthColors } from './resource-utils'
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// ARGOCD STATUS UTILITIES
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
export function getArgoApplicationStatus(app: any): StatusBadge {
|
|
11
|
+
const health = app.status?.health?.status
|
|
12
|
+
const sync = app.status?.sync?.status
|
|
13
|
+
const opPhase = app.status?.operationState?.phase
|
|
14
|
+
|
|
15
|
+
// Check for suspended (no automated sync policy)
|
|
16
|
+
const hasAutomatedSync = !!app.spec?.syncPolicy?.automated
|
|
17
|
+
if (health === 'Suspended' || (!hasAutomatedSync && app.metadata?.annotations?.['radar.skyhook.io/suspended-prune'])) {
|
|
18
|
+
return { text: 'Suspended', color: healthColors.degraded, level: 'degraded' }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Operation in progress
|
|
22
|
+
if (opPhase === 'Running') {
|
|
23
|
+
return { text: 'Syncing', color: healthColors.degraded, level: 'degraded' }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Failed operation
|
|
27
|
+
if (opPhase === 'Failed' || opPhase === 'Error') {
|
|
28
|
+
return { text: 'Failed', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Health-based status
|
|
32
|
+
if (health === 'Healthy' && sync === 'Synced') {
|
|
33
|
+
return { text: 'Healthy', color: healthColors.healthy, level: 'healthy' }
|
|
34
|
+
}
|
|
35
|
+
if (health === 'Degraded') {
|
|
36
|
+
return { text: 'Degraded', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
37
|
+
}
|
|
38
|
+
if (health === 'Progressing') {
|
|
39
|
+
return { text: 'Progressing', color: healthColors.degraded, level: 'degraded' }
|
|
40
|
+
}
|
|
41
|
+
if (health === 'Missing') {
|
|
42
|
+
return { text: 'Missing', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Sync-based status
|
|
46
|
+
if (sync === 'OutOfSync') {
|
|
47
|
+
return { text: 'OutOfSync', color: healthColors.degraded, level: 'degraded' }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { text: health || sync || 'Unknown', color: healthColors.unknown, level: 'unknown' }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// ARGOCD TABLE CELL UTILITIES
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
export function getArgoApplicationProject(app: any): string {
|
|
58
|
+
return app.spec?.project || 'default'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getArgoApplicationSync(app: any): { status: string; color: string } {
|
|
62
|
+
const sync = app.status?.sync?.status
|
|
63
|
+
switch (sync) {
|
|
64
|
+
case 'Synced':
|
|
65
|
+
return { status: 'Synced', color: healthColors.healthy }
|
|
66
|
+
case 'OutOfSync':
|
|
67
|
+
return { status: 'OutOfSync', color: healthColors.degraded }
|
|
68
|
+
default:
|
|
69
|
+
return { status: sync || 'Unknown', color: healthColors.unknown }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getArgoApplicationHealth(app: any): { status: string; color: string } {
|
|
74
|
+
const health = app.status?.health?.status
|
|
75
|
+
switch (health) {
|
|
76
|
+
case 'Healthy':
|
|
77
|
+
return { status: 'Healthy', color: healthColors.healthy }
|
|
78
|
+
case 'Progressing':
|
|
79
|
+
return { status: 'Progressing', color: healthColors.degraded }
|
|
80
|
+
case 'Degraded':
|
|
81
|
+
return { status: 'Degraded', color: healthColors.unhealthy }
|
|
82
|
+
case 'Suspended':
|
|
83
|
+
return { status: 'Suspended', color: healthColors.degraded }
|
|
84
|
+
case 'Missing':
|
|
85
|
+
return { status: 'Missing', color: healthColors.unhealthy }
|
|
86
|
+
default:
|
|
87
|
+
return { status: health || 'Unknown', color: healthColors.unknown }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getArgoApplicationRepo(app: any): string {
|
|
92
|
+
// Can be source (single) or sources (multi-source)
|
|
93
|
+
const source = app.spec?.source || app.spec?.sources?.[0]
|
|
94
|
+
if (!source?.repoURL) return '-'
|
|
95
|
+
// Shorten the URL for display
|
|
96
|
+
const url = source.repoURL
|
|
97
|
+
try {
|
|
98
|
+
const parsed = new URL(url)
|
|
99
|
+
return parsed.pathname.replace(/^\//, '').replace(/\.git$/, '')
|
|
100
|
+
} catch {
|
|
101
|
+
return url
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function getArgoApplicationSetGenerators(appSet: any): string {
|
|
106
|
+
const generators = appSet.spec?.generators || []
|
|
107
|
+
if (generators.length === 0) return '-'
|
|
108
|
+
// Get the type of each generator
|
|
109
|
+
const types = generators.map((g: any) => {
|
|
110
|
+
const keys = Object.keys(g)
|
|
111
|
+
return keys[0] || 'unknown'
|
|
112
|
+
})
|
|
113
|
+
return types.join(', ')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function getArgoApplicationSetTemplate(appSet: any): string {
|
|
117
|
+
const template = appSet.spec?.template?.metadata?.name
|
|
118
|
+
return template || '-'
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function getArgoApplicationSetAppCount(appSet: any): number {
|
|
122
|
+
return appSet.status?.conditions?.find((c: any) => c.type === 'ResourcesUpToDate')
|
|
123
|
+
? appSet.status?.applicationStatus?.length || 0
|
|
124
|
+
: 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function getArgoApplicationSetStatus(appSet: any): StatusBadge {
|
|
128
|
+
const conditions = appSet.status?.conditions || []
|
|
129
|
+
const errorCondition = conditions.find((c: any) => c.type === 'ErrorOccurred' && c.status === 'True')
|
|
130
|
+
if (errorCondition) {
|
|
131
|
+
return { text: 'Error', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
132
|
+
}
|
|
133
|
+
const resourcesUpToDate = conditions.find((c: any) => c.type === 'ResourcesUpToDate')
|
|
134
|
+
if (resourcesUpToDate?.status === 'True') {
|
|
135
|
+
return { text: 'Ready', color: healthColors.healthy, level: 'healthy' }
|
|
136
|
+
}
|
|
137
|
+
return { text: 'Unknown', color: healthColors.unknown, level: 'unknown' }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function getArgoAppProjectDescription(project: any): string {
|
|
141
|
+
return project.spec?.description || '-'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function getArgoAppProjectDestinations(project: any): number {
|
|
145
|
+
const destinations = project.spec?.destinations || []
|
|
146
|
+
// '*' means all, count as 1
|
|
147
|
+
if (destinations.some((d: any) => d.server === '*' && d.namespace === '*')) return Infinity
|
|
148
|
+
return destinations.length
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function getArgoAppProjectSources(project: any): number {
|
|
152
|
+
const sources = project.spec?.sourceRepos || []
|
|
153
|
+
if (sources.includes('*')) return Infinity
|
|
154
|
+
return sources.length
|
|
155
|
+
}
|