@skyhook-io/radar-app 1.7.0 → 1.8.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 (47) hide show
  1. package/package.json +9 -3
  2. package/src/App.tsx +150 -44
  3. package/src/api/client.ts +3 -3
  4. package/src/components/ConnectionErrorView.tsx +5 -2
  5. package/src/components/DebugOverlay.tsx +5 -3
  6. package/src/components/UserMenu.tsx +5 -2
  7. package/src/components/applications/ApplicationsView.tsx +1 -1
  8. package/src/components/audit/AuditSettingsDialog.tsx +14 -10
  9. package/src/components/audit/AuditView.tsx +3 -1
  10. package/src/components/compare/CompareViewRoute.tsx +13 -5
  11. package/src/components/compare/useCompareLauncher.tsx +6 -3
  12. package/src/components/cost/CostTrendChart.tsx +3 -3
  13. package/src/components/cost/CostView.tsx +14 -5
  14. package/src/components/helm/ChartBrowser.tsx +7 -5
  15. package/src/components/helm/HelmReleaseDrawer.tsx +25 -13
  16. package/src/components/helm/HelmView.tsx +3 -2
  17. package/src/components/helm/InstallWizard.tsx +4 -3
  18. package/src/components/helm/OwnedResources.tsx +24 -13
  19. package/src/components/helm/RevisionHistory.tsx +2 -1
  20. package/src/components/helm/ValuesViewer.tsx +4 -2
  21. package/src/components/home/ActivitySummary.tsx +4 -1
  22. package/src/components/home/ClusterHealthCard.tsx +21 -18
  23. package/src/components/home/HelmSummary.tsx +3 -1
  24. package/src/components/home/MCPSetupDialog.tsx +10 -4
  25. package/src/components/issues/IssuesPane.tsx +2 -2
  26. package/src/components/nav/PrimaryNavRail.tsx +5 -2
  27. package/src/components/portforward/PortForwardButton.tsx +14 -8
  28. package/src/components/portforward/PortForwardManager.tsx +70 -8
  29. package/src/components/resource/PrometheusChartsGrid.tsx +10 -3
  30. package/src/components/resource/RestartChart.tsx +6 -5
  31. package/src/components/resource/RightsizingStrip.tsx +4 -1
  32. package/src/components/resource-drawer/ResourceDrawer.tsx +3 -1
  33. package/src/components/resources/ImageFilesystemModal.tsx +16 -8
  34. package/src/components/resources/PodFilesystemModal.tsx +4 -2
  35. package/src/components/resources/ResourcesView.tsx +2 -0
  36. package/src/components/settings/MyPermissionsDialog.tsx +64 -4
  37. package/src/components/settings/SettingsDialog.tsx +371 -141
  38. package/src/components/shared/LargeClusterNamespacePicker.tsx +1 -1
  39. package/src/components/traffic/TrafficFilterSidebar.tsx +8 -43
  40. package/src/components/traffic/TrafficFlowList.tsx +13 -4
  41. package/src/components/traffic/TrafficGraph.tsx +37 -23
  42. package/src/components/traffic/TrafficView.tsx +7 -5
  43. package/src/components/ui/DiagnosticsOverlay.tsx +1 -1
  44. package/src/components/ui/Omnibar.tsx +0 -1
  45. package/src/components/workload/WorkloadView.tsx +32 -27
  46. package/src/context/NavCustomization.tsx +19 -5
  47. package/src/main.tsx +1 -1
@@ -23,6 +23,7 @@ import { getSkeletonYaml } from '../../utils/skeleton-yaml'
23
23
  interface ResourceCountsResponse {
24
24
  counts: Record<string, number>
25
25
  forbidden?: string[]
26
+ reasons?: Record<string, string>
26
27
  unavailable?: string[]
27
28
  }
28
29
 
