@skyhook-io/k8s-ui 1.2.4 → 1.3.1

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 (129) hide show
  1. package/package.json +4 -3
  2. package/src/components/dock/BottomDock.tsx +24 -6
  3. package/src/components/dock/DockContext.tsx +9 -1
  4. package/src/components/dock/LocalTerminalTab.tsx +1 -1
  5. package/src/components/dock/NodeTerminalTab.tsx +1 -1
  6. package/src/components/dock/TerminalTab.tsx +2 -2
  7. package/src/components/gitops/GitOpsActions.tsx +12 -11
  8. package/src/components/gitops/GitOpsStatusBadge.tsx +6 -6
  9. package/src/components/logs/LogCore.tsx +8 -8
  10. package/src/components/logs/LogsViewer.tsx +8 -3
  11. package/src/components/logs/WorkloadLogsViewer.tsx +37 -9
  12. package/src/components/logs/useLogStream.ts +20 -0
  13. package/src/components/resources/ResourcesSidebar.tsx +10 -10
  14. package/src/components/resources/ResourcesView.tsx +49 -48
  15. package/src/components/resources/renderers/AlertRenderer.tsx +2 -2
  16. package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +2 -2
  17. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +1 -1
  18. package/src/components/resources/renderers/CertificateRenderer.tsx +3 -3
  19. package/src/components/resources/renderers/CertificateRequestRenderer.tsx +3 -3
  20. package/src/components/resources/renderers/ChallengeRenderer.tsx +2 -2
  21. package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +3 -3
  22. package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +3 -3
  23. package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +2 -2
  24. package/src/components/resources/renderers/ContourHTTPProxyRenderer.tsx +1 -1
  25. package/src/components/resources/renderers/EventRenderer.tsx +1 -1
  26. package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +2 -2
  27. package/src/components/resources/renderers/ExternalSecretRenderer.tsx +2 -2
  28. package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +1 -1
  29. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +5 -5
  30. package/src/components/resources/renderers/GatewayClassRenderer.tsx +1 -1
  31. package/src/components/resources/renderers/GatewayRenderer.tsx +3 -3
  32. package/src/components/resources/renderers/GenericRenderer.tsx +1 -1
  33. package/src/components/resources/renderers/HPARenderer.tsx +1 -1
  34. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +5 -5
  35. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +1 -1
  36. package/src/components/resources/renderers/IngressClassRenderer.tsx +1 -1
  37. package/src/components/resources/renderers/IngressRenderer.tsx +1 -1
  38. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +10 -10
  39. package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +1 -1
  40. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +2 -2
  41. package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +2 -2
  42. package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +6 -6
  43. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +5 -5
  44. package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +5 -5
  45. package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +2 -2
  46. package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +4 -4
  47. package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +3 -3
  48. package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +3 -3
  49. package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +5 -5
  50. package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +2 -2
  51. package/src/components/resources/renderers/KnativeEventingRenderer.tsx +5 -5
  52. package/src/components/resources/renderers/KnativeFlowRenderer.tsx +4 -4
  53. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +8 -8
  54. package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +3 -3
  55. package/src/components/resources/renderers/KnativeRouteRenderer.tsx +1 -1
  56. package/src/components/resources/renderers/KnativeServiceRenderer.tsx +2 -2
  57. package/src/components/resources/renderers/KnativeSourceRenderer.tsx +6 -6
  58. package/src/components/resources/renderers/KustomizationRenderer.tsx +1 -1
  59. package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +4 -4
  60. package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +6 -6
  61. package/src/components/resources/renderers/NodeRenderer.tsx +5 -5
  62. package/src/components/resources/renderers/OrderRenderer.tsx +3 -3
  63. package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +1 -1
  64. package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +1 -1
  65. package/src/components/resources/renderers/PodMonitorRenderer.tsx +3 -3
  66. package/src/components/resources/renderers/PodRenderer.tsx +10 -10
  67. package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +2 -2
  68. package/src/components/resources/renderers/RoleBindingRenderer.tsx +3 -3
  69. package/src/components/resources/renderers/RoleRenderer.tsx +8 -8
  70. package/src/components/resources/renderers/RolloutRenderer.tsx +1 -1
  71. package/src/components/resources/renderers/RuntimeClassRenderer.tsx +2 -2
  72. package/src/components/resources/renderers/SealedSecretRenderer.tsx +2 -2
  73. package/src/components/resources/renderers/SecretRenderer.tsx +3 -3
  74. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +1 -1
  75. package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +3 -3
  76. package/src/components/resources/renderers/ServiceRenderer.tsx +1 -1
  77. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +5 -5
  78. package/src/components/resources/renderers/StorageClassRenderer.tsx +1 -1
  79. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +1 -1
  80. package/src/components/resources/renderers/VPARenderer.tsx +2 -2
  81. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +2 -2
  82. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +6 -6
  83. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +5 -5
  84. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +6 -6
  85. package/src/components/resources/renderers/VeleroVSLRenderer.tsx +1 -1
  86. package/src/components/resources/renderers/WebhookConfigRenderer.tsx +10 -10
  87. package/src/components/resources/renderers/WorkflowRenderer.tsx +2 -2
  88. package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +2 -2
  89. package/src/components/resources/renderers/WorkloadRenderer.tsx +1 -1
  90. package/src/components/resources/renderers/argo-cells.tsx +3 -3
  91. package/src/components/resources/renderers/certmanager-cells.tsx +6 -6
  92. package/src/components/resources/renderers/cnpg-cells.tsx +5 -5
  93. package/src/components/resources/renderers/eso-cells.tsx +4 -4
  94. package/src/components/resources/renderers/flux-cells.tsx +6 -6
  95. package/src/components/resources/renderers/istio-cells.tsx +9 -9
  96. package/src/components/resources/renderers/karpenter-cells.tsx +3 -3
  97. package/src/components/resources/renderers/keda-cells.tsx +2 -2
  98. package/src/components/resources/renderers/knative-cells.tsx +2 -2
  99. package/src/components/resources/renderers/kyverno-cells.tsx +3 -3
  100. package/src/components/resources/renderers/prometheus-cells.tsx +3 -3
  101. package/src/components/resources/renderers/trivy-cells.tsx +4 -4
  102. package/src/components/resources/renderers/velero-cells.tsx +4 -4
  103. package/src/components/shared/EditableYamlView.tsx +1 -1
  104. package/src/components/shared/ResourceActionsBar.tsx +17 -17
  105. package/src/components/shared/ResourceRendererDispatch.tsx +8 -7
  106. package/src/components/timeline/DiffViewer.tsx +131 -0
  107. package/src/components/timeline/TimelineList.tsx +817 -0
  108. package/src/components/timeline/index.ts +2 -0
  109. package/src/components/topology/GroupNode.tsx +189 -79
  110. package/src/components/topology/K8sResourceNode.tsx +5 -5
  111. package/src/components/topology/TopologyControls.tsx +2 -2
  112. package/src/components/topology/TopologyGraph.tsx +362 -62
  113. package/src/components/topology/layout.ts +288 -92
  114. package/src/components/topology/topology.css +112 -1
  115. package/src/components/ui/Badge.tsx +178 -0
  116. package/src/components/ui/HealthRing.tsx +70 -35
  117. package/src/components/ui/MetricsChart.tsx +2 -2
  118. package/src/components/ui/Toast.tsx +74 -27
  119. package/src/components/ui/drawer-components.tsx +12 -31
  120. package/src/components/workload/ResourceDetailDrawer.tsx +4 -4
  121. package/src/components/workload/WorkloadView.tsx +10 -10
  122. package/src/theme/components.css +195 -0
  123. package/src/theme/tailwind-theme.css +13 -13
  124. package/src/theme/variables.css +46 -29
  125. package/src/types/core.ts +41 -0
  126. package/src/utils/badge-colors.ts +54 -205
  127. package/src/utils/download.ts +18 -3
  128. package/src/utils/log-format.ts +0 -8
  129. package/tsconfig.json +0 -1
@@ -191,7 +191,7 @@ export function FluxHelmReleaseRenderer({ data }: FluxHelmReleaseRendererProps)
191
191
  </span>
192
192
  <span
193
193
  className={clsx(
194
- 'px-1.5 py-0.5 rounded text-xs',
194
+ 'badge-sm',
195
195
  release.status === 'deployed'
196
196
  ? 'status-healthy'
197
197
  : release.status === 'failed'
@@ -77,7 +77,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
77
77
  hostnames.length > 0 ? (
78
78
  <div className="flex flex-wrap gap-1">
79
79
  {hostnames.map((h: string) => (
80
- <span key={h} className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary">{h}</span>
80
+ <span key={h} className="badge bg-theme-elevated text-theme-text-secondary">{h}</span>
81
81
  ))}
82
82
  </div>
83
83
  ) : (
@@ -111,7 +111,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
111
111
  const multiBackend = backendRefs.length > 1
112
112
 
113
113
  return (
114
- <div key={ruleIdx} className="bg-theme-elevated/30 rounded p-2.5">
114
+ <div key={ruleIdx} className="card-inner">
115
115
  <div className="text-xs font-medium text-theme-text-tertiary mb-1.5">
116
116
  Rule {ruleIdx + 1}
117
117
  </div>
@@ -224,7 +224,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
224
224
  const resolved = conditions.find((c: any) => c.type === 'ResolvedRefs')
225
225
 
226
226
  return (
227
- <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="bg-theme-elevated/30 rounded p-2.5">
227
+ <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="card-inner">
228
228
  <div className="text-sm font-medium text-theme-text-primary mb-1.5">
229
229
  {ref.namespace ? `${ref.namespace}/` : ''}{ref.name || 'unknown'}
230
230
  {ref.sectionName ? ` (${ref.sectionName})` : ''}
@@ -232,7 +232,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
232
232
  <div className="flex flex-wrap gap-2">
233
233
  {accepted && (
234
234
  <span className={clsx(
235
- 'px-2 py-0.5 rounded text-xs font-medium',
235
+ 'badge',
236
236
  accepted.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
237
237
  )}>
238
238
  {accepted.status === 'True' ? 'Accepted' : 'Not Accepted'}
@@ -240,7 +240,7 @@ export function GRPCRouteRenderer({ data, onNavigate }: GRPCRouteRendererProps)
240
240
  )}
241
241
  {resolved && (
242
242
  <span className={clsx(
243
- 'px-2 py-0.5 rounded text-xs font-medium',
243
+ 'badge',
244
244
  resolved.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'
245
245
  )}>
246
246
  {resolved.status === 'True' ? 'Refs Resolved' : 'Unresolved Refs'}
@@ -35,7 +35,7 @@ export function GatewayClassRenderer({ data }: GatewayClassRendererProps) {
35
35
  label="Accepted"
36
36
  value={
37
37
  <span className={clsx(
38
- 'px-2 py-0.5 rounded text-xs font-medium',
38
+ 'badge',
39
39
  isAccepted
40
40
  ? 'bg-green-500/20 text-green-400'
41
41
  : isNotAccepted
@@ -68,7 +68,7 @@ export function GatewayRenderer({ data, onNavigate }: GatewayRendererProps) {
68
68
  label="Accepted"
69
69
  value={
70
70
  <span className={clsx(
71
- 'px-2 py-0.5 rounded text-xs font-medium',
71
+ 'badge',
72
72
  isAccepted
73
73
  ? 'bg-green-500/20 text-green-400'
74
74
  : isNotAccepted
@@ -83,7 +83,7 @@ export function GatewayRenderer({ data, onNavigate }: GatewayRendererProps) {
83
83
  label="Programmed"
84
84
  value={
85
85
  <span className={clsx(
86
- 'px-2 py-0.5 rounded text-xs font-medium',
86
+ 'badge',
87
87
  isProgrammed
88
88
  ? 'bg-green-500/20 text-green-400'
89
89
  : isNotProgrammed
@@ -127,7 +127,7 @@ export function GatewayRenderer({ data, onNavigate }: GatewayRendererProps) {
127
127
  const isHTTPS = listener.protocol === 'HTTPS' || listener.protocol === 'TLS'
128
128
 
129
129
  return (
130
- <div key={listener.name} className="bg-theme-elevated/30 rounded p-3">
130
+ <div key={listener.name} className="card-inner-lg">
131
131
  <div className="flex items-center justify-between mb-2">
132
132
  <div className="flex items-center gap-2">
133
133
  {isHTTPS && <Lock className="w-3.5 h-3.5 text-green-400" />}
@@ -428,7 +428,7 @@ function GenericConditionsSection({ conditions }: { conditions: any[] }) {
428
428
  <div className="flex items-center gap-2 flex-wrap">
429
429
  <span className="text-theme-text-primary font-medium">{cond.type}</span>
430
430
  <span className={clsx(
431
- 'px-1.5 py-0.5 rounded text-xs font-medium',
431
+ 'badge-sm',
432
432
  isTrue ? 'bg-theme-elevated text-theme-text-secondary' : 'bg-red-500/20 text-red-400'
433
433
  )}>
434
434
  {cond.status}
@@ -136,7 +136,7 @@ export function HPARenderer({ data, onNavigate }: HPARendererProps) {
136
136
  const current = metric.resource?.current?.averageUtilization || metric.resource?.current?.averageValue
137
137
  const target = spec.metrics?.[i]?.resource?.target?.averageUtilization || spec.metrics?.[i]?.resource?.target?.averageValue
138
138
  return (
139
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
139
+ <div key={i} className="card-inner">
140
140
  <div className="flex items-center justify-between text-sm">
141
141
  <span className="text-theme-text-primary">{metric.resource?.name || metric.type}</span>
142
142
  <span className="text-theme-text-secondary">{current}{typeof current === 'number' ? '%' : ''} / {target}{typeof target === 'number' ? '%' : ''}</span>
@@ -77,7 +77,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
77
77
  hostnames.length > 0 ? (
78
78
  <div className="flex flex-wrap gap-1">
79
79
  {hostnames.map((h: string) => (
80
- <span key={h} className="px-2 py-0.5 bg-theme-elevated rounded text-xs text-theme-text-secondary">{h}</span>
80
+ <span key={h} className="badge bg-theme-elevated text-theme-text-secondary">{h}</span>
81
81
  ))}
82
82
  </div>
83
83
  ) : (
@@ -111,7 +111,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
111
111
  const multiBackend = backendRefs.length > 1
112
112
 
113
113
  return (
114
- <div key={ruleIdx} className="bg-theme-elevated/30 rounded p-2.5">
114
+ <div key={ruleIdx} className="card-inner">
115
115
  <div className="text-xs font-medium text-theme-text-tertiary mb-1.5">
116
116
  Rule {ruleIdx + 1}
117
117
  </div>
@@ -256,7 +256,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
256
256
  const resolved = conditions.find((c: any) => c.type === 'ResolvedRefs')
257
257
 
258
258
  return (
259
- <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="bg-theme-elevated/30 rounded p-2.5">
259
+ <div key={`${ref.namespace || ''}-${ref.name}-${idx}`} className="card-inner">
260
260
  <div className="text-sm font-medium text-theme-text-primary mb-1.5">
261
261
  {ref.namespace ? `${ref.namespace}/` : ''}{ref.name || 'unknown'}
262
262
  {ref.sectionName ? ` (${ref.sectionName})` : ''}
@@ -264,7 +264,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
264
264
  <div className="flex flex-wrap gap-2">
265
265
  {accepted && (
266
266
  <span className={clsx(
267
- 'px-2 py-0.5 rounded text-xs font-medium',
267
+ 'badge',
268
268
  accepted.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
269
269
  )}>
270
270
  {accepted.status === 'True' ? 'Accepted' : 'Not Accepted'}
@@ -272,7 +272,7 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
272
272
  )}
273
273
  {resolved && (
274
274
  <span className={clsx(
275
- 'px-2 py-0.5 rounded text-xs font-medium',
275
+ 'badge',
276
276
  resolved.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'
277
277
  )}>
278
278
  {resolved.status === 'True' ? 'Refs Resolved' : 'Unresolved Refs'}
@@ -97,7 +97,7 @@ export function HelmRepositoryRenderer({ data }: HelmRepositoryRendererProps) {
97
97
  label="Type"
98
98
  value={
99
99
  <span className={clsx(
100
- 'px-2 py-0.5 rounded text-xs font-medium',
100
+ 'badge',
101
101
  isOCI ? 'bg-purple-500/20 text-purple-400' : 'bg-blue-500/20 text-blue-400'
102
102
  )}>
103
103
  {isOCI ? 'OCI' : 'HTTP'}
@@ -21,7 +21,7 @@ export function IngressClassRenderer({ data }: IngressClassRendererProps) {
21
21
  label="Default"
22
22
  value={
23
23
  <span className={clsx(
24
- 'px-2 py-0.5 rounded text-xs font-medium',
24
+ 'badge',
25
25
  isDefault
26
26
  ? 'bg-green-500/20 text-green-400'
27
27
  : 'bg-gray-500/20 text-gray-400'
@@ -53,7 +53,7 @@ export function IngressRenderer({ data, onNavigate }: IngressRendererProps) {
53
53
  <Section title="Rules" defaultExpanded>
54
54
  <div className="space-y-3">
55
55
  {rules.map((rule: any, i: number) => (
56
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
56
+ <div key={i} className="card-inner-lg">
57
57
  <div className="flex items-center gap-2 mb-2">
58
58
  {tls.some((t: any) => t.hosts?.includes(rule.host)) && (
59
59
  <Shield className="w-3.5 h-3.5 text-green-400" />
@@ -51,7 +51,7 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
51
51
  <PropertyList>
52
52
  <Property label="Action" value={
53
53
  <span className={clsx(
54
- 'px-2 py-0.5 rounded text-xs font-medium',
54
+ 'badge',
55
55
  actionColors[action] || 'bg-gray-500/20 text-gray-400'
56
56
  )}>
57
57
  {action}
@@ -77,7 +77,7 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
77
77
  <Section title={`Rules (${rules.length})`} defaultExpanded>
78
78
  <div className="space-y-3">
79
79
  {rules.map((rule: any, i: number) => (
80
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
80
+ <div key={i} className="card-inner-lg">
81
81
  <div className="text-sm font-medium text-theme-text-primary mb-2">Rule {i + 1}</div>
82
82
 
83
83
  {/* From (sources) */}
@@ -87,22 +87,22 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
87
87
  {rule.from.map((f: any, fi: number) => (
88
88
  <div key={fi} className="flex flex-wrap gap-1 mb-1">
89
89
  {f.source?.principals?.map((p: string, pi: number) => (
90
- <span key={`p-${pi}`} className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded text-xs">
90
+ <span key={`p-${pi}`} className="badge-sm bg-blue-500/10 text-blue-400">
91
91
  principal: {p}
92
92
  </span>
93
93
  ))}
94
94
  {f.source?.namespaces?.map((n: string, ni: number) => (
95
- <span key={`n-${ni}`} className="px-1.5 py-0.5 bg-purple-500/10 text-purple-400 rounded text-xs">
95
+ <span key={`n-${ni}`} className="badge-sm bg-purple-500/10 text-purple-400">
96
96
  namespace: {n}
97
97
  </span>
98
98
  ))}
99
99
  {f.source?.ipBlocks?.map((ip: string, ipi: number) => (
100
- <span key={`ip-${ipi}`} className="px-1.5 py-0.5 bg-orange-500/10 text-orange-400 rounded text-xs">
100
+ <span key={`ip-${ipi}`} className="badge-sm bg-orange-500/10 text-orange-400">
101
101
  IP: {ip}
102
102
  </span>
103
103
  ))}
104
104
  {f.source?.requestPrincipals?.map((rp: string, rpi: number) => (
105
- <span key={`rp-${rpi}`} className="px-1.5 py-0.5 bg-cyan-500/10 text-cyan-400 rounded text-xs">
105
+ <span key={`rp-${rpi}`} className="badge-sm bg-cyan-500/10 text-cyan-400">
106
106
  reqPrincipal: {rp}
107
107
  </span>
108
108
  ))}
@@ -118,22 +118,22 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
118
118
  {rule.to.map((t: any, ti: number) => (
119
119
  <div key={ti} className="flex flex-wrap gap-1 mb-1">
120
120
  {t.operation?.hosts?.map((h: string, hi: number) => (
121
- <span key={`h-${hi}`} className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded text-xs">
121
+ <span key={`h-${hi}`} className="badge-sm bg-blue-500/10 text-blue-400">
122
122
  host: {h}
123
123
  </span>
124
124
  ))}
125
125
  {t.operation?.ports?.map((p: string, pi: number) => (
126
- <span key={`p-${pi}`} className="px-1.5 py-0.5 bg-orange-500/10 text-orange-400 rounded text-xs">
126
+ <span key={`p-${pi}`} className="badge-sm bg-orange-500/10 text-orange-400">
127
127
  port: {p}
128
128
  </span>
129
129
  ))}
130
130
  {t.operation?.methods?.map((m: string, mi: number) => (
131
- <span key={`m-${mi}`} className="px-1.5 py-0.5 bg-green-500/10 text-green-400 rounded text-xs">
131
+ <span key={`m-${mi}`} className="badge-sm bg-green-500/10 text-green-400">
132
132
  method: {m}
133
133
  </span>
134
134
  ))}
135
135
  {t.operation?.paths?.map((p: string, pi: number) => (
136
- <span key={`path-${pi}`} className="px-1.5 py-0.5 bg-purple-500/10 text-purple-400 rounded text-xs">
136
+ <span key={`path-${pi}`} className="badge-sm bg-purple-500/10 text-purple-400">
137
137
  path: {p}
138
138
  </span>
139
139
  ))}
@@ -151,7 +151,7 @@ export function IstioDestinationRuleRenderer({ data, onNavigate }: IstioDestinat
151
151
  <Section title={`Subsets (${subsets.length})`} defaultExpanded>
152
152
  <div className="space-y-3">
153
153
  {subsets.map((subset, i) => (
154
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
154
+ <div key={i} className="card-inner-lg">
155
155
  <div className="text-sm font-medium text-theme-text-primary mb-2">{subset.name}</div>
156
156
  {Object.keys(subset.labels).length > 0 && (
157
157
  <div className="mb-2">
@@ -43,7 +43,7 @@ export function IstioGatewayRenderer({ data }: IstioGatewayRendererProps) {
43
43
  <Section title="Gateway" icon={Globe} defaultExpanded>
44
44
  <PropertyList>
45
45
  <Property label="Status" value={
46
- <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
46
+ <span className={clsx('badge', status.color)}>
47
47
  {status.text}
48
48
  </span>
49
49
  } />
@@ -64,7 +64,7 @@ export function IstioGatewayRenderer({ data }: IstioGatewayRendererProps) {
64
64
  const protocol = server.port.protocol || 'TCP'
65
65
 
66
66
  return (
67
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
67
+ <div key={i} className="card-inner-lg">
68
68
  <div className="flex items-center justify-between mb-2">
69
69
  <div className="flex items-center gap-2">
70
70
  {isSecure && <Lock className="w-3.5 h-3.5 text-green-400" />}
@@ -32,7 +32,7 @@ export function IstioPeerAuthenticationRenderer({ data }: IstioPeerAuthenticatio
32
32
  <PropertyList>
33
33
  <Property label="mTLS Mode" value={
34
34
  <span className={clsx(
35
- 'px-2 py-0.5 rounded text-xs font-medium',
35
+ 'badge',
36
36
  modeColors[mode] || modeColors.UNSET
37
37
  )}>
38
38
  {mode}
@@ -67,7 +67,7 @@ export function IstioPeerAuthenticationRenderer({ data }: IstioPeerAuthenticatio
67
67
  <div key={port} className="flex items-center gap-2 text-sm">
68
68
  <span className="text-theme-text-secondary font-mono">Port {port}</span>
69
69
  <span className={clsx(
70
- 'px-1.5 py-0.5 rounded text-xs font-medium',
70
+ 'badge-sm',
71
71
  modeColors[config.mode] || modeColors.UNSET
72
72
  )}>
73
73
  {config.mode}
@@ -38,14 +38,14 @@ export function IstioServiceEntryRenderer({ data }: IstioServiceEntryRendererPro
38
38
  <Section title="Service Entry" icon={Globe} defaultExpanded>
39
39
  <PropertyList>
40
40
  <Property label="Status" value={
41
- <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
41
+ <span className={clsx('badge', status.color)}>
42
42
  {status.text}
43
43
  </span>
44
44
  } />
45
45
  <Property label="Hosts" value={hosts.join(', ') || '-'} />
46
46
  <Property label="Location" value={
47
47
  <span className={clsx(
48
- 'px-2 py-0.5 rounded text-xs font-medium',
48
+ 'badge',
49
49
  location === 'MESH_EXTERNAL'
50
50
  ? 'bg-orange-500/20 text-orange-400'
51
51
  : 'bg-blue-500/20 text-blue-400'
@@ -63,7 +63,7 @@ export function IstioServiceEntryRenderer({ data }: IstioServiceEntryRendererPro
63
63
  <div className="space-y-1">
64
64
  {ports.map((port, i) => (
65
65
  <div key={i} className="flex items-center gap-2 text-sm">
66
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
66
+ <span className="badge-sm bg-theme-hover text-theme-text-secondary">
67
67
  {port.number}/{port.protocol || 'TCP'}
68
68
  </span>
69
69
  {port.name && (
@@ -80,12 +80,12 @@ export function IstioServiceEntryRenderer({ data }: IstioServiceEntryRendererPro
80
80
  <Section title={`Endpoints (${endpoints.length})`} defaultExpanded>
81
81
  <div className="space-y-2">
82
82
  {endpoints.map((endpoint, i) => (
83
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
83
+ <div key={i} className="card-inner">
84
84
  <div className="text-sm text-theme-text-primary">{endpoint.address}</div>
85
85
  {endpoint.ports && Object.keys(endpoint.ports).length > 0 && (
86
86
  <div className="flex flex-wrap gap-1 mt-1">
87
87
  {Object.entries(endpoint.ports).map(([name, port]) => (
88
- <span key={name} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
88
+ <span key={name} className="badge-sm bg-theme-hover text-theme-text-secondary">
89
89
  {name}: {port}
90
90
  </span>
91
91
  ))}
@@ -94,7 +94,7 @@ export function IstioServiceEntryRenderer({ data }: IstioServiceEntryRendererPro
94
94
  {endpoint.labels && Object.keys(endpoint.labels).length > 0 && (
95
95
  <div className="flex flex-wrap gap-1 mt-1">
96
96
  {Object.entries(endpoint.labels).map(([k, v]) => (
97
- <span key={k} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
97
+ <span key={k} className="badge-sm bg-theme-hover text-theme-text-secondary">
98
98
  {k}={v}
99
99
  </span>
100
100
  ))}
@@ -51,7 +51,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
51
51
  <Section title="Routing" icon={Network} defaultExpanded>
52
52
  <PropertyList>
53
53
  <Property label="Status" value={
54
- <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
54
+ <span className={clsx('badge', status.color)}>
55
55
  {status.text}
56
56
  </span>
57
57
  } />
@@ -62,7 +62,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
62
62
  {gateways.map((gw, i) => {
63
63
  // Gateway reference can be "namespace/name" or just "name" or "mesh"
64
64
  if (gw === 'mesh') {
65
- return <span key={i} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">mesh</span>
65
+ return <span key={i} className="badge-sm bg-theme-hover text-theme-text-secondary">mesh</span>
66
66
  }
67
67
  const parts = gw.split('/')
68
68
  const gwNs = parts.length === 2 ? parts[0] : ns
@@ -88,7 +88,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
88
88
  <Section title={`HTTP Routes (${httpRoutes.length})`} icon={Route} defaultExpanded>
89
89
  <div className="space-y-3">
90
90
  {httpRoutes.map((route: any, i: number) => (
91
- <div key={i} className="bg-theme-elevated/30 rounded p-3">
91
+ <div key={i} className="card-inner-lg">
92
92
  {/* Route header */}
93
93
  <div className="flex items-center gap-2 mb-2">
94
94
  <span className="text-sm font-medium text-theme-text-primary">
@@ -239,7 +239,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
239
239
  <Section title={`TCP Routes (${tcpRoutes.length})`} defaultExpanded>
240
240
  <div className="space-y-2">
241
241
  {tcpRoutes.map((route: any, i: number) => (
242
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
242
+ <div key={i} className="card-inner">
243
243
  {route.match && (
244
244
  <div className="text-xs text-theme-text-tertiary mb-1">
245
245
  Match: {JSON.stringify(route.match)}
@@ -263,7 +263,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
263
263
  <Section title={`TLS Routes (${tlsRoutes.length})`} defaultExpanded>
264
264
  <div className="space-y-2">
265
265
  {tlsRoutes.map((route: any, i: number) => (
266
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
266
+ <div key={i} className="card-inner">
267
267
  {route.match && (
268
268
  <div className="text-xs text-theme-text-tertiary mb-1">
269
269
  SNI: {route.match.map((m: any) => m.sniHosts?.join(', ')).join('; ')}
@@ -50,7 +50,7 @@ export function KarpenterEC2NodeClassRenderer({ data }: KarpenterEC2NodeClassRen
50
50
  <Section title={`Block Devices (${blockDevices.length})`} icon={HardDrive}>
51
51
  <div className="space-y-2">
52
52
  {blockDevices.map((bd: any, i: number) => (
53
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
53
+ <div key={i} className="card-inner">
54
54
  <div className="text-sm font-medium text-theme-text-primary mb-1">
55
55
  {bd.deviceName || `/dev/xvda`}
56
56
  </div>
@@ -102,9 +102,9 @@ export function KarpenterEC2NodeClassRenderer({ data }: KarpenterEC2NodeClassRen
102
102
  <div className="mb-3">
103
103
  <div className="text-xs text-theme-text-tertiary font-medium mb-1">Subnet Selector</div>
104
104
  {subnetTerms.map((term: any, i: number) => (
105
- <div key={i} className="bg-theme-elevated/30 rounded p-2 mb-1">
105
+ <div key={i} className="card-inner mb-1">
106
106
  {term.tags && Object.entries(term.tags).map(([key, val]) => (
107
- <span key={key} className="inline-flex items-center px-1.5 py-0.5 mr-1 mb-1 bg-theme-hover rounded text-xs text-theme-text-secondary">
107
+ <span key={key} className="badge-sm mr-1 mb-1 bg-theme-hover text-theme-text-secondary">
108
108
  {key}: {String(val)}
109
109
  </span>
110
110
  ))}
@@ -119,9 +119,9 @@ export function KarpenterEC2NodeClassRenderer({ data }: KarpenterEC2NodeClassRen
119
119
  <div>
120
120
  <div className="text-xs text-theme-text-tertiary font-medium mb-1">Security Group Selector</div>
121
121
  {sgTerms.map((term: any, i: number) => (
122
- <div key={i} className="bg-theme-elevated/30 rounded p-2 mb-1">
122
+ <div key={i} className="card-inner mb-1">
123
123
  {term.tags && Object.entries(term.tags).map(([key, val]) => (
124
- <span key={key} className="inline-flex items-center px-1.5 py-0.5 mr-1 mb-1 bg-theme-hover rounded text-xs text-theme-text-secondary">
124
+ <span key={key} className="badge-sm mr-1 mb-1 bg-theme-hover text-theme-text-secondary">
125
125
  {key}: {String(val)}
126
126
  </span>
127
127
  ))}
@@ -105,7 +105,7 @@ export function KarpenterNodeClaimRenderer({ data, onNavigate }: KarpenterNodeCl
105
105
  <Section title={`Requirements (${requirements.length})`} icon={Settings}>
106
106
  <div className="space-y-1">
107
107
  {requirements.map((req: any, i: number) => (
108
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
108
+ <div key={i} className="card-inner">
109
109
  <div className="flex items-center gap-2 text-sm">
110
110
  <span className="text-theme-text-primary font-medium">{req.key}</span>
111
111
  <span className="text-theme-text-tertiary">{req.operator}</span>
@@ -113,7 +113,7 @@ export function KarpenterNodeClaimRenderer({ data, onNavigate }: KarpenterNodeCl
113
113
  {req.values && req.values.length > 0 && (
114
114
  <div className="mt-1 flex flex-wrap gap-1">
115
115
  {req.values.map((v: string, vi: number) => (
116
- <span key={vi} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
116
+ <span key={vi} className="badge-sm bg-theme-hover text-theme-text-secondary">
117
117
  {v}
118
118
  </span>
119
119
  ))}
@@ -92,7 +92,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
92
92
  <div className="mt-2 space-y-1">
93
93
  <div className="text-xs text-theme-text-tertiary font-medium mb-1">Budgets</div>
94
94
  {disruption.budgets.map((budget: any, i: number) => (
95
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm text-theme-text-secondary">
95
+ <div key={i} className="card-inner text-sm text-theme-text-secondary">
96
96
  {budget.nodes && <span>Nodes: {budget.nodes}</span>}
97
97
  {budget.schedule && <span className="ml-2">Schedule: {budget.schedule}</span>}
98
98
  {budget.duration && <span className="ml-2">Duration: {budget.duration}</span>}
@@ -109,7 +109,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
109
109
  {Object.entries(templateLabels).map(([key, val]) => (
110
110
  <span
111
111
  key={key}
112
- className="inline-flex items-center px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary"
112
+ className="badge-sm bg-theme-hover text-theme-text-secondary"
113
113
  >
114
114
  {key}: {String(val)}
115
115
  </span>
@@ -123,7 +123,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
123
123
  <Section title={`Requirements (${requirements.length})`} icon={Settings} defaultExpanded>
124
124
  <div className="space-y-1">
125
125
  {requirements.map((req: any, i: number) => (
126
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
126
+ <div key={i} className="card-inner">
127
127
  <div className="flex items-center gap-2 text-sm">
128
128
  <span className="text-theme-text-primary font-medium">{req.key}</span>
129
129
  <span className="text-theme-text-tertiary">{req.operator}</span>
@@ -131,7 +131,7 @@ export function KarpenterNodePoolRenderer({ data, onNavigate }: KarpenterNodePoo
131
131
  {req.values && req.values.length > 0 && (
132
132
  <div className="mt-1 flex flex-wrap gap-1">
133
133
  {req.values.map((v: string, vi: number) => (
134
- <span key={vi} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
134
+ <span key={vi} className="badge-sm bg-theme-hover text-theme-text-secondary">
135
135
  {v}
136
136
  </span>
137
137
  ))}
@@ -57,14 +57,14 @@ export function KedaScaledJobRenderer({ data }: KedaScaledJobRendererProps) {
57
57
  <Section title={`Triggers (${triggers.length})`} defaultExpanded>
58
58
  <div className="space-y-2">
59
59
  {triggers.map((trigger, i) => (
60
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
60
+ <div key={i} className="card-inner">
61
61
  <div className="flex items-center gap-2 text-sm">
62
62
  <span className="text-theme-text-primary font-medium">{trigger.type}</span>
63
63
  {trigger.name && (
64
64
  <span className="text-theme-text-tertiary">({trigger.name})</span>
65
65
  )}
66
66
  {trigger.authenticationRef && (
67
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
67
+ <span className="badge-sm bg-theme-hover text-theme-text-secondary">
68
68
  auth: {trigger.authenticationRef.name}
69
69
  </span>
70
70
  )}
@@ -72,7 +72,7 @@ export function KedaScaledJobRenderer({ data }: KedaScaledJobRendererProps) {
72
72
  {trigger.metadata && Object.keys(trigger.metadata).length > 0 && (
73
73
  <div className="mt-1 flex flex-wrap gap-1">
74
74
  {Object.entries(trigger.metadata).map(([k, v]) => (
75
- <span key={k} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
75
+ <span key={k} className="badge-sm bg-theme-hover text-theme-text-secondary">
76
76
  {k}: {v}
77
77
  </span>
78
78
  ))}
@@ -104,14 +104,14 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
104
104
  <Section title={`Triggers (${triggers.length})`} defaultExpanded>
105
105
  <div className="space-y-2">
106
106
  {triggers.map((trigger, i) => (
107
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
107
+ <div key={i} className="card-inner">
108
108
  <div className="flex items-center gap-2 text-sm">
109
109
  <span className="text-theme-text-primary font-medium">{trigger.type}</span>
110
110
  {trigger.name && (
111
111
  <span className="text-theme-text-tertiary">({trigger.name})</span>
112
112
  )}
113
113
  {trigger.authenticationRef && (
114
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
114
+ <span className="badge-sm bg-theme-hover text-theme-text-secondary">
115
115
  auth: {trigger.authenticationRef.name}
116
116
  </span>
117
117
  )}
@@ -119,7 +119,7 @@ export function KedaScaledObjectRenderer({ data, onNavigate }: KedaScaledObjectR
119
119
  {trigger.metadata && Object.keys(trigger.metadata).length > 0 && (
120
120
  <div className="mt-1 flex flex-wrap gap-1">
121
121
  {Object.entries(trigger.metadata).map(([k, v]) => (
122
- <span key={k} className="px-1.5 py-0.5 bg-theme-hover rounded text-xs text-theme-text-secondary">
122
+ <span key={k} className="badge-sm bg-theme-hover text-theme-text-secondary">
123
123
  {k}: {v}
124
124
  </span>
125
125
  ))}
@@ -43,7 +43,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
43
43
  <Section title={`Secret References (${secretRefs.length})`} icon={KeyRound} defaultExpanded>
44
44
  <div className="space-y-2">
45
45
  {secretRefs.map((ref, i) => (
46
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
46
+ <div key={i} className="card-inner">
47
47
  <div className="flex flex-wrap gap-x-4 gap-y-1 text-sm">
48
48
  <span className="text-theme-text-primary font-medium">{ref.parameter}</span>
49
49
  <span className="text-theme-text-secondary">
@@ -61,7 +61,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
61
61
  <Section title={`Environment Variables (${envVars.length})`} defaultExpanded>
62
62
  <div className="space-y-2">
63
63
  {envVars.map((env, i) => (
64
- <div key={i} className="bg-theme-elevated/30 rounded p-2">
64
+ <div key={i} className="card-inner">
65
65
  <div className="flex flex-wrap gap-x-4 gap-y-1 text-sm">
66
66
  <span className="text-theme-text-primary font-medium">{env.parameter}</span>
67
67
  <span className="text-theme-text-secondary">Env: {env.name}</span>
@@ -90,7 +90,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
90
90
  <div className="mt-2 space-y-1">
91
91
  <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Secrets</div>
92
92
  {vault.secrets.map((s: any, i: number) => (
93
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
93
+ <div key={i} className="card-inner text-sm">
94
94
  <span className="text-theme-text-primary font-medium">{s.parameter}</span>
95
95
  <span className="text-theme-text-secondary ml-2">{s.path} / {s.key}</span>
96
96
  </div>
@@ -113,7 +113,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
113
113
  <div className="mt-2 space-y-1">
114
114
  <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Secrets</div>
115
115
  {azureKeyVault.secrets.map((s: any, i: number) => (
116
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
116
+ <div key={i} className="card-inner text-sm">
117
117
  <span className="text-theme-text-primary font-medium">{s.parameter}</span>
118
118
  <span className="text-theme-text-secondary ml-2">{s.name}</span>
119
119
  </div>
@@ -135,7 +135,7 @@ export function KedaTriggerAuthRenderer({ data, onNavigate }: KedaTriggerAuthRen
135
135
  <div className="mt-2 space-y-1">
136
136
  <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-1">Secrets</div>
137
137
  {awsSecretManager.secrets.map((s: any, i: number) => (
138
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
138
+ <div key={i} className="card-inner text-sm">
139
139
  <span className="text-theme-text-primary font-medium">{s.parameter}</span>
140
140
  <span className="text-theme-text-secondary ml-2">{s.name}</span>
141
141
  </div>
@@ -23,7 +23,7 @@ export function KnativeConfigurationRenderer({ data, onNavigate }: KnativeConfig
23
23
  <Section title="Overview" icon={Settings} defaultExpanded>
24
24
  <PropertyList>
25
25
  <Property label="Status" value={
26
- <span className={clsx('px-2 py-0.5 rounded text-xs font-medium', status.color)}>
26
+ <span className={clsx('badge', status.color)}>
27
27
  {status.text}
28
28
  </span>
29
29
  } />
@@ -50,7 +50,7 @@ export function KnativeConfigurationRenderer({ data, onNavigate }: KnativeConfig
50
50
  <Section title="Template" icon={Container} defaultExpanded>
51
51
  <div className="space-y-2">
52
52
  {containers.map((c: any, i: number) => (
53
- <div key={i} className="bg-theme-elevated/30 rounded p-2 text-sm">
53
+ <div key={i} className="card-inner text-sm">
54
54
  <div className="font-medium text-theme-text-primary">{c.name || 'container'}</div>
55
55
  <div className="text-xs text-theme-text-secondary truncate" title={c.image}>{c.image}</div>
56
56
  {c.ports && c.ports.length > 0 && (