@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.
Files changed (193) hide show
  1. package/package.json +63 -0
  2. package/src/components/dock/BottomDock.tsx +204 -0
  3. package/src/components/dock/DockContext.tsx +212 -0
  4. package/src/components/dock/TerminalTab.tsx +333 -0
  5. package/src/components/dock/index.ts +3 -0
  6. package/src/components/gitops/GitOpsActions.tsx +227 -0
  7. package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
  8. package/src/components/gitops/ManagedResourcesList.tsx +210 -0
  9. package/src/components/gitops/SyncCountdown.tsx +146 -0
  10. package/src/components/gitops/index.ts +4 -0
  11. package/src/components/logs/JsonLogLine.tsx +90 -0
  12. package/src/components/logs/LogCore.tsx +553 -0
  13. package/src/components/logs/LogToolbarSelects.tsx +74 -0
  14. package/src/components/logs/LogsViewer.tsx +146 -0
  15. package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
  16. package/src/components/logs/index.ts +13 -0
  17. package/src/components/logs/useLogBuffer.ts +138 -0
  18. package/src/components/logs/useLogSearch.ts +151 -0
  19. package/src/components/logs/useLogStream.ts +61 -0
  20. package/src/components/resources/ResourcesView.tsx +5494 -0
  21. package/src/components/resources/index.ts +17 -0
  22. package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
  23. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
  24. package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
  25. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
  26. package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
  27. package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
  28. package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
  29. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
  30. package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
  31. package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
  32. package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
  33. package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
  34. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
  35. package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
  36. package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
  37. package/src/components/resources/renderers/EventRenderer.tsx +175 -0
  38. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
  39. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
  40. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
  41. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
  42. package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
  43. package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
  44. package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
  45. package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
  46. package/src/components/resources/renderers/HPARenderer.tsx +164 -0
  47. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
  48. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
  49. package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
  50. package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
  51. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
  52. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
  53. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
  54. package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
  55. package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
  56. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
  57. package/src/components/resources/renderers/JobRenderer.tsx +103 -0
  58. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
  59. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
  60. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
  61. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
  62. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
  63. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
  64. package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
  65. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
  66. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
  67. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
  68. package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
  69. package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
  70. package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
  71. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
  72. package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
  73. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
  74. package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
  75. package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
  76. package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
  77. package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
  78. package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
  79. package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
  80. package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
  81. package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
  82. package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
  83. package/src/components/resources/renderers/PodRenderer.tsx +677 -0
  84. package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
  85. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
  86. package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
  87. package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
  88. package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
  89. package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
  90. package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
  91. package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
  92. package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
  93. package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
  94. package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
  95. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
  96. package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
  97. package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
  98. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
  99. package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
  100. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
  101. package/src/components/resources/renderers/VPARenderer.tsx +193 -0
  102. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
  103. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
  104. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
  105. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
  106. package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
  107. package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
  108. package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
  109. package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
  110. package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
  111. package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
  112. package/src/components/resources/renderers/argo-cells.tsx +118 -0
  113. package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
  114. package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
  115. package/src/components/resources/renderers/eso-cells.tsx +115 -0
  116. package/src/components/resources/renderers/flux-cells.tsx +253 -0
  117. package/src/components/resources/renderers/index.ts +105 -0
  118. package/src/components/resources/renderers/istio-cells.tsx +210 -0
  119. package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
  120. package/src/components/resources/renderers/keda-cells.tsx +94 -0
  121. package/src/components/resources/renderers/knative-cells.tsx +396 -0
  122. package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
  123. package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
  124. package/src/components/resources/renderers/traefik-cells.tsx +120 -0
  125. package/src/components/resources/renderers/trivy-cells.tsx +153 -0
  126. package/src/components/resources/renderers/trivy-shared.tsx +67 -0
  127. package/src/components/resources/renderers/velero-cells.tsx +164 -0
  128. package/src/components/resources/resource-utils-argo.ts +155 -0
  129. package/src/components/resources/resource-utils-certmanager.ts +198 -0
  130. package/src/components/resources/resource-utils-cnpg.ts +344 -0
  131. package/src/components/resources/resource-utils-eso.ts +385 -0
  132. package/src/components/resources/resource-utils-flux.ts +186 -0
  133. package/src/components/resources/resource-utils-istio.ts +372 -0
  134. package/src/components/resources/resource-utils-karpenter.ts +150 -0
  135. package/src/components/resources/resource-utils-keda.ts +203 -0
  136. package/src/components/resources/resource-utils-knative.ts +218 -0
  137. package/src/components/resources/resource-utils-kyverno.ts +224 -0
  138. package/src/components/resources/resource-utils-prometheus.ts +159 -0
  139. package/src/components/resources/resource-utils-traefik.ts +180 -0
  140. package/src/components/resources/resource-utils-trivy.ts +146 -0
  141. package/src/components/resources/resource-utils-velero.ts +293 -0
  142. package/src/components/resources/resource-utils.ts +1558 -0
  143. package/src/components/shared/EditableYamlView.tsx +302 -0
  144. package/src/components/shared/ResourceActionsBar.tsx +924 -0
  145. package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
  146. package/src/components/shared/index.ts +3 -0
  147. package/src/components/timeline/index.ts +1 -0
  148. package/src/components/timeline/shared.tsx +614 -0
  149. package/src/components/topology/GroupNode.tsx +198 -0
  150. package/src/components/topology/K8sResourceNode.tsx +440 -0
  151. package/src/components/topology/TopologyControls.tsx +62 -0
  152. package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
  153. package/src/components/topology/TopologyGraph.tsx +748 -0
  154. package/src/components/topology/TopologySearch.tsx +304 -0
  155. package/src/components/topology/index.ts +7 -0
  156. package/src/components/topology/layout.ts +734 -0
  157. package/src/components/topology/layout.worker.ts +272 -0
  158. package/src/components/topology/topology.css +129 -0
  159. package/src/components/ui/CodeViewer.tsx +451 -0
  160. package/src/components/ui/ConfirmDialog.tsx +188 -0
  161. package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
  162. package/src/components/ui/HealthRing.tsx +72 -0
  163. package/src/components/ui/MetricsChart.tsx +259 -0
  164. package/src/components/ui/ResourceBar.tsx +68 -0
  165. package/src/components/ui/Toast.tsx +225 -0
  166. package/src/components/ui/Tooltip.tsx +165 -0
  167. package/src/components/ui/YamlEditor.tsx +280 -0
  168. package/src/components/ui/drawer-components.tsx +792 -0
  169. package/src/components/ui/index.ts +10 -0
  170. package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
  171. package/src/components/workload/WorkloadView.tsx +1109 -0
  172. package/src/components/workload/index.ts +2 -0
  173. package/src/hooks/index.ts +9 -0
  174. package/src/hooks/useAnimatedUnmount.ts +30 -0
  175. package/src/hooks/useKeyboardShortcuts.tsx +336 -0
  176. package/src/hooks/useRefreshAnimation.ts +58 -0
  177. package/src/index.ts +35 -0
  178. package/src/types/core.ts +894 -0
  179. package/src/types/gitops.ts +458 -0
  180. package/src/types/index.ts +2 -0
  181. package/src/utils/animation.ts +40 -0
  182. package/src/utils/api-resources.ts +185 -0
  183. package/src/utils/badge-colors.ts +399 -0
  184. package/src/utils/context-name.ts +72 -0
  185. package/src/utils/download.ts +19 -0
  186. package/src/utils/format.ts +233 -0
  187. package/src/utils/index.ts +10 -0
  188. package/src/utils/log-format.ts +300 -0
  189. package/src/utils/navigation.ts +119 -0
  190. package/src/utils/resource-hierarchy.ts +630 -0
  191. package/src/utils/resource-icons.ts +206 -0
  192. package/src/vite-env.d.ts +1 -0
  193. 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
+ }