@skyhook-io/k8s-ui 1.8.4 → 1.8.6

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 (55) hide show
  1. package/package.json +2 -2
  2. package/src/components/charts/PrometheusChartsView.tsx +3 -8
  3. package/src/components/gitops/GitOpsDetailLayout.tsx +2 -3
  4. package/src/components/gitops/GitOpsTableView.tsx +2 -4
  5. package/src/components/gitops/insights/GitOpsInsightViews.tsx +3 -6
  6. package/src/components/gitops/tree/GitOpsTreeGraph.tsx +3 -7
  7. package/src/components/logs/LogCore.tsx +1 -1
  8. package/src/components/resources/ResourcesView.tsx +34 -5
  9. package/src/components/resources/get-pod-phase-display.test.ts +115 -3
  10. package/src/components/resources/renderers/CronJobRenderer.tsx +14 -7
  11. package/src/components/resources/renderers/EndpointSliceRenderer.tsx +4 -3
  12. package/src/components/resources/renderers/GRPCRouteRenderer.tsx +9 -15
  13. package/src/components/resources/renderers/GatewayClassRenderer.tsx +3 -11
  14. package/src/components/resources/renderers/GatewayRenderer.tsx +11 -35
  15. package/src/components/resources/renderers/HTTPRouteRenderer.tsx +10 -16
  16. package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +3 -6
  17. package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +24 -28
  18. package/src/components/resources/renderers/IstioGatewayRenderer.tsx +19 -26
  19. package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +20 -19
  20. package/src/components/resources/renderers/JobRenderer.tsx +6 -5
  21. package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +9 -11
  22. package/src/components/resources/renderers/ServiceRenderer.tsx +1 -1
  23. package/src/components/resources/renderers/SimpleRouteRenderer.tsx +6 -12
  24. package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +11 -10
  25. package/src/components/resources/renderers/TraefikMiddlewareRenderer.tsx +185 -0
  26. package/src/components/resources/renderers/TraefikServersTransportRenderer.tsx +84 -0
  27. package/src/components/resources/renderers/TraefikServiceRenderer.tsx +118 -0
  28. package/src/components/resources/renderers/TraefikTLSOptionRenderer.tsx +62 -0
  29. package/src/components/resources/renderers/WorkflowRenderer.tsx +1 -1
  30. package/src/components/resources/renderers/WorkloadRenderer.tsx +1 -1
  31. package/src/components/resources/renderers/badge-no-handrolled.test.tsx +66 -0
  32. package/src/components/resources/renderers/contour-cells.tsx +6 -5
  33. package/src/components/resources/renderers/index.ts +4 -0
  34. package/src/components/resources/renderers/istio-cells.tsx +16 -25
  35. package/src/components/resources/resource-utils-cnpg.ts +1 -1
  36. package/src/components/resources/resource-utils-keda.ts +12 -6
  37. package/src/components/resources/resource-utils.ts +172 -57
  38. package/src/components/shared/ResourceActionsBar.tsx +1 -1
  39. package/src/components/shared/ResourceRendererDispatch.tsx +10 -0
  40. package/src/components/topology/TopologyControls.tsx +41 -9
  41. package/src/components/topology/TopologyGraph.tsx +20 -7
  42. package/src/components/topology/layout-elk-graph.test.ts +222 -0
  43. package/src/components/topology/layout.ts +96 -33
  44. package/src/components/topology/layout.worker.ts +18 -34
  45. package/src/components/ui/Badge.tsx +66 -3
  46. package/src/components/ui/ClusterName.tsx +12 -4
  47. package/src/components/ui/CodeViewer.tsx +1 -1
  48. package/src/components/ui/PaneLoader.tsx +6 -1
  49. package/src/components/ui/RestrictedState.tsx +152 -0
  50. package/src/components/ui/YamlEditor.tsx +1 -1
  51. package/src/components/ui/drawer-components.tsx +1 -1
  52. package/src/components/ui/index.ts +1 -0
  53. package/src/components/workload/WorkloadView.tsx +1 -1
  54. package/src/types/core.ts +37 -0
  55. package/src/utils/asset-url.ts +13 -0
