@skyhook-io/k8s-ui 1.5.8 → 1.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyhook-io/k8s-ui",
3
- "version": "1.5.8",
3
+ "version": "1.5.10",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/skyhook-io/radar",
@@ -58,7 +58,7 @@
58
58
  "dependencies": {
59
59
  "@monaco-editor/react": "^4.7.0",
60
60
  "html-to-image": "^1.11.0",
61
- "react-virtuoso": "^4.18.5",
61
+ "react-virtuoso": "^4.18.6",
62
62
  "shiki": "^4.0.0"
63
63
  },
64
64
  "peerDependencies": {
@@ -85,7 +85,7 @@
85
85
  "clsx": "^2.1.1",
86
86
  "diff": "^9.0.0",
87
87
  "elkjs": "^0.11.1",
88
- "lucide-react": "^1.8.0",
88
+ "lucide-react": "^1.12.0",
89
89
  "react": "^19.2.4",
90
90
  "react-dom": "^19.2.4",
91
91
  "typescript": "^6.0.2",
@@ -190,7 +190,7 @@ function FlowRow({
190
190
  const isIngress = direction === 'ingress'
191
191
 
192
192
  const sourceNodes = (
193
- <div className="flex-1 min-w-0 space-y-1">
193
+ <div className="min-w-0 max-w-full shrink space-y-1">
194
194
  {sources.map((peer, i) => (
195
195
  <div key={i}>
196
196
  {i > 0 && (
@@ -199,13 +199,13 @@ function FlowRow({
199
199
  <Tooltip content={peer.sublabel ? `${peer.label}\n${peer.sublabel}` : peer.label} position="top">
200
200
  <div
201
201
  className={clsx(
202
- 'rounded-md border px-2 py-1.5',
202
+ 'rounded-md border px-2 py-1.5 min-w-0 overflow-hidden',
203
203
  PEER_STYLES[peer.type],
204
204
  )}
205
205
  >
206
- <div className="flex items-center gap-1.5">
206
+ <div className="flex items-center gap-1.5 min-w-0">
207
207
  <span className={clsx('w-1.5 h-1.5 rounded-full shrink-0', PEER_DOT[peer.type])} />
208
- <span className={clsx('text-[11px] font-medium truncate', denied && 'line-through text-red-400')}>
208
+ <span className={clsx('text-[11px] font-medium truncate min-w-0', denied && 'line-through text-red-400')}>
209
209
  {peer.label}
210
210
  </span>
211
211
  </div>
@@ -220,14 +220,16 @@ function FlowRow({
220
220
  )
221
221
 
222
222
  const targetNode = (
223
- <Tooltip content={target} position="top">
224
- <div className="rounded-md border border-indigo-500/30 bg-indigo-500/8 px-2 py-1.5 flex-1 min-w-0">
225
- <div className="flex items-center gap-1.5">
226
- <span className="w-1.5 h-1.5 rounded-full shrink-0 bg-indigo-500" />
227
- <span className="text-[11px] font-medium truncate">{target}</span>
223
+ <div className="min-w-0 max-w-full shrink-[1000]">
224
+ <Tooltip content={target} position="top">
225
+ <div className="rounded-md border border-indigo-500/30 bg-indigo-500/8 px-2 py-1.5 min-w-0 max-w-full overflow-hidden">
226
+ <div className="flex items-center gap-1.5 min-w-0">
227
+ <span className="w-1.5 h-1.5 rounded-full shrink-0 bg-indigo-500" />
228
+ <span className="text-[11px] font-medium truncate min-w-0">{target}</span>
229
+ </div>
228
230
  </div>
229
- </div>
230
- </Tooltip>
231
+ </Tooltip>
232
+ </div>
231
233
  )
232
234
 
233
235
  const arrow = (
@@ -374,72 +374,59 @@ export const K8sResourceNode = memo(function K8sResourceNode({
374
374
  'pl-3 pr-3',
375
375
  isSmallNode ? 'py-2' : 'py-2.5'
376
376
  )}>
377
- {/* Header row: icon + kind label + expand/collapse + status dot */}
377
+ {/* Header row: icon + kind label + (right-aligned) policy badge + expand/collapse + status dot */}
378
378
  <div className="flex items-center gap-1.5 mb-0.5">
379
379
  <span className={iconClass} />
380
380
  <span className="text-[10px] uppercase tracking-wide text-theme-text-tertiary font-medium">
381
381
  {isPodGroup ? 'Pod Group' : displayKind(kind)}
382
382
  </span>
383
- {/* Expand/Collapse button for PodGroup */}
384
- {canExpand && (
385
- <button
386
- onClick={(e) => {
387
- e.stopPropagation()
388
- onExpand(id)
389
- }}
390
- className="ml-auto p-0.5 hover:bg-theme-elevated rounded transition-colors"
391
- title="Expand to show individual pods"
392
- >
393
- <ChevronDown className="w-3.5 h-3.5 text-theme-text-secondary" />
394
- </button>
395
- )}
396
- {canCollapse && (
397
- <button
398
- onClick={(e) => {
399
- e.stopPropagation()
400
- onCollapse(id)
401
- }}
402
- className="ml-auto p-0.5 hover:bg-theme-elevated rounded transition-colors"
403
- title="Collapse back to group"
404
- >
405
- <ChevronUp className="w-3.5 h-3.5 text-theme-text-secondary" />
406
- </button>
407
- )}
408
- {issueTooltip ? (
409
- <Tooltip content={issueTooltip} position="right">
410
- <span
411
- className={clsx(
412
- canExpand || canCollapse ? '' : 'ml-auto',
413
- 'w-1.5 h-1.5 rounded-full cursor-help',
414
- getStatusDotColor(status)
415
- )}
416
- />
417
- </Tooltip>
418
- ) : (
419
- <span
420
- className={clsx(
421
- canExpand || canCollapse ? '' : 'ml-auto',
422
- 'w-1.5 h-1.5 rounded-full',
423
- getStatusDotColor(status)
424
- )}
425
- />
426
- )}
383
+ <div className="ml-auto flex items-center gap-1.5">
384
+ {policyStatus && (
385
+ <Tooltip content={policyStatus === 'protected' ? 'Protected by NetworkPolicy' : 'No NetworkPolicy coverage'} position="right">
386
+ <span className={clsx(
387
+ 'inline-flex items-center justify-center w-3 h-3 rounded-sm text-[8px] font-bold cursor-help leading-none',
388
+ policyStatus === 'protected'
389
+ ? 'bg-green-500/20 text-green-500 border border-green-500/30'
390
+ : 'bg-yellow-500/20 text-yellow-500 border border-yellow-500/30',
391
+ )}>
392
+ {policyStatus === 'protected' ? '✓' : '!'}
393
+ </span>
394
+ </Tooltip>
395
+ )}
396
+ {canExpand && (
397
+ <button
398
+ onClick={(e) => {
399
+ e.stopPropagation()
400
+ onExpand(id)
401
+ }}
402
+ className="p-0.5 hover:bg-theme-elevated rounded transition-colors"
403
+ title="Expand to show individual pods"
404
+ >
405
+ <ChevronDown className="w-3.5 h-3.5 text-theme-text-secondary" />
406
+ </button>
407
+ )}
408
+ {canCollapse && (
409
+ <button
410
+ onClick={(e) => {
411
+ e.stopPropagation()
412
+ onCollapse(id)
413
+ }}
414
+ className="p-0.5 hover:bg-theme-elevated rounded transition-colors"
415
+ title="Collapse back to group"
416
+ >
417
+ <ChevronUp className="w-3.5 h-3.5 text-theme-text-secondary" />
418
+ </button>
419
+ )}
420
+ {issueTooltip ? (
421
+ <Tooltip content={issueTooltip} position="right">
422
+ <span className={clsx('w-1.5 h-1.5 rounded-full cursor-help', getStatusDotColor(status))} />
423
+ </Tooltip>
424
+ ) : (
425
+ <span className={clsx('w-1.5 h-1.5 rounded-full', getStatusDotColor(status))} />
426
+ )}
427
+ </div>
427
428
  </div>
428
429
 
429
- {/* Network Policy coverage indicator */}
430
- {policyStatus && (
431
- <Tooltip content={policyStatus === 'protected' ? 'Protected by NetworkPolicy' : 'No NetworkPolicy coverage'} position="right">
432
- <span className={clsx(
433
- 'inline-flex items-center justify-center w-3.5 h-3.5 rounded-sm text-[8px] font-bold cursor-help',
434
- policyStatus === 'protected'
435
- ? 'bg-green-500/20 text-green-500 border border-green-500/30'
436
- : 'bg-yellow-500/20 text-yellow-500 border border-yellow-500/30',
437
- )}>
438
- {policyStatus === 'protected' ? '✓' : '!'}
439
- </span>
440
- </Tooltip>
441
- )}
442
-
443
430
  {/* Name */}
444
431
  <div className="text-sm font-medium text-theme-text-primary truncate pr-1">
445
432
  {name}
@@ -654,12 +654,12 @@ export function TopologyGraph({
654
654
  }, [selectedNodeId, setNodes])
655
655
 
656
656
  if (!topology) {
657
- return <PaneLoader label="Loading topology…" className="flex-1" />
657
+ return <PaneLoader label="Loading topology…" className="absolute inset-0" />
658
658
  }
659
659
 
660
660
  if (topology.nodes.length === 0) {
661
661
  return (
662
- <div className="flex-1 flex items-center justify-center text-theme-text-secondary">
662
+ <div className="absolute inset-0 flex items-center justify-center text-theme-text-secondary">
663
663
  <div className="text-center">
664
664
  <p className="text-lg">No resources found</p>
665
665
  <p className="text-sm mt-2">
@@ -673,7 +673,7 @@ export function TopologyGraph({
673
673
  // Show layout error if we have topology data but layout failed
674
674
  if (layoutError && nodes.length === 0) {
675
675
  return (
676
- <div className="flex-1 flex items-center justify-center text-theme-text-secondary">
676
+ <div className="absolute inset-0 flex items-center justify-center text-theme-text-secondary">
677
677
  <div className="text-center max-w-md">
678
678
  <p className="text-lg text-amber-400">Layout Error</p>
679
679
  <p className="text-sm mt-2">
package/src/types/core.ts CHANGED
@@ -33,11 +33,27 @@ export interface Capabilities {
33
33
  helmWrite: boolean // Helm write operations (install, upgrade, rollback, uninstall, apply values)
34
34
  nodeWrite: boolean // Node write operations (cordon, uncordon, drain)
35
35
  mcpEnabled: boolean // MCP server is running
36
+ // How / where this Radar binary is running. Optional on the wire so a
37
+ // newer frontend (e.g. radar-hub-web bundling a fresher @skyhook-io/radar-app)
38
+ // doesn't crash against an older backend that hasn't shipped the field yet —
39
+ // consumers should default to { mode: 'local' } when absent.
40
+ deployment?: Deployment
36
41
  resources?: ResourcePermissions // Per-resource-type permissions
37
42
  authEnabled?: boolean // Auth is enabled on the backend
38
43
  username?: string // Authenticated user's username (when auth enabled)
39
44
  }
40
45
 
46
+ // DeploymentMode is the closed set of topologies Radar can run in.
47
+ // `local` is a developer's machine with a kubeconfig (most OSS use).
48
+ // `in-cluster` is a Radar pod inside the cluster, no kubeconfig.
49
+ // `cloud` is in-cluster + tunneled to Radar Cloud's hub — UI suppresses
50
+ // chrome the hub already renders (cluster headline, local-MCP card).
51
+ export type DeploymentMode = 'local' | 'in-cluster' | 'cloud'
52
+
53
+ export interface Deployment {
54
+ mode: DeploymentMode
55
+ }
56
+
41
57
  // Core node kinds that have specific UI handling
42
58
  //
43
59
  // When adding a new kind here, also update: