@skyhook-io/k8s-ui 1.2.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/package.json +3 -2
  2. package/src/components/dock/BottomDock.tsx +1 -1
  3. package/src/components/dock/LocalTerminalTab.tsx +1 -1
  4. package/src/components/dock/NodeTerminalTab.tsx +1 -1
  5. package/src/components/dock/TerminalTab.tsx +2 -2
  6. package/src/components/gitops/GitOpsActions.tsx +12 -11
  7. package/src/components/gitops/GitOpsStatusBadge.tsx +6 -6
  8. package/src/components/logs/LogCore.tsx +8 -8
  9. package/src/components/logs/WorkloadLogsViewer.tsx +29 -5
  10. package/src/components/logs/useLogStream.ts +20 -0
  11. package/src/components/resources/ResourcesSidebar.tsx +10 -10
  12. package/src/components/resources/ResourcesView.tsx +49 -48
  13. package/src/components/resources/renderers/AlertRenderer.tsx +2 -2
  14. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +2 -2
  15. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +1 -1
  16. package/src/components/resources/renderers/CertificateRenderer.tsx +3 -3
  17. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +3 -3
  18. package/src/components/resources/renderers/ChallengeRenderer.tsx +2 -2
  19. package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +3 -3
  20. package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +3 -3
  21. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +2 -2
  22. package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +1 -1
  23. package/src/components/resources/renderers/EventRenderer.tsx +1 -1
  24. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +2 -2
  25. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +2 -2
  26. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +1 -1
  27. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +5 -5
  28. package/src/components/resources/renderers/GatewayClassRenderer.tsx +1 -1
  29. package/src/components/resources/renderers/GatewayRenderer.tsx +3 -3
  30. package/src/components/resources/renderers/GenericRenderer.tsx +1 -1
  31. package/src/components/resources/renderers/HPARenderer.tsx +1 -1
  32. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +5 -5
  33. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +1 -1
  34. package/src/components/resources/renderers/IngressClassRenderer.tsx +1 -1
  35. package/src/components/resources/renderers/IngressRenderer.tsx +1 -1
  36. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +10 -10
  37. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +1 -1
  38. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +2 -2
  39. package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +2 -2
  40. package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +6 -6
  41. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -5
  42. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +5 -5
  43. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +2 -2
  44. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +4 -4
  45. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +3 -3
  46. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +3 -3
  47. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +5 -5
  48. package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +2 -2
  49. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +5 -5
  50. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +4 -4
  51. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +8 -8
  52. package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +3 -3
  53. package/src/components/resources/renderers/KnativeRouteRenderer.tsx +1 -1
  54. package/src/components/resources/renderers/KnativeServiceRenderer.tsx +2 -2
  55. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +6 -6
  56. package/src/components/resources/renderers/KustomizationRenderer.tsx +1 -1
  57. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +4 -4
  58. package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +6 -6
  59. package/src/components/resources/renderers/NodeRenderer.tsx +5 -5
  60. package/src/components/resources/renderers/OrderRenderer.tsx +3 -3
  61. package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +1 -1
  62. package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +1 -1
  63. package/src/components/resources/renderers/PodMonitorRenderer.tsx +3 -3
  64. package/src/components/resources/renderers/PodRenderer.tsx +10 -10
  65. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +2 -2
  66. package/src/components/resources/renderers/RoleBindingRenderer.tsx +3 -3
  67. package/src/components/resources/renderers/RoleRenderer.tsx +8 -8
  68. package/src/components/resources/renderers/RolloutRenderer.tsx +1 -1
  69. package/src/components/resources/renderers/RuntimeClassRenderer.tsx +2 -2
  70. package/src/components/resources/renderers/SealedSecretRenderer.tsx +2 -2
  71. package/src/components/resources/renderers/SecretRenderer.tsx +3 -3
  72. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +1 -1
  73. package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +3 -3
  74. package/src/components/resources/renderers/ServiceRenderer.tsx +1 -1
  75. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +5 -5
  76. package/src/components/resources/renderers/StorageClassRenderer.tsx +1 -1
  77. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +1 -1
  78. package/src/components/resources/renderers/VPARenderer.tsx +2 -2
  79. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +2 -2
  80. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +6 -6
  81. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +5 -5
  82. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +6 -6
  83. package/src/components/resources/renderers/VeleroVSLRenderer.tsx +1 -1
  84. package/src/components/resources/renderers/WebhookConfigRenderer.tsx +10 -10
  85. package/src/components/resources/renderers/WorkflowRenderer.tsx +2 -2
  86. package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +2 -2
  87. package/src/components/resources/renderers/WorkloadRenderer.tsx +1 -1
  88. package/src/components/resources/renderers/argo-cells.tsx +3 -3
  89. package/src/components/resources/renderers/certmanager-cells.tsx +6 -6
  90. package/src/components/resources/renderers/cnpg-cells.tsx +5 -5
  91. package/src/components/resources/renderers/eso-cells.tsx +4 -4
  92. package/src/components/resources/renderers/flux-cells.tsx +6 -6
  93. package/src/components/resources/renderers/istio-cells.tsx +9 -9
  94. package/src/components/resources/renderers/karpenter-cells.tsx +3 -3
  95. package/src/components/resources/renderers/keda-cells.tsx +2 -2
  96. package/src/components/resources/renderers/knative-cells.tsx +2 -2
  97. package/src/components/resources/renderers/kyverno-cells.tsx +3 -3
  98. package/src/components/resources/renderers/prometheus-cells.tsx +3 -3
  99. package/src/components/resources/renderers/trivy-cells.tsx +4 -4
  100. package/src/components/resources/renderers/velero-cells.tsx +4 -4
  101. package/src/components/shared/EditableYamlView.tsx +1 -1
  102. package/src/components/shared/ResourceActionsBar.tsx +17 -17
  103. package/src/components/shared/ResourceRendererDispatch.tsx +8 -7
  104. package/src/components/topology/K8sResourceNode.tsx +5 -5
  105. package/src/components/topology/TopologyControls.tsx +2 -2
  106. package/src/components/topology/TopologyGraph.tsx +89 -23
  107. package/src/components/topology/topology.css +1 -1
  108. package/src/components/ui/Badge.tsx +178 -0
  109. package/src/components/ui/HealthRing.tsx +70 -35
  110. package/src/components/ui/MetricsChart.tsx +2 -2
  111. package/src/components/ui/drawer-components.tsx +12 -31
  112. package/src/components/workload/ResourceDetailDrawer.tsx +4 -4
  113. package/src/components/workload/WorkloadView.tsx +10 -10
  114. package/src/theme/components.css +195 -0
  115. package/src/theme/tailwind-theme.css +13 -13
  116. package/src/theme/variables.css +46 -29
  117. package/src/types/core.ts +2 -0
  118. package/src/utils/badge-colors.ts +54 -205
  119. package/src/utils/log-format.ts +0 -8
@@ -64,7 +64,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
64
64
  <Section title={`Rules (${rules.length})`} icon={Shield} defaultExpanded>
65
65
  <div className="space-y-3">
66
66
  {rules.map((rule: any, i: number) => (
67
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
67
+ <div key={i} className="card-inner-lg">
68
68
  {/* API Groups */}
69
69
  {rule.apiGroups && rule.apiGroups.length > 0 && (
70
70
  <div className="mb-2">
@@ -73,7 +73,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
73
73
  {rule.apiGroups.map((group: string, gi: number) => (
74
74
  <span
75
75
  key={gi}
76
- className="px-2 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary"
76
+ className="badge bg-theme-elevated text-theme-text-secondary"
77
77
  >
78
78
  {group === '' ? 'core' : group}
79
79
  </span>
@@ -90,7 +90,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
90
90
  {rule.resources.map((resource: string) => (
91
91
  <span
92
92
  key={resource}
93
- className="px-2 py-0.5 rounded text-xs bg-purple-500/20 text-purple-400"
93
+ className="badge bg-purple-500/20 text-purple-400"
94
94
  >
95
95
  {resource}
96
96
  </span>
@@ -108,7 +108,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
108
108
  <span
109
109
  key={verb}
110
110
  className={clsx(
111
- 'px-2 py-0.5 rounded text-xs',
111
+ 'badge',
112
112
  getVerbColor(verb)
113
113
  )}
114
114
  >
@@ -127,7 +127,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
127
127
  {rule.resourceNames.map((name: string) => (
128
128
  <span
129
129
  key={name}
130
- className="px-2 py-0.5 rounded text-xs bg-cyan-500/20 text-cyan-400"
130
+ className="badge bg-cyan-500/20 text-cyan-400"
131
131
  >
132
132
  {name}
133
133
  </span>
@@ -144,7 +144,7 @@ export function RoleRenderer({ data }: RoleRendererProps) {
144
144
  {rule.nonResourceURLs.map((url: string) => (
145
145
  <span
146
146
  key={url}
147
- className="px-2 py-0.5 rounded text-xs bg-orange-500/20 text-orange-400"
147
+ className="badge bg-orange-500/20 text-orange-400"
148
148
  >
149
149
  {url}
150
150
  </span>
@@ -166,14 +166,14 @@ export function RoleRenderer({ data }: RoleRendererProps) {
166
166
  <Section title="Aggregation Rule" defaultExpanded>
167
167
  <div className="space-y-3">
168
168
  {aggregationRule.clusterRoleSelectors.map((selector: any, i: number) => (
169
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
169
+ <div key={i} className="card-inner-lg">
170
170
  <div className="text-xs text-theme-text-tertiary mb-1">Match Labels</div>
171
171
  {selector.matchLabels && Object.keys(selector.matchLabels).length > 0 ? (
172
172
  <div className="flex flex-wrap gap-1">
173
173
  {Object.entries(selector.matchLabels).map(([k, v]) => (
174
174
  <span
175
175
  key={k}
176
- className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary"
176
+ className="badge bg-theme-elevated text-theme-text-secondary"
177
177
  >
178
178
  {k}={String(v)}
179
179
  </span>
@@ -102,7 +102,7 @@ export function RolloutRenderer({ data }: RolloutRendererProps) {
102
102
  <Property
103
103
  label="Phase"
104
104
  value={
105
- <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', phaseColor)}>
105
+ <span className={clsx('badge', phaseColor)}>
106
106
  {phase}
107
107
  </span>
108
108
  }
@@ -42,7 +42,7 @@ export function RuntimeClassRenderer({ data }: RuntimeClassRendererProps) {
42
42
  {Object.entries(nodeSelector).map(([key, value]) => (
43
43
  <span
44
44
  key={key}
45
- className="px-2 py-0.5 rounded text-xs bg-blue-500/20 text-blue-400"
45
+ className="badge status-neutral"
46
46
  >
47
47
  {key}={value as string}
48
48
  </span>
@@ -59,7 +59,7 @@ export function RuntimeClassRenderer({ data }: RuntimeClassRendererProps) {
59
59
  const effect = t.effect ? `: ${t.effect}` : ''
60
60
  const seconds = t.tolerationSeconds != null ? ` (${t.tolerationSeconds}s)` : ''
61
61
  return (
62
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-xs text-theme-text-secondary">
62
+ <div key={i} className="card-inner text-xs text-theme-text-secondary">
63
63
  {parts}{effect}{seconds}
64
64
  </div>
65
65
  )
@@ -54,7 +54,7 @@ export function SealedSecretRenderer({ data }: SealedSecretRendererProps) {
54
54
  label="Synced"
55
55
  value={
56
56
  <span className={clsx(
57
- 'px-2 py-0.5 rounded text-xs font-medium',
57
+ 'badge',
58
58
  isSynced
59
59
  ? 'bg-green-500/20 text-green-400'
60
60
  : isNotSynced
@@ -78,7 +78,7 @@ export function SealedSecretRenderer({ data }: SealedSecretRendererProps) {
78
78
  {encryptedKeys.map((key) => (
79
79
  <span
80
80
  key={key}
81
- className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary"
81
+ className="badge bg-theme-elevated text-theme-text-secondary"
82
82
  >
83
83
  {key}
84
84
  </span>
@@ -161,7 +161,7 @@ export function SecretRenderer({ data, certificateInfo, resourceData, onSaveSecr
161
161
  const canEdit = onSaveSecretValue && !isImmutable && !isBinary
162
162
 
163
163
  return (
164
- <div key={key} className="bg-theme-elevated/30 rounded p-2">
164
+ <div key={key} className="card-inner">
165
165
  <div className="flex items-center justify-between gap-2">
166
166
  <span className="text-sm text-theme-text-primary truncate">{key}</span>
167
167
  <div className="flex items-center gap-1 shrink-0">
@@ -211,7 +211,7 @@ export function SecretRenderer({ data, certificateInfo, resourceData, onSaveSecr
211
211
  <button
212
212
  onClick={() => setShowSaveConfirm(true)}
213
213
  disabled={isSaving}
214
- className="flex items-center gap-1 px-2.5 py-1 text-xs text-white bg-blue-600 hover:bg-blue-700 rounded transition-colors disabled:opacity-50"
214
+ className="flex items-center gap-1 px-2.5 py-1 text-xs btn-brand rounded"
215
215
  >
216
216
  {isSaving ? (
217
217
  <RefreshCw className="w-3 h-3 animate-spin" />
@@ -285,7 +285,7 @@ function CertificateInfoSection({ cert, index, total }: { cert: CertificateInfo;
285
285
  <Property label="SANs" value={
286
286
  <div className="flex flex-wrap gap-1">
287
287
  {cert.sans.map(san => (
288
- <span key={san} className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary">
288
+ <span key={san} className="badge bg-theme-elevated text-theme-text-secondary">
289
289
  {san}
290
290
  </span>
291
291
  ))}
@@ -68,7 +68,7 @@ export function ServiceAccountRenderer({ data }: ServiceAccountRendererProps) {
68
68
  {imagePullSecrets.map((secret: any) => (
69
69
  <span
70
70
  key={secret.name}
71
- className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary"
71
+ className="badge bg-theme-elevated text-theme-text-secondary"
72
72
  >
73
73
  {secret.name}
74
74
  </span>
@@ -30,19 +30,19 @@ export function ServiceMonitorRenderer({ data }: ServiceMonitorRendererProps) {
30
30
  <Section title={`Scrape Endpoints (${endpoints.length})`} defaultExpanded>
31
31
  <div className="space-y-2">
32
32
  {endpoints.map((ep, i) => (
33
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
33
+ <div key={i} className="card-inner text-sm">
34
34
  <div className="flex items-center gap-2 flex-wrap">
35
35
  {ep.port && (
36
36
  <span className="text-theme-text-primary font-medium">{ep.port}</span>
37
37
  )}
38
38
  <span className="text-theme-text-secondary">{ep.path}</span>
39
39
  {ep.interval && (
40
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
40
+ <span className="badge-sm bg-theme-hover text-theme-text-secondary">
41
41
  every {ep.interval}
42
42
  </span>
43
43
  )}
44
44
  {ep.scheme && ep.scheme !== 'http' && (
45
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
45
+ <span className="badge-sm bg-theme-hover text-theme-text-secondary">
46
46
  {ep.scheme}
47
47
  </span>
48
48
  )}
@@ -67,7 +67,7 @@ export function ServiceRenderer({ data, onCopy, copied, renderPortAction }: Serv
67
67
  <Section title="Ports" defaultExpanded>
68
68
  <div className="space-y-2">
69
69
  {ports.map((port: any, i: number) => (
70
- <div key={`${port.port}-${port.protocol || 'TCP'}`} className="bg-theme-elevated/30 rounded p-2 text-sm">
70
+ <div key={`${port.port}-${port.protocol || 'TCP'}`} className="card-inner text-sm">
71
71
  <div className="flex items-center justify-between">
72
72
  <span className="text-theme-text-primary font-medium">{port.name || `port-${i + 1}`}</span>
73
73
  <div className="flex items-center gap-2">
@@ -81,7 +81,7 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
81
81
  hostnames.length > 0 ? (
82
82
  <div className="flex flex-wrap gap-1">
83
83
  {hostnames.map((h: string) => (
84
- <span key={h} className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary">{h}</span>
84
+ <span key={h} className="badge bg-theme-elevated text-theme-text-secondary">{h}</span>
85
85
  ))}
86
86
  </div>
87
87
  ) : (
@@ -113,7 +113,7 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
113
113
  const totalWeight = hasWeights ? backendRefs.reduce((sum: number, b: any) => sum + (b.weight ?? 1), 0) : 0
114
114
 
115
115
  return (
116
- <div key={ruleIdx} className="bg-theme-elevated/30 rounded p-2.5">
116
+ <div key={ruleIdx} className="card-inner">
117
117
  {rules.length > 1 && (
118
118
  <div className="text-xs font-medium text-theme-text-tertiary mb-1.5">
119
119
  Rule {ruleIdx + 1}
@@ -156,7 +156,7 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
156
156
  const resolved = conditions.find((c: any) => c.type === 'ResolvedRefs')
157
157
 
158
158
  return (
159
- <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="bg-theme-elevated/30 rounded p-2.5">
159
+ <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="card-inner">
160
160
  <div className="text-sm font-medium text-theme-text-primary mb-1.5">
161
161
  {ref.namespace ? `${ref.namespace}/` : ''}{ref.name || 'unknown'}
162
162
  {ref.sectionName ? ` (${ref.sectionName})` : ''}
@@ -164,7 +164,7 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
164
164
  <div className="flex flex-wrap gap-2">
165
165
  {accepted && (
166
166
  <span className={clsx(
167
- 'px-2 py-0.5 rounded text-xs font-medium',
167
+ 'badge',
168
168
  accepted.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
169
169
  )}>
170
170
  {accepted.status === 'True' ? 'Accepted' : 'Not Accepted'}
@@ -172,7 +172,7 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
172
172
  )}
173
173
  {resolved && (
174
174
  <span className={clsx(
175
- 'px-2 py-0.5 rounded text-xs font-medium',
175
+ 'badge',
176
176
  resolved.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'
177
177
  )}>
178
178
  {resolved.status === 'True' ? 'Refs Resolved' : 'Unresolved Refs'}
@@ -69,7 +69,7 @@ export function StorageClassRenderer({ data }: StorageClassRendererProps) {
69
69
  {mountOptions.map((option: string) => (
70
70
  <span
71
71
  key={option}
72
- className="px-2 py-0.5 rounded text-xs bg-blue-500/20 text-blue-400"
72
+ className="badge status-neutral"
73
73
  >
74
74
  {option}
75
75
  </span>
@@ -77,7 +77,7 @@ export function TraefikIngressRouteRenderer({ data, onNavigate }: TraefikIngress
77
77
  const middlewares = route.middlewares || []
78
78
 
79
79
  return (
80
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
80
+ <div key={i} className="card-inner-lg">
81
81
  {/* Match expression */}
82
82
  <div className="flex items-start gap-2 mb-2">
83
83
  <span className="text-sm font-medium text-theme-text-primary break-all">
@@ -96,7 +96,7 @@ export function VPARenderer({ data, onNavigate }: VPARendererProps) {
96
96
  <Section title="Recommendations" defaultExpanded>
97
97
  <div className="space-y-3">
98
98
  {recommendations.map((rec: any) => (
99
- <div key={rec.containerName} className="bg-theme-elevated/30 rounded-lg p-3">
99
+ <div key={rec.containerName} className="card-inner-lg">
100
100
  <div className="text-sm font-medium text-theme-text-primary mb-2">{rec.containerName}</div>
101
101
  <div className="overflow-x-auto">
102
102
  <table className="w-full text-xs">
@@ -144,7 +144,7 @@ export function VPARenderer({ data, onNavigate }: VPARendererProps) {
144
144
  <Section title="Resource Policy" defaultExpanded>
145
145
  <div className="space-y-3">
146
146
  {containerPolicies.map((policy: any, i: number) => (
147
- <div key={i} className="bg-theme-elevated/30 rounded-lg p-3">
147
+ <div key={i} className="card-inner-lg">
148
148
  <div className="flex items-center gap-2 mb-2">
149
149
  <span className="text-sm font-medium text-theme-text-primary">{policy.containerName || '*'}</span>
150
150
  {policy.mode && (
@@ -29,7 +29,7 @@ export function VeleroBSLRenderer({ data }: VeleroBSLRendererProps) {
29
29
  <Section title="Status" icon={Clock} defaultExpanded>
30
30
  <PropertyList>
31
31
  <Property label="Phase" value={
32
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', bslStatus.color)}>
32
+ <span className={clsx('badge', bslStatus.color)}>
33
33
  {bslStatus.text}
34
34
  </span>
35
35
  } />
@@ -58,7 +58,7 @@ export function VeleroBSLRenderer({ data }: VeleroBSLRendererProps) {
58
58
  <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Config</div>
59
59
  <div className="flex flex-wrap gap-1">
60
60
  {Object.entries(config).map(([k, v]) => (
61
- <span key={k} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
61
+ <span key={k} className="badge-sm bg-theme-hover text-theme-text-secondary">
62
62
  {k}: {String(v)}
63
63
  </span>
64
64
  ))}
@@ -72,7 +72,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
72
72
  <Section title="Status" icon={Archive} defaultExpanded>
73
73
  <PropertyList>
74
74
  <Property label="Phase" value={
75
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', backupStatus.color)}>
75
+ <span className={clsx('badge', backupStatus.color)}>
76
76
  {backupStatus.text}
77
77
  </span>
78
78
  } />
@@ -116,7 +116,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
116
116
  <Property label="Included Namespaces" value={
117
117
  <div className="flex flex-wrap gap-1">
118
118
  {includedNamespaces.map((ns: string) => (
119
- <span key={ns} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{ns}</span>
119
+ <span key={ns} className="badge-sm bg-theme-hover text-theme-text-secondary">{ns}</span>
120
120
  ))}
121
121
  </div>
122
122
  } />
@@ -128,7 +128,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
128
128
  <Property label="Excluded Namespaces" value={
129
129
  <div className="flex flex-wrap gap-1">
130
130
  {excludedNamespaces.map((ns: string) => (
131
- <span key={ns} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{ns}</span>
131
+ <span key={ns} className="badge-sm bg-red-500/10 text-red-400">{ns}</span>
132
132
  ))}
133
133
  </div>
134
134
  } />
@@ -137,7 +137,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
137
137
  <Property label="Included Resources" value={
138
138
  <div className="flex flex-wrap gap-1">
139
139
  {includedResources.map((r: string) => (
140
- <span key={r} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{r}</span>
140
+ <span key={r} className="badge-sm bg-theme-hover text-theme-text-secondary">{r}</span>
141
141
  ))}
142
142
  </div>
143
143
  } />
@@ -146,7 +146,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
146
146
  <Property label="Excluded Resources" value={
147
147
  <div className="flex flex-wrap gap-1">
148
148
  {excludedResources.map((r: string) => (
149
- <span key={r} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{r}</span>
149
+ <span key={r} className="badge-sm bg-red-500/10 text-red-400">{r}</span>
150
150
  ))}
151
151
  </div>
152
152
  } />
@@ -170,7 +170,7 @@ export function VeleroBackupRenderer({ data }: VeleroBackupRendererProps) {
170
170
  <Property label="Volume Snapshot Locations" value={
171
171
  <div className="flex flex-wrap gap-1">
172
172
  {vslLocations.map((loc: string) => (
173
- <span key={loc} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{loc}</span>
173
+ <span key={loc} className="badge-sm bg-theme-hover text-theme-text-secondary">{loc}</span>
174
174
  ))}
175
175
  </div>
176
176
  } />
@@ -64,7 +64,7 @@ export function VeleroRestoreRenderer({ data }: VeleroRestoreRendererProps) {
64
64
  <Section title="Status" icon={ArchiveRestore} defaultExpanded>
65
65
  <PropertyList>
66
66
  <Property label="Phase" value={
67
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', restoreStatus.color)}>
67
+ <span className={clsx('badge', restoreStatus.color)}>
68
68
  {restoreStatus.text}
69
69
  </span>
70
70
  } />
@@ -108,7 +108,7 @@ export function VeleroRestoreRenderer({ data }: VeleroRestoreRendererProps) {
108
108
  <Property label="Included Namespaces" value={
109
109
  <div className="flex flex-wrap gap-1">
110
110
  {includedNamespaces.map((ns: string) => (
111
- <span key={ns} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{ns}</span>
111
+ <span key={ns} className="badge-sm bg-theme-hover text-theme-text-secondary">{ns}</span>
112
112
  ))}
113
113
  </div>
114
114
  } />
@@ -120,7 +120,7 @@ export function VeleroRestoreRenderer({ data }: VeleroRestoreRendererProps) {
120
120
  <Property label="Excluded Namespaces" value={
121
121
  <div className="flex flex-wrap gap-1">
122
122
  {excludedNamespaces.map((ns: string) => (
123
- <span key={ns} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{ns}</span>
123
+ <span key={ns} className="badge-sm bg-red-500/10 text-red-400">{ns}</span>
124
124
  ))}
125
125
  </div>
126
126
  } />
@@ -129,7 +129,7 @@ export function VeleroRestoreRenderer({ data }: VeleroRestoreRendererProps) {
129
129
  <Property label="Included Resources" value={
130
130
  <div className="flex flex-wrap gap-1">
131
131
  {includedResources.map((r: string) => (
132
- <span key={r} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{r}</span>
132
+ <span key={r} className="badge-sm bg-theme-hover text-theme-text-secondary">{r}</span>
133
133
  ))}
134
134
  </div>
135
135
  } />
@@ -138,7 +138,7 @@ export function VeleroRestoreRenderer({ data }: VeleroRestoreRendererProps) {
138
138
  <Property label="Excluded Resources" value={
139
139
  <div className="flex flex-wrap gap-1">
140
140
  {excludedResources.map((r: string) => (
141
- <span key={r} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{r}</span>
141
+ <span key={r} className="badge-sm bg-red-500/10 text-red-400">{r}</span>
142
142
  ))}
143
143
  </div>
144
144
  } />
@@ -49,7 +49,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
49
49
  <Section title="Schedule" icon={Clock} defaultExpanded>
50
50
  <PropertyList>
51
51
  <Property label="Status" value={
52
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', scheduleStatus.color)}>
52
+ <span className={clsx('badge', scheduleStatus.color)}>
53
53
  {scheduleStatus.text}
54
54
  </span>
55
55
  } />
@@ -75,7 +75,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
75
75
  <Property label="Included Namespaces" value={
76
76
  <div className="flex flex-wrap gap-1">
77
77
  {templateIncludedNs.map((ns: string) => (
78
- <span key={ns} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{ns}</span>
78
+ <span key={ns} className="badge-sm bg-theme-hover text-theme-text-secondary">{ns}</span>
79
79
  ))}
80
80
  </div>
81
81
  } />
@@ -87,7 +87,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
87
87
  <Property label="Excluded Namespaces" value={
88
88
  <div className="flex flex-wrap gap-1">
89
89
  {templateExcludedNs.map((ns: string) => (
90
- <span key={ns} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{ns}</span>
90
+ <span key={ns} className="badge-sm bg-red-500/10 text-red-400">{ns}</span>
91
91
  ))}
92
92
  </div>
93
93
  } />
@@ -96,7 +96,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
96
96
  <Property label="Included Resources" value={
97
97
  <div className="flex flex-wrap gap-1">
98
98
  {templateIncludedResources.map((r: string) => (
99
- <span key={r} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{r}</span>
99
+ <span key={r} className="badge-sm bg-theme-hover text-theme-text-secondary">{r}</span>
100
100
  ))}
101
101
  </div>
102
102
  } />
@@ -105,7 +105,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
105
105
  <Property label="Excluded Resources" value={
106
106
  <div className="flex flex-wrap gap-1">
107
107
  {templateExcludedResources.map((r: string) => (
108
- <span key={r} className="px-1.5 py-0.5 bg-red-500/10 rounded text-xs text-red-400">{r}</span>
108
+ <span key={r} className="badge-sm bg-red-500/10 text-red-400">{r}</span>
109
109
  ))}
110
110
  </div>
111
111
  } />
@@ -120,7 +120,7 @@ export function VeleroScheduleRenderer({ data }: VeleroScheduleRendererProps) {
120
120
  <Property label="Volume Snapshot Locations" value={
121
121
  <div className="flex flex-wrap gap-1">
122
122
  {template.volumeSnapshotLocations.map((loc: string) => (
123
- <span key={loc} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">{loc}</span>
123
+ <span key={loc} className="badge-sm bg-theme-hover text-theme-text-secondary">{loc}</span>
124
124
  ))}
125
125
  </div>
126
126
  } />
@@ -23,7 +23,7 @@ export function VeleroVSLRenderer({ data }: VeleroVSLRendererProps) {
23
23
  <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Config</div>
24
24
  <div className="flex flex-wrap gap-1">
25
25
  {Object.entries(config).map(([k, v]) => (
26
- <span key={k} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
26
+ <span key={k} className="badge-sm bg-theme-hover text-theme-text-secondary">
27
27
  {k}: {String(v)}
28
28
  </span>
29
29
  ))}
@@ -43,9 +43,9 @@ export function WebhookConfigRenderer({ data, isMutating }: WebhookConfigRendere
43
43
  label="Failure Policy"
44
44
  value={
45
45
  hasFailPolicy ? (
46
- <span className="px-1.5 py-0.5 rounded text-xs bg-red-500/20 text-red-400">Fail</span>
46
+ <span className="badge-sm status-unhealthy">Fail</span>
47
47
  ) : allIgnore ? (
48
- <span className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">Ignore</span>
48
+ <span className="badge-sm bg-theme-elevated text-theme-text-secondary">Ignore</span>
49
49
  ) : (
50
50
  'Mixed'
51
51
  )
@@ -69,30 +69,30 @@ export function WebhookConfigRenderer({ data, isMutating }: WebhookConfigRendere
69
69
  const objLabels = wh.objectSelector?.matchLabels
70
70
 
71
71
  return (
72
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
72
+ <div key={i} className="card-inner-lg">
73
73
  <div className="text-sm font-medium text-theme-text-primary">{wh.name}</div>
74
74
  <div className="text-xs text-theme-text-secondary mt-0.5">{target}</div>
75
75
 
76
76
  {/* Policy badges */}
77
77
  <div className="flex flex-wrap gap-1.5 mt-2">
78
- <span className={clsx('px-1.5 py-0.5 rounded text-xs', wh.failurePolicy === 'Fail' ? 'bg-red-500/20 text-red-400' : 'bg-theme-elevated text-theme-text-secondary')}>
78
+ <span className={clsx('badge-sm', wh.failurePolicy === 'Fail' ? 'bg-red-500/20 text-red-400' : 'bg-theme-elevated text-theme-text-secondary')}>
79
79
  {wh.failurePolicy || 'Fail'}
80
80
  </span>
81
81
  {wh.sideEffects && (
82
- <span className={clsx('px-1.5 py-0.5 rounded text-xs', getSideEffectsColor(wh.sideEffects))}>
82
+ <span className={clsx('badge-sm', getSideEffectsColor(wh.sideEffects))}>
83
83
  {wh.sideEffects}
84
84
  </span>
85
85
  )}
86
- <span className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">
86
+ <span className="badge-sm bg-theme-elevated text-theme-text-secondary">
87
87
  {wh.timeoutSeconds ?? 10}s
88
88
  </span>
89
89
  {wh.matchPolicy && (
90
- <span className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">
90
+ <span className="badge-sm bg-theme-elevated text-theme-text-secondary">
91
91
  {wh.matchPolicy}
92
92
  </span>
93
93
  )}
94
94
  {isMutating && wh.reinvocationPolicy && (
95
- <span className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">
95
+ <span className="badge-sm bg-theme-elevated text-theme-text-secondary">
96
96
  {wh.reinvocationPolicy}
97
97
  </span>
98
98
  )}
@@ -126,7 +126,7 @@ export function WebhookConfigRenderer({ data, isMutating }: WebhookConfigRendere
126
126
  <div className="text-xs text-theme-text-tertiary mb-1">Namespace Selector</div>
127
127
  <div className="flex flex-wrap gap-1">
128
128
  {Object.entries(nsLabels).map(([k, v]) => (
129
- <span key={k} className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">{k}={String(v)}</span>
129
+ <span key={k} className="badge-sm bg-theme-elevated text-theme-text-secondary">{k}={String(v)}</span>
130
130
  ))}
131
131
  </div>
132
132
  </div>
@@ -136,7 +136,7 @@ export function WebhookConfigRenderer({ data, isMutating }: WebhookConfigRendere
136
136
  <div className="text-xs text-theme-text-tertiary mb-1">Object Selector</div>
137
137
  <div className="flex flex-wrap gap-1">
138
138
  {Object.entries(objLabels).map(([k, v]) => (
139
- <span key={k} className="px-1.5 py-0.5 rounded text-xs bg-theme-elevated text-theme-text-secondary">{k}={String(v)}</span>
139
+ <span key={k} className="badge-sm bg-theme-elevated text-theme-text-secondary">{k}={String(v)}</span>
140
140
  ))}
141
141
  </div>
142
142
  </div>
@@ -155,7 +155,7 @@ export function WorkflowRenderer({ data }: WorkflowRendererProps) {
155
155
  <Section title="Status" icon={Play}>
156
156
  <PropertyList>
157
157
  <Property label="Phase" value={
158
- <span className={clsx('px-2 py-0.5 rounded text-xs', getPhaseBadgeClass(phase))}>
158
+ <span className={clsx('badge', getPhaseBadgeClass(phase))}>
159
159
  {phase}
160
160
  </span>
161
161
  } />
@@ -174,7 +174,7 @@ export function WorkflowRenderer({ data }: WorkflowRendererProps) {
174
174
  <Section title={`Steps (${steps.length})`} defaultExpanded>
175
175
  <div className="space-y-1.5">
176
176
  {steps.map(step => (
177
- <div key={step.id} className="flex items-center gap-2 text-sm bg-theme-elevated/30 rounded px-3 py-2">
177
+ <div key={step.id} className="flex items-center gap-2 text-sm card-inner px-3 py-2">
178
178
  <StepStatusIcon phase={step.phase} />
179
179
  <span className="flex-1 text-theme-text-primary">{step.displayName}</span>
180
180
  <span className="text-xs text-theme-text-secondary">{getStepDuration(step) || '-'}</span>
@@ -45,7 +45,7 @@ export function WorkflowTemplateRenderer({ data }: WorkflowTemplateRendererProps
45
45
  const type = getTemplateType(template)
46
46
  const image = getTemplateImage(template)
47
47
  return (
48
- <div key={template.name} className="bg-theme-elevated/30 rounded px-3 py-2 text-sm">
48
+ <div key={template.name} className="card-inner px-3 py-2 text-sm">
49
49
  <div className="font-medium text-theme-text-primary">{template.name}</div>
50
50
  <div className="text-xs text-theme-text-secondary mt-0.5">{type}</div>
51
51
  {image && (
@@ -78,7 +78,7 @@ export function WorkflowTemplateRenderer({ data }: WorkflowTemplateRendererProps
78
78
  {imagePullSecrets.map((secret: any) => (
79
79
  <span
80
80
  key={secret.name}
81
- className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary"
81
+ className="badge bg-theme-elevated text-theme-text-secondary"
82
82
  >
83
83
  {secret.name}
84
84
  </span>
@@ -266,7 +266,7 @@ export function WorkloadRenderer({ kind, data, onNavigate, onViewPods, onScale,
266
266
  <button
267
267
  onClick={handleScale}
268
268
  disabled={isScalePending || targetReplicas === (spec.replicas || 0)}
269
- className="flex-1 px-3 py-2 text-sm text-white bg-blue-600 hover:bg-blue-500 disabled:bg-blue-600/50 disabled:cursor-not-allowed rounded-lg transition-colors"
269
+ className="flex-1 px-3 py-2 text-sm btn-brand disabled:cursor-not-allowed rounded-lg"
270
270
  >
271
271
  {isScalePending ? 'Scaling...' : 'Apply'}
272
272
  </button>
@@ -25,7 +25,7 @@ export function ArgoApplicationCell({ resource, column }: { resource: any; colum
25
25
  case 'sync': {
26
26
  const { status, color } = getArgoApplicationSync(resource)
27
27
  return (
28
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', color)}>
28
+ <span className={clsx('badge', color)}>
29
29
  {status}
30
30
  </span>
31
31
  )
@@ -33,7 +33,7 @@ export function ArgoApplicationCell({ resource, column }: { resource: any; colum
33
33
  case 'health': {
34
34
  const { status, color } = getArgoApplicationHealth(resource)
35
35
  return (
36
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', color)}>
36
+ <span className={clsx('badge', color)}>
37
37
  {status}
38
38
  </span>
39
39
  )
@@ -76,7 +76,7 @@ export function ArgoApplicationSetCell({ resource, column }: { resource: any; co
76
76
  case 'status': {
77
77
  const status = getArgoApplicationSetStatus(resource)
78
78
  return (
79
- <span className={clsx('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', status.color)}>
79
+ <span className={clsx('badge', status.color)}>
80
80
  {status.text}
81
81
  </span>
82
82
  )