@@ -284,6 +285,7 @@ export function ResourcesView({ namespaces, selectedResource, onResourceClick, o
284
285
  // Lightweight counts for sidebar (replaces 233 parallel queries)
285
286
  resourceCounts={countsData?.counts}
286
287
  resourceForbidden={countsData?.forbidden}
288
+ resourceReasons={countsData?.reasons}
287
289
  resourceUnavailable={countsData?.unavailable}
288
290
  selectedKindQuery={selectedKindQueryResult}
289
291
  largeListGuard={largeListGuard}
@@ -1,17 +1,19 @@
1
1
  import { useState, useEffect, useRef } from 'react'
2
2
  import { createPortal } from 'react-dom'
3
- import { Shield, X, Loader2 } from 'lucide-react'
3
+ import { Shield, X, Loader2, Lock, ExternalLink } from 'lucide-react'
4
4
  import { clsx } from 'clsx'
5
+ import { useQuery } from '@tanstack/react-query'
5
6
  import {
6
7
  rbacVerbBadgeClass,
7
8
  rbacResourceBadgeClass,
8
9
  rbacApiGroupBadgeClass,
9
10
  rbacResourceNameBadgeClass,
10
11
  rbacNonResourceUrlBadgeClass,
12
+ type RBACWhoamiResponse,
11
13
  } from '@skyhook-io/k8s-ui'
12
14
  import { useAnimatedUnmount } from '../../hooks/useAnimatedUnmount'
13
15
  import { TRANSITION_BACKDROP, TRANSITION_PANEL } from '../../utils/animation'
14
- import { useNamespaces, useAuthMe } from '../../api/client'
16
+ import { useNamespaces, useAuthMe, fetchJSON } from '../../api/client'
15
17
  import { useRBACWhoami } from '../../api/rbac'
16
18
 
17
19
  interface MyPermissionsDialogProps {
@@ -71,7 +73,7 @@ export function MyPermissionsDialog({ open, onClose }: MyPermissionsDialogProps)
71
73
  <div className="flex items-center justify-between p-4 border-b border-theme-border shrink-0">
72
74
  <div className="flex items-center gap-2">
73
75
  <Shield className="w-5 h-5 text-theme-text-secondary" />
74
- <h2 className="text-lg font-semibold text-theme-text-primary">My Permissions</h2>
76
+ <h2 className="text-lg font-semibold text-theme-text-primary">Your access on this cluster</h2>
75
77
  </div>
76
78
  <button
77
79
  onClick={onClose}
@@ -134,6 +136,8 @@ export function MyPermissionsDialog({ open, onClose }: MyPermissionsDialogProps)
134
136
  ) : whoami ? (
135
137
  <PermissionsTable whoami={whoami} />
136
138
  ) : null}
139
+
140
+ <RestrictedResources enabled={open} />
137
141
  </div>
138
142
  </div>
139
143
  </div>,
@@ -141,7 +145,7 @@ export function MyPermissionsDialog({ open, onClose }: MyPermissionsDialogProps)
141
145
  )
142
146
  }
143
147
 
144
- function PermissionsTable({ whoami }: { whoami: { resourceRules: any[]; nonResourceRules: any[] } }) {
148
+ function PermissionsTable({ whoami }: { whoami: RBACWhoamiResponse }) {
145
149
  const resourceRules = whoami.resourceRules ?? []
146
150
  const nonResourceRules = whoami.nonResourceRules ?? []
147
151
 
@@ -229,3 +233,59 @@ function ResourceRuleRow({ rule }: { rule: { verbs?: string[]; apiGroups?: strin
229
233
  </div>
230
234
  )
231
235
  }
236
+
237
+ // displayKind strips the API group from a resource-counts key ("group/Kind" →
238
+ // "Kind"; core kinds have no prefix).
239
+ function displayKind(countKey: string): string {
240
+ const i = countKey.indexOf('/')
241
+ return i === -1 ? countKey : countKey.slice(i + 1)
242
+ }
243
+
244
+ // RestrictedResources surfaces the kinds Radar isn't showing the user (the
245
+ // resource-counts `forbidden` set) — the "what's hidden from me" half of access,
246
+ // alongside the SelfSubjectRulesReview rules above. That set mixes RBAC denials
247
+ // with not-installed/not-watched kinds, so the copy says "usually RBAC" rather
248
+ // than asserting a cause, and links to the docs that carry the unblock RBAC.
249
+ function RestrictedResources({ enabled }: { enabled: boolean }) {
250
+ const { data } = useQuery<{ forbidden?: string[] }>({
251
+ queryKey: ['resource-counts', 'your-access'],
252
+ queryFn: () => fetchJSON('/resource-counts'),
253
+ enabled,
254
+ staleTime: 10000,
255
+ })
256
+ const forbidden = data?.forbidden ?? []
257
+ if (forbidden.length === 0) return null
258
+
259
+ return (
260
+ <div>
261
+ <div className="text-xs font-medium text-theme-text-secondary uppercase tracking-wider mb-2 flex items-center gap-1.5">
262
+ <Lock className="w-3.5 h-3.5 text-amber-400" />
263
+ Restricted or unavailable ({forbidden.length})
264
+ </div>
265
+ <p className="text-xs text-theme-text-tertiary mb-2">
266
+ Resource types Radar isn't showing you — usually because your RBAC doesn't allow listing
267
+ them, sometimes because the type isn't installed or watched on this cluster. Either way,
268
+ not an empty cluster.
269
+ </p>
270
+ <div className="flex flex-wrap gap-1.5">
271
+ {forbidden.map((k) => (
272
+ <span
273
+ key={k}
274
+ className="inline-flex items-center px-2 py-0.5 text-xs rounded border border-theme-border bg-theme-elevated text-theme-text-secondary"
275
+ >
276
+ {displayKind(k)}
277
+ </span>
278
+ ))}
279
+ </div>
280
+ <a
281
+ href="https://radarhq.io/docs/cloud/rbac"
282
+ target="_blank"
283
+ rel="noreferrer"
284
+ className="inline-flex items-center gap-1 text-xs text-accent-text hover:underline mt-2"
285
+ >
286
+ How to get access
287
+ <ExternalLink className="w-3 h-3" />
288
+ </a>
289
+ </div>
290
+ )
291
+ }