@@ -1,6 +1,6 @@
1
1
  import { Globe, ArrowRight, Network, Filter } from 'lucide-react'
2
- import { clsx } from 'clsx'
3
2
  import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge } from '../../ui/drawer-components'
3
+ import { Badge } from '../../ui/Badge'
4
4
  import type { ResourceRef } from '../../../types'
5
5
 
6
6
  interface HTTPRouteRendererProps {
@@ -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="badge bg-theme-elevated text-theme-text-secondary">{h}</span>
80
+ <Badge key={h} tone="structural">{h}</Badge>
81
81
  ))}
82
82
  </div>
83
83
  ) : (
@@ -148,9 +148,9 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
148
148
  {matches.map((match: any, matchIdx: number) => (
149
149
  <div key={matchIdx} className="text-xs text-theme-text-secondary flex flex-wrap items-center gap-1.5">
150
150
  {match.method && (
151
- <span className="px-1.5 py-0.5 bg-blue-500/20 text-blue-400 rounded font-medium">
151
+ <Badge tone="structural" size="sm">
152
152
  {match.method}
153
- </span>
153
+ </Badge>
154
154
  )}
155
155
  {match.path && (
156
156
  <span>
@@ -201,9 +201,9 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
201
201
  <Filter className="w-3 h-3 text-theme-text-tertiary" />
202
202
  {filters.map((filter: any, filterIdx: number) => (
203
203
  <span key={filterIdx} className="inline-flex items-center gap-1">
204
- <span className="px-1.5 py-0.5 bg-amber-500/20 text-amber-400 rounded">
204
+ <Badge tone="accent1" size="sm">
205
205
  {filter.type}
206
- </span>
206
+ </Badge>
207
207
  {filter.type === 'RequestHeaderModifier' && filter.requestHeaderModifier && (
208
208
  <span className="text-theme-text-tertiary">
209
209
  {summarizeHeaderModifier(filter.requestHeaderModifier)}
@@ -263,20 +263,14 @@ export function HTTPRouteRenderer({ data, onNavigate }: HTTPRouteRendererProps)
263
263
  </div>
264
264
  <div className="flex flex-wrap gap-2">
265
265
  {accepted && (
266
- <span className={clsx(
267
- 'badge',
268
- accepted.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
269
- )}>
266
+ <Badge severity={accepted.status === 'True' ? 'success' : 'error'}>
270
267
  {accepted.status === 'True' ? 'Accepted' : 'Not Accepted'}
271
- </span>
268
+ </Badge>
272
269
  )}
273
270
  {resolved && (
274
- <span className={clsx(
275
- 'badge',
276
- resolved.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'
277
- )}>
271
+ <Badge severity={resolved.status === 'True' ? 'success' : 'warning'}>
278
272
  {resolved.status === 'True' ? 'Refs Resolved' : 'Unresolved Refs'}
279
- </span>
273
+ </Badge>
280
274
  )}
281
275
  </div>
282
276
  {accepted?.message && accepted.status === 'False' && (
@@ -1,6 +1,6 @@
1
1
  import { Database, CheckCircle2, Shield } from 'lucide-react'
2
- import { clsx } from 'clsx'
3
2
  import { Section, PropertyList, Property, ConditionsSection, ProblemAlerts } from '../../ui/drawer-components'
3
+ import { Badge } from '../../ui/Badge'
4
4
  import { formatAge } from '../resource-utils'
5
5
  import { formatBytes } from '../../../utils/format'
6
6
  import { GitOpsStatusBadge, SyncCountdown } from '../../gitops'
@@ -58,12 +58,9 @@ export function HelmRepositoryRenderer({ data }: HelmRepositoryRendererProps) {
58
58
  <Property
59
59
  label="Type"
60
60
  value={
61
- <span className={clsx(
62
- 'badge',
63
- isOCI ? 'bg-purple-500/20 text-purple-400' : 'bg-blue-500/20 text-blue-400'
64
- )}>
61
+ <Badge tone={isOCI ? 'accent2' : 'accent1'}>
65
62
  {isOCI ? 'OCI' : 'HTTP'}
66
- </span>
63
+ </Badge>
67
64
  }
68
65
  />
69
66
  {spec.provider && <Property label="Provider" value={spec.provider} />}
@@ -1,18 +1,17 @@
1
1
  import { Shield } from 'lucide-react'
2
- import { clsx } from 'clsx'
3
2
  import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList } from '../../ui/drawer-components'
3
+ import { Badge, type BadgeSeverity } from '../../ui/Badge'
4
4
  import {
5
5
  getAuthorizationPolicyAction,
6
6
  getAuthorizationPolicyRules,
7
7
  getAuthorizationPolicySelector,
8
8
  } from '../resource-utils-istio'
9
- import { BADGE_INACTIVE } from '../../../utils/badge-colors'
10
9
 
11
- const actionColors: Record<string, string> = {
12
- ALLOW: 'bg-green-500/20 text-green-400',
13
- DENY: 'bg-red-500/20 text-red-400',
14
- CUSTOM: 'bg-blue-500/20 text-blue-400',
15
- AUDIT: 'bg-yellow-500/20 text-yellow-400',
10
+ const actionSeverity: Record<string, BadgeSeverity> = {
11
+ ALLOW: 'success',
12
+ DENY: 'error',
13
+ CUSTOM: 'info',
14
+ AUDIT: 'warning',
16
15
  }
17
16
 
18
17
  interface IstioAuthorizationPolicyRendererProps {
@@ -51,12 +50,9 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
51
50
  <Section title="Authorization Policy" icon={Shield} defaultExpanded>
52
51
  <PropertyList>
53
52
  <Property label="Action" value={
54
- <span className={clsx(
55
- 'badge',
56
- actionColors[action] || BADGE_INACTIVE
57
- )}>
53
+ <Badge severity={actionSeverity[action] ?? 'neutral'}>
58
54
  {action}
59
- </span>
55
+ </Badge>
60
56
  } />
61
57
  <Property label="Scope" value={hasSelector ? 'Workload-scoped' : 'Namespace-wide'} />
62
58
  <Property label="Rules" value={String(rules.length)} />
@@ -88,24 +84,24 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
88
84
  {rule.from.map((f: any, fi: number) => (
89
85
  <div key={fi} className="flex flex-wrap gap-1 mb-1">
90
86
  {f.source?.principals?.map((p: string, pi: number) => (
91
- <span key={`p-${pi}`} className="badge-sm bg-blue-500/10 text-blue-400">
87
+ <Badge key={`p-${pi}`} tone="structural" size="sm">
92
88
  principal: {p}
93
- </span>
89
+ </Badge>
94
90
  ))}
95
91
  {f.source?.namespaces?.map((n: string, ni: number) => (
96
- <span key={`n-${ni}`} className="badge-sm bg-purple-500/10 text-purple-400">
92
+ <Badge key={`n-${ni}`} tone="structural" size="sm">
97
93
  namespace: {n}
98
- </span>
94
+ </Badge>
99
95
  ))}
100
96
  {f.source?.ipBlocks?.map((ip: string, ipi: number) => (
101
- <span key={`ip-${ipi}`} className="badge-sm bg-orange-500/10 text-orange-400">
97
+ <Badge key={`ip-${ipi}`} tone="structural" size="sm">
102
98
  IP: {ip}
103
- </span>
99
+ </Badge>
104
100
  ))}
105
101
  {f.source?.requestPrincipals?.map((rp: string, rpi: number) => (
106
- <span key={`rp-${rpi}`} className="badge-sm bg-cyan-500/10 text-cyan-400">
102
+ <Badge key={`rp-${rpi}`} tone="structural" size="sm">
107
103
  reqPrincipal: {rp}
108
- </span>
104
+ </Badge>
109
105
  ))}
110
106
  </div>
111
107
  ))}
@@ -119,24 +115,24 @@ export function IstioAuthorizationPolicyRenderer({ data }: IstioAuthorizationPol
119
115
  {rule.to.map((t: any, ti: number) => (
120
116
  <div key={ti} className="flex flex-wrap gap-1 mb-1">
121
117
  {t.operation?.hosts?.map((h: string, hi: number) => (
122
- <span key={`h-${hi}`} className="badge-sm bg-blue-500/10 text-blue-400">
118
+ <Badge key={`h-${hi}`} tone="structural" size="sm">
123
119
  host: {h}
124
- </span>
120
+ </Badge>
125
121
  ))}
126
122
  {t.operation?.ports?.map((p: string, pi: number) => (
127
- <span key={`p-${pi}`} className="badge-sm bg-orange-500/10 text-orange-400">
123
+ <Badge key={`p-${pi}`} tone="structural" size="sm">
128
124
  port: {p}
129
- </span>
125
+ </Badge>
130
126
  ))}
131
127
  {t.operation?.methods?.map((m: string, mi: number) => (
132
- <span key={`m-${mi}`} className="badge-sm bg-green-500/10 text-green-400">
128
+ <Badge key={`m-${mi}`} tone="structural" size="sm">
133
129
  method: {m}
134
- </span>
130
+ </Badge>
135
131
  ))}
136
132
  {t.operation?.paths?.map((p: string, pi: number) => (
137
- <span key={`path-${pi}`} className="badge-sm bg-purple-500/10 text-purple-400">
133
+ <Badge key={`path-${pi}`} tone="structural" size="sm">
138
134
  path: {p}
139
- </span>
135
+ </Badge>
140
136
  ))}
141
137
  </div>
142
138
  ))}
@@ -1,23 +1,12 @@
1
1
  import { Globe, Lock } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
3
  import { Section, PropertyList, Property, ConditionsSection, AlertBanner, KeyValueBadgeList } from '../../ui/drawer-components'
4
+ import { Badge } from '../../ui/Badge'
4
5
  import {
5
6
  getIstioGatewayStatus,
6
7
  getIstioGatewayServers,
7
8
  getIstioGatewaySelector,
8
9
  } from '../resource-utils-istio'
9
- import { BADGE_INACTIVE } from '../../../utils/badge-colors'
10
-
11
- const protocolColors: Record<string, string> = {
12
- HTTP: 'bg-blue-500/20 text-blue-400',
13
- HTTPS: 'bg-green-500/20 text-green-400',
14
- HTTP2: 'bg-blue-500/20 text-blue-400',
15
- GRPC: 'bg-purple-500/20 text-purple-400',
16
- TCP: 'bg-orange-500/20 text-orange-400',
17
- TLS: 'bg-green-500/20 text-green-400',
18
- MONGO: 'bg-emerald-500/20 text-emerald-400',
19
- MYSQL: 'bg-cyan-500/20 text-cyan-400',
20
- }
21
10
 
22
11
  interface IstioGatewayRendererProps {
23
12
  data: any
@@ -72,12 +61,9 @@ export function IstioGatewayRenderer({ data }: IstioGatewayRendererProps) {
72
61
  <span className="text-sm font-medium text-theme-text-primary">
73
62
  {server.port.name || `Port ${server.port.number}`}
74
63
  </span>
75
- <span className={clsx(
76
- 'px-1.5 py-0.5 rounded text-[10px] font-medium',
77
- protocolColors[protocol] || BADGE_INACTIVE
78
- )}>
64
+ <Badge protocol={protocol} size="sm">
79
65
  {protocol}:{server.port.number}
80
- </span>
66
+ </Badge>
81
67
  </div>
82
68
  </div>
83
69
 
@@ -93,16 +79,23 @@ export function IstioGatewayRenderer({ data }: IstioGatewayRendererProps) {
93
79
  <>
94
80
  <div>
95
81
  <span className="text-theme-text-tertiary">TLS Mode: </span>
96
- <span className={clsx(
97
- 'px-1.5 py-0.5 rounded text-[10px] font-medium',
98
- server.tls.mode === 'SIMPLE' || server.tls.mode === 'MUTUAL'
99
- ? 'bg-green-500/20 text-green-400'
100
- : server.tls.mode === 'PASSTHROUGH'
101
- ? 'bg-blue-500/20 text-blue-400'
102
- : BADGE_INACTIVE
103
- )}>
82
+ <Badge
83
+ // Every TLS server row already shows a teal HTTPS/TLS protocol pill, so
84
+ // a teal mode badge would collide. PASSTHROUGH uses `note` (the mode where
85
+ // the gateway does not terminate TLS — the one worth flagging) to stay clear.
86
+ tone={
87
+ server.tls.mode === 'SIMPLE'
88
+ ? 'accent1'
89
+ : server.tls.mode === 'MUTUAL' || server.tls.mode === 'ISTIO_MUTUAL'
90
+ ? 'accent2'
91
+ : server.tls.mode === 'PASSTHROUGH' || server.tls.mode === 'AUTO_PASSTHROUGH'
92
+ ? 'note'
93
+ : 'structural'
94
+ }
95
+ size="sm"
96
+ >
104
97
  {server.tls.mode || 'SIMPLE'}
105
- </span>
98
+ </Badge>
106
99
  </div>
107
100
  {server.tls.credentialName && (
108
101
  <div>
@@ -1,6 +1,7 @@
1
1
  import { Network, Route } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
3
  import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceLink } from '../../ui/drawer-components'
4
+ import { Badge } from '../../ui/Badge'
4
5
  import {
5
6
  getVirtualServiceStatus,
6
7
  getVirtualServiceHostsList,
@@ -62,7 +63,7 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
62
63
  {gateways.map((gw, i) => {
63
64
  // Gateway reference can be "namespace/name" or just "name" or "mesh"
64
65
  if (gw === 'mesh') {
65
- return <span key={i} className="badge-sm bg-theme-hover text-theme-text-secondary">mesh</span>
66
+ return <Badge key={i} tone="structural" size="sm">mesh</Badge>
66
67
  }
67
68
  const parts = gw.split('/')
68
69
  const gwNs = parts.length === 2 ? parts[0] : ns
@@ -95,19 +96,19 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
95
96
  {route.name || `Route ${i + 1}`}
96
97
  </span>
97
98
  {route.timeout && (
98
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-[10px] text-theme-text-secondary">
99
+ <Badge tone="structural" size="sm">
99
100
  timeout: {route.timeout}
100
- </span>
101
+ </Badge>
101
102
  )}
102
103
  {route.fault && (
103
- <span className="px-1.5 py-0.5 bg-yellow-500/20 text-yellow-400 rounded text-[10px] font-medium">
104
+ <Badge severity="warning" size="sm">
104
105
  fault injection
105
- </span>
106
+ </Badge>
106
107
  )}
107
108
  {route.mirror && (
108
- <span className="px-1.5 py-0.5 bg-purple-500/20 text-purple-400 rounded text-[10px] font-medium">
109
+ <Badge tone="note" size="sm">
109
110
  mirroring
110
- </span>
111
+ </Badge>
111
112
  )}
112
113
  </div>
113
114
 
@@ -119,19 +120,19 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
119
120
  {route.match.map((m: any, mi: number) => (
120
121
  <div key={mi} className="flex flex-wrap gap-1 text-xs">
121
122
  {m.uri && (
122
- <span className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded">
123
+ <Badge tone="structural" size="sm">
123
124
  URI {Object.keys(m.uri)[0]}: {Object.values(m.uri)[0] as string}
124
- </span>
125
+ </Badge>
125
126
  )}
126
127
  {m.method && (
127
- <span className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded">
128
+ <Badge tone="structural" size="sm">
128
129
  Method: {m.method.exact || Object.values(m.method)[0]}
129
- </span>
130
+ </Badge>
130
131
  )}
131
132
  {m.headers && Object.entries(m.headers).map(([hk, hv]: [string, any]) => (
132
- <span key={hk} className="px-1.5 py-0.5 bg-blue-500/10 text-blue-400 rounded">
133
+ <Badge key={hk} tone="structural" size="sm">
133
134
  Header {hk}: {typeof hv === 'object' ? Object.values(hv)[0] as string : String(hv)}
134
- </span>
135
+ </Badge>
135
136
  ))}
136
137
  </div>
137
138
  ))}
@@ -174,9 +175,9 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
174
175
  <span className="text-theme-text-tertiary">:{destPort}</span>
175
176
  )}
176
177
  {destSubset && (
177
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-theme-text-secondary">
178
+ <Badge tone="structural" size="sm">
178
179
  subset: {destSubset}
179
- </span>
180
+ </Badge>
180
181
  )}
181
182
  </div>
182
183
  )
@@ -201,16 +202,16 @@ export function IstioVirtualServiceRenderer({ data, onNavigate }: IstioVirtualSe
201
202
  {route.fault && (
202
203
  <div className="flex flex-wrap gap-2 text-xs">
203
204
  {route.fault.delay && (
204
- <span className="px-1.5 py-0.5 bg-yellow-500/10 text-yellow-400 rounded">
205
+ <Badge severity="warning" size="sm">
205
206
  Delay: {route.fault.delay.fixedDelay}
206
207
  {route.fault.delay.percentage?.value && ` (${route.fault.delay.percentage.value}%)`}
207
- </span>
208
+ </Badge>
208
209
  )}
209
210
  {route.fault.abort && (
210
- <span className="px-1.5 py-0.5 bg-red-500/10 text-red-400 rounded">
211
+ <Badge severity="error" size="sm">
211
212
  Abort: HTTP {route.fault.abort.httpStatus}
212
213
  {route.fault.abort.percentage?.value && ` (${route.fault.abort.percentage.value}%)`}
213
- </span>
214
+ </Badge>
214
215
  )}
215
216
  </div>
216
217
  )}
@@ -35,11 +35,6 @@ function getJobProblems(data: any): string[] {
35
35
  }
36
36
  }
37
37
 
38
- // Check for suspended
39
- if (spec.suspend) {
40
- problems.push('Job is suspended — pods will not be created')
41
- }
42
-
43
38
  return problems
44
39
  }
45
40
 
@@ -62,6 +57,7 @@ export function JobRenderer({ data }: JobRendererProps) {
62
57
 
63
58
  // Check if job completed successfully
64
59
  const isComplete = conditions.some((c: any) => c.type === 'Complete' && c.status === 'True')
60
+ const isSuspended = spec.suspend === true
65
61
 
66
62
  return (
67
63
  <>
@@ -70,6 +66,11 @@ export function JobRenderer({ data }: JobRendererProps) {
70
66
  <AlertBanner variant="error" title="Job Issues" items={problems} />
71
67
  )}
72
68
 
69
+ {/* Suspended is an intentional state, not a fault — keep it informational. */}
70
+ {isSuspended && !hasProblems && (
71
+ <AlertBanner variant="info" title="Job Suspended" message="Pods will not be created until this Job is resumed." />
72
+ )}
73
+
73
74
  {/* Success banner */}
74
75
  {isComplete && !hasProblems && (
75
76
  <AlertBanner variant="success" title="Job Completed Successfully" />
@@ -1,6 +1,7 @@
1
1
  import { Network, ShieldCheck, Server, Globe } from 'lucide-react'
2
2
  import { clsx } from 'clsx'
3
3
  import { Section, PropertyList, Property, ConditionsSection, KnativeNotReadyBanner, ResourceLink } from '../../ui/drawer-components'
4
+ import { Badge } from '../../ui/Badge'
4
5
  import { kindToPlural } from '../../../utils/navigation'
5
6
  import { getKnativeConditionStatus } from '../resource-utils-knative'
6
7
 
@@ -43,14 +44,14 @@ export function KnativeIngressRenderer({ data }: RendererProps) {
43
44
  <div key={i} className="card-inner-lg">
44
45
  <div className="flex flex-wrap gap-1 mb-2">
45
46
  {(rule.hosts || []).map((host: string, hi: number) => (
46
- <span key={hi} className="badge-sm bg-blue-500/10 text-blue-400">
47
+ <Badge key={hi} size="sm" tone="structural">
47
48
  {host}
48
- </span>
49
+ </Badge>
49
50
  ))}
50
51
  {rule.visibility && (
51
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-[10px] text-theme-text-secondary">
52
+ <Badge size="sm" tone="structural">
52
53
  {rule.visibility}
53
- </span>
54
+ </Badge>
54
55
  )}
55
56
  </div>
56
57
  {rule.http?.paths && rule.http.paths.length > 0 && (
@@ -117,9 +118,9 @@ export function KnativeCertificateRenderer({ data }: RendererProps) {
117
118
  <Section title={`DNS Names (${dnsNames.length})`} defaultExpanded>
118
119
  <div className="flex flex-wrap gap-1">
119
120
  {dnsNames.map((name: string, i: number) => (
120
- <span key={i} className="badge-sm bg-theme-elevated text-theme-text-secondary">
121
+ <Badge key={i} size="sm" tone="structural">
121
122
  {name}
122
- </span>
123
+ </Badge>
123
124
  ))}
124
125
  </div>
125
126
  </Section>
@@ -157,12 +158,9 @@ export function ServerlessServiceRenderer({ data, onNavigate }: RendererProps) {
157
158
  </span>
158
159
  } />
159
160
  <Property label="Mode" value={mode ? (
160
- <span className={clsx(
161
- 'badge',
162
- mode === 'Proxy' ? 'bg-yellow-500/20 text-yellow-400' : 'bg-green-500/20 text-green-400'
163
- )}>
161
+ <Badge tone={mode === 'Proxy' ? 'accent1' : 'accent2'}>
164
162
  {mode}
165
- </span>
163
+ </Badge>
166
164
  ) : undefined} />
167
165
  <Property label="Activators" value={numActivators != null ? String(numActivators) : undefined} />
168
166
  <Property label="Protocol" value={protocolType} />
@@ -128,7 +128,7 @@ export function ServiceRenderer({ data, onCopy, copied, endpointSlices, endpoint
128
128
  {hasNoSelector && !isExternalName && (
129
129
  <Section title="EndpointSlices" icon={Radio}>
130
130
  {endpointSlicesLoading ? (
131
- <div className="text-sm text-theme-text-tertiary">Loading EndpointSlices...</div>
131
+ <div className="text-sm text-theme-text-tertiary">Loading EndpointSlices…</div>
132
132
  ) : endpointSlices && endpointSlices.length > 0 ? (
133
133
  <div className="space-y-2">
134
134
  {endpointSlices.map((slice: any) => {
@@ -1,6 +1,6 @@
1
1
  import { Globe, ArrowRight, Network } from 'lucide-react'
2
- import { clsx } from 'clsx'
3
2
  import { Section, PropertyList, Property, ConditionsSection, AlertBanner, ResourceRefBadge } from '../../ui/drawer-components'
3
+ import { Badge } from '../../ui/Badge'
4
4
  import type { ResourceRef } from '../../../types'
5
5
 
6
6
  interface SimpleRouteRendererProps {
@@ -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="badge bg-theme-elevated text-theme-text-secondary">{h}</span>
84
+ <Badge key={h} tone="structural">{h}</Badge>
85
85
  ))}
86
86
  </div>
87
87
  ) : (
@@ -163,20 +163,14 @@ export function SimpleRouteRenderer({ data, kind, onNavigate }: SimpleRouteRende
163
163
  </div>
164
164
  <div className="flex flex-wrap gap-2">
165
165
  {accepted && (
166
- <span className={clsx(
167
- 'badge',
168
- accepted.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
169
- )}>
166
+ <Badge severity={accepted.status === 'True' ? 'success' : 'error'}>
170
167
  {accepted.status === 'True' ? 'Accepted' : 'Not Accepted'}
171
- </span>
168
+ </Badge>
172
169
  )}
173
170
  {resolved && (
174
- <span className={clsx(
175
- 'badge',
176
- resolved.status === 'True' ? 'bg-green-500/20 text-green-400' : 'bg-yellow-500/20 text-yellow-400'
177
- )}>
171
+ <Badge severity={resolved.status === 'True' ? 'success' : 'warning'}>
178
172
  {resolved.status === 'True' ? 'Refs Resolved' : 'Unresolved Refs'}
179
- </span>
173
+ </Badge>
180
174
  )}
181
175
  </div>
182
176
  {accepted?.message && accepted.status === 'False' && (
@@ -1,5 +1,6 @@
1
1
  import { Globe, Route, Layers, Lock } from 'lucide-react'
2
2
  import { Section, PropertyList, Property, AlertBanner, ResourceLink } from '../../ui/drawer-components'
3
+ import { Badge } from '../../ui/Badge'
3
4
 
4
5
  interface TraefikIngressRouteRendererProps {
5
6
  data: any
@@ -84,14 +85,14 @@ export function TraefikIngressRouteRenderer({ data, onNavigate }: TraefikIngress
84
85
  {route.match || 'No match rule'}
85
86
  </span>
86
87
  {route.priority && (
87
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-[10px] text-theme-text-secondary shrink-0">
88
+ <Badge tone="structural" size="sm" className="shrink-0">
88
89
  priority: {route.priority}
89
- </span>
90
+ </Badge>
90
91
  )}
91
92
  {route.kind && route.kind !== 'Rule' && (
92
- <span className="px-1.5 py-0.5 bg-theme-hover rounded text-[10px] text-theme-text-secondary shrink-0">
93
+ <Badge tone="structural" size="sm" className="shrink-0">
93
94
  {route.kind}
94
- </span>
95
+ </Badge>
95
96
  )}
96
97
  </div>
97
98
 
@@ -110,9 +111,9 @@ export function TraefikIngressRouteRenderer({ data, onNavigate }: TraefikIngress
110
111
  return (
111
112
  <div key={si} className="flex items-center gap-2 text-xs">
112
113
  {isTraefikSvc && (
113
- <span className="px-1.5 py-0.5 bg-cyan-500/10 text-cyan-400 rounded text-[10px]">
114
+ <Badge kind="TraefikService" size="sm">
114
115
  TraefikService
115
- </span>
116
+ </Badge>
116
117
  )}
117
118
  <ResourceLink
118
119
  name={svc.name}
@@ -152,9 +153,9 @@ export function TraefikIngressRouteRenderer({ data, onNavigate }: TraefikIngress
152
153
  kind="middlewares"
153
154
  namespace={mwNs}
154
155
  label={
155
- <span className="px-1.5 py-0.5 bg-purple-500/10 text-purple-400 rounded text-[10px] inline-block">
156
+ <Badge tone="accent1" size="sm" className="inline-block">
156
157
  {mw.namespace && mw.namespace !== ns ? `${mw.namespace}/` : ''}{mw.name}
157
- </span>
158
+ </Badge>
158
159
  }
159
160
  onNavigate={onNavigate}
160
161
  />
@@ -242,9 +243,9 @@ export function TraefikIngressRouteRenderer({ data, onNavigate }: TraefikIngress
242
243
  onNavigate={onNavigate}
243
244
  />
244
245
  {isCrossNs && (
245
- <span className="px-1.5 py-0.5 bg-yellow-500/10 text-yellow-400 rounded text-[10px]">
246
+ <Badge tone="note" size="sm">
246
247
  {mw.namespace}
247
- </span>
248
+ </Badge>
248
249
  )}
249
250
  </div>
250
251
  )