@skyhook-io/radar-app 0.2.2 → 0.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 (177) hide show
  1. package/README.md +7 -1
  2. package/package.json +33 -25
  3. package/src/App.tsx +1449 -382
  4. package/src/RadarApp.tsx +132 -19
  5. package/src/api/apiResources.ts +1 -1
  6. package/src/api/client.argoResourceSync.test.ts +69 -0
  7. package/src/api/client.delta.test.ts +89 -0
  8. package/src/api/client.deltaSync.test.ts +216 -0
  9. package/src/api/client.metrics.test.ts +106 -0
  10. package/src/api/client.rightsizing.test.ts +32 -0
  11. package/src/api/client.ts +2730 -271
  12. package/src/api/client.yaml.test.ts +45 -0
  13. package/src/api/diagnose.ts +289 -0
  14. package/src/api/quotas.ts +16 -0
  15. package/src/api/rbac.ts +57 -0
  16. package/src/api/timelineSource.test.ts +217 -0
  17. package/src/api/timelineSource.ts +582 -0
  18. package/src/components/ConnectionErrorView.tsx +186 -70
  19. package/src/components/ContextSwitcher.tsx +63 -18
  20. package/src/components/DebugOverlay.tsx +5 -3
  21. package/src/components/NamespaceSwitcher.tsx +41 -0
  22. package/src/components/UserMenu.tsx +69 -21
  23. package/src/components/applications/ApplicationsView.tsx +936 -0
  24. package/src/components/audit/AuditSettingsDialog.tsx +79 -17
  25. package/src/components/audit/AuditView.tsx +65 -62
  26. package/src/components/compare/CompareViewRoute.tsx +124 -0
  27. package/src/components/compare/useCompareCandidates.ts +27 -0
  28. package/src/components/compare/useCompareLauncher.tsx +79 -0
  29. package/src/components/cost/ApplicationCostTab.test.ts +204 -0
  30. package/src/components/cost/ApplicationCostTab.tsx +571 -0
  31. package/src/components/cost/CostTrendChart.tsx +106 -75
  32. package/src/components/cost/CostView.test.ts +12 -0
  33. package/src/components/cost/CostView.tsx +507 -223
  34. package/src/components/cost/CostViewTabs.test.tsx +21 -0
  35. package/src/components/cost/CostViewTabs.tsx +40 -0
  36. package/src/components/cost/CurrentAllocationUse.test.ts +21 -0
  37. package/src/components/cost/CurrentAllocationUse.tsx +126 -0
  38. package/src/components/cost/WorkloadCostTab.test.ts +153 -0
  39. package/src/components/cost/WorkloadCostTab.tsx +372 -0
  40. package/src/components/cost/cloud-console.test.ts +39 -0
  41. package/src/components/cost/cloud-console.ts +81 -0
  42. package/src/components/cost/errors.ts +8 -0
  43. package/src/components/cost/format.test.ts +27 -0
  44. package/src/components/cost/format.ts +46 -0
  45. package/src/components/cost/kinds.ts +5 -0
  46. package/src/components/curl/ServiceCurlButton.tsx +445 -0
  47. package/src/components/diagnose/AISettings.tsx +147 -0
  48. package/src/components/diagnose/DiagnoseContext.tsx +495 -0
  49. package/src/components/diagnose/DiagnoseSurface.tsx +394 -0
  50. package/src/components/diagnose/Home.tsx +163 -0
  51. package/src/components/diagnose/InvestigationView.tsx +622 -0
  52. package/src/components/diagnose/LocalDiagnoseAction.tsx +162 -0
  53. package/src/components/diagnose/launch.ts +65 -0
  54. package/src/components/diagnose/parts.tsx +1756 -0
  55. package/src/components/dock/BottomDock.tsx +2 -3
  56. package/src/components/dock/DockContext.tsx +1 -0
  57. package/src/components/dock/TerminalTab.tsx +1 -1
  58. package/src/components/dock/WorkloadLogsTab.tsx +21 -5
  59. package/src/components/dock/index.ts +1 -1
  60. package/src/components/execution/BatchExecutionView.test.ts +170 -0
  61. package/src/components/execution/BatchExecutionView.tsx +1329 -0
  62. package/src/components/execution/batch-run-actions.test.ts +48 -0
  63. package/src/components/execution/batch-run-actions.ts +24 -0
  64. package/src/components/execution/batch-timeline.test.ts +57 -0
  65. package/src/components/execution/batch-timeline.ts +46 -0
  66. package/src/components/execution/execution-definition.test.ts +208 -0
  67. package/src/components/execution/execution-definition.ts +245 -0
  68. package/src/components/gitops/ArgoResourceDiffLoader.tsx +23 -0
  69. package/src/components/gitops/GitOpsView.tsx +1042 -0
  70. package/src/components/gitops/RevisionMetaChip.tsx +63 -0
  71. package/src/components/helm/ChartBrowser.tsx +87 -31
  72. package/src/components/helm/HelmCompareRoute.tsx +1341 -0
  73. package/src/components/helm/HelmReleaseDrawer.test.ts +17 -0
  74. package/src/components/helm/HelmReleaseDrawer.tsx +1073 -102
  75. package/src/components/helm/HelmView.tsx +237 -96
  76. package/src/components/helm/InstallWizard.tsx +94 -38
  77. package/src/components/helm/ManifestDiffViewer.tsx +8 -27
  78. package/src/components/helm/OwnedResources.tsx +34 -59
  79. package/src/components/helm/RevisionHistory.tsx +52 -3
  80. package/src/components/helm/RoleGatedPanel.tsx +3 -3
  81. package/src/components/helm/TrackChartSourceDialog.tsx +185 -0
  82. package/src/components/helm/ValuesDiffPreview.tsx +17 -7
  83. package/src/components/helm/ValuesViewer.tsx +49 -53
  84. package/src/components/helm/helm-utils.ts +4 -0
  85. package/src/components/home/ActivitySummary.tsx +4 -1
  86. package/src/components/home/ClusterHealthCard.tsx +56 -42
  87. package/src/components/home/CostCard.tsx +21 -36
  88. package/src/components/home/GitOpsControllersCard.tsx +110 -0
  89. package/src/components/home/HelmSummary.tsx +3 -1
  90. package/src/components/home/HomeView.tsx +339 -105
  91. package/src/components/home/MCPSetupDialog.tsx +29 -87
  92. package/src/components/home/TrafficSummary.tsx +2 -2
  93. package/src/components/home/mcpToolCatalog.ts +333 -0
  94. package/src/components/issues/IssuesPane.tsx +151 -0
  95. package/src/components/logs/LogsViewer.tsx +4 -1
  96. package/src/components/logs/ScheduledWorkloadLogsViewer.tsx +135 -0
  97. package/src/components/logs/WorkloadLogsViewer.tsx +4 -1
  98. package/src/components/nav/PrimaryNavRail.tsx +285 -0
  99. package/src/components/portforward/PortForwardButton.tsx +118 -47
  100. package/src/components/portforward/PortForwardManager.tsx +253 -131
  101. package/src/components/resource/HPACharts.tsx +237 -0
  102. package/src/components/resource/PVCUsageBar.tsx +59 -0
  103. package/src/components/resource/PrometheusCharts.tsx +160 -584
  104. package/src/components/resource/PrometheusChartsGrid.tsx +270 -0
  105. package/src/components/resource/RestartChart.tsx +133 -0
  106. package/src/components/resource/RightsizingStrip.test.ts +109 -0
  107. package/src/components/resource/RightsizingStrip.tsx +363 -0
  108. package/src/components/resource-drawer/ResourceDrawer.tsx +3 -1
  109. package/src/components/resources/CompositeRenderer.tsx +101 -0
  110. package/src/components/resources/ImageFilesystemModal.tsx +19 -12
  111. package/src/components/resources/PodFilesystemModal.tsx +6 -5
  112. package/src/components/resources/ResourceDetailDrawer.tsx +13 -3
  113. package/src/components/resources/ResourcesView.tsx +194 -17
  114. package/src/components/resources/renderers/CronWorkflowRenderer.tsx +1 -0
  115. package/src/components/resources/renderers/HPARenderer.tsx +20 -1
  116. package/src/components/resources/renderers/NamespaceRenderer.tsx +31 -0
  117. package/src/components/resources/renderers/NodeRenderer.tsx +10 -4
  118. package/src/components/resources/renderers/PVCRenderer.tsx +19 -1
  119. package/src/components/resources/renderers/PodRenderer.tsx +30 -6
  120. package/src/components/resources/renderers/RoleBindingRenderer.tsx +45 -1
  121. package/src/components/resources/renderers/RoleRenderer.tsx +27 -1
  122. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +28 -1
  123. package/src/components/resources/renderers/ServiceRenderer.tsx +81 -8
  124. package/src/components/resources/renderers/WorkloadRenderer.tsx +51 -4
  125. package/src/components/resources/renderers/index.ts +2 -0
  126. package/src/components/resources/resource-utils.ts +2 -1
  127. package/src/components/rightsizing/RightsizingScanView.tsx +938 -0
  128. package/src/components/rightsizing/copy.test.ts +56 -0
  129. package/src/components/rightsizing/model.test.ts +227 -0
  130. package/src/components/rightsizing/model.ts +158 -0
  131. package/src/components/rightsizing/presentation.test.ts +104 -0
  132. package/src/components/rightsizing/presentation.ts +94 -0
  133. package/src/components/settings/MyPermissionsDialog.tsx +241 -0
  134. package/src/components/settings/SettingsDialog.tsx +1505 -165
  135. package/src/components/shared/CreateResourceDialog.tsx +9 -2
  136. package/src/components/shared/LargeClusterNamespacePicker.tsx +3 -3
  137. package/src/components/timeline/LocalTimelineScrubber.tsx +212 -0
  138. package/src/components/timeline/RetainedTimelineScrubber.tsx +311 -0
  139. package/src/components/timeline/TimelineList.tsx +86 -13
  140. package/src/components/timeline/TimelineSwimlanes.tsx +9 -1299
  141. package/src/components/timeline/TimelineView.tsx +873 -24
  142. package/src/components/timeline/TimelineView.urlparams.test.ts +335 -0
  143. package/src/components/traffic/TrafficFilterSidebar.tsx +10 -45
  144. package/src/components/traffic/TrafficFlowList.tsx +29 -15
  145. package/src/components/traffic/TrafficGraph.tsx +42 -24
  146. package/src/components/traffic/TrafficView.tsx +32 -19
  147. package/src/components/ui/CommandPalette.tsx +8 -215
  148. package/src/components/ui/DiagnosticsOverlay.tsx +219 -9
  149. package/src/components/ui/Markdown.tsx +3 -3
  150. package/src/components/ui/Omnibar.tsx +602 -0
  151. package/src/components/ui/RadarOmnibar.tsx +52 -0
  152. package/src/components/ui/SearchSyntaxHelp.tsx +89 -0
  153. package/src/components/ui/ShortcutHelpOverlay.tsx +3 -2
  154. package/src/components/ui/UpdateNotification.tsx +48 -36
  155. package/src/components/ui/command-items.ts +178 -0
  156. package/src/components/workload/WorkloadView.tsx +1342 -158
  157. package/src/context/ConnectionContext.tsx +146 -21
  158. package/src/context/DiagnoseCustomization.tsx +93 -0
  159. package/src/context/NavCustomization.tsx +75 -0
  160. package/src/context/TimelineSource.tsx +50 -0
  161. package/src/contexts/CapabilitiesContext.tsx +32 -8
  162. package/src/filter/FilterLocationBridge.tsx +30 -0
  163. package/src/hooks/useClusterLoadState.ts +73 -0
  164. package/src/hooks/useDocumentTitle.ts +25 -0
  165. package/src/hooks/useEventSource.ts +6 -0
  166. package/src/hooks/useKeyboardShortcuts.tsx +1 -0
  167. package/src/hooks/useMediaQuery.ts +21 -0
  168. package/src/hooks/useNavRailPinned.ts +46 -0
  169. package/src/hooks/useRecentResources.ts +49 -0
  170. package/src/index.css +162 -1
  171. package/src/index.ts +73 -1
  172. package/src/main.tsx +7 -5
  173. package/src/types/clusterLoadState.ts +33 -0
  174. package/src/types.ts +2 -0
  175. package/src/utils/auditBadges.ts +53 -0
  176. package/src/utils/navigation.ts +64 -1
  177. package/src/components/ui/NamespaceSelector.tsx +0 -436
@@ -1 +1,28 @@
1
- export * from '@skyhook-io/k8s-ui/components/resources/renderers/ServiceAccountRenderer'
1
+ import { ServiceAccountRenderer as BaseServiceAccountRenderer } from '@skyhook-io/k8s-ui/components/resources/renderers/ServiceAccountRenderer'
2
+ import type { ResourceRef } from '@skyhook-io/k8s-ui'
3
+ import { useRBACSubject } from '../../../api/rbac'
4
+
5
+ interface ServiceAccountRendererProps {
6
+ data: any
7
+ onNavigate?: (ref: ResourceRef) => void
8
+ }
9
+
10
+ export function ServiceAccountRenderer({ data, onNavigate }: ServiceAccountRendererProps) {
11
+ const namespace = data?.metadata?.namespace ?? ''
12
+ const name = data?.metadata?.name ?? ''
13
+ const { data: rbacData, isLoading, error } = useRBACSubject(
14
+ 'ServiceAccount',
15
+ namespace,
16
+ name,
17
+ !!name,
18
+ )
19
+ return (
20
+ <BaseServiceAccountRenderer
21
+ data={data}
22
+ rbacData={rbacData ?? null}
23
+ rbacLoading={isLoading}
24
+ rbacError={error as Error | null}
25
+ onNavigate={onNavigate}
26
+ />
27
+ )
28
+ }
@@ -1,26 +1,99 @@
1
+ import { useMemo, useState, useCallback } from 'react'
1
2
  import { ServiceRenderer as BaseServiceRenderer } from '@skyhook-io/k8s-ui/components/resources/renderers/ServiceRenderer'
2
3
  import { PortForwardInlineButton } from '../../portforward/PortForwardButton'
4
+ import { CurlButton, CurlPanel, isHttpishPort, defaultScheme, defaultPathForPort } from '../../curl/ServiceCurlButton'
5
+ import { useResources } from '../../../api/client'
6
+ import { useNamespacedCapabilities, useIsLocalDeployment } from '../../../contexts/CapabilitiesContext'
7
+ import type { ResourceRef } from '../../../types'
3
8
 
4
9
  interface ServiceRendererProps {
5
10
  data: any
6
11
  onCopy: (text: string, label: string) => void
7
12
  copied: string | null
13
+ onNavigate?: (ref: ResourceRef) => void
8
14
  }
9
15
 
10
- export function ServiceRenderer({ data, onCopy, copied }: ServiceRendererProps) {
16
+ export function ServiceRenderer({ data, onCopy, copied, onNavigate }: ServiceRendererProps) {
17
+ const namespace = data.metadata?.namespace
18
+ const serviceName = data.metadata?.name
19
+ const { canPortForward } = useNamespacedCapabilities(namespace)
20
+ const isLocal = useIsLocalDeployment()
21
+ // Offer the port-forward affordance when a live forward is possible (local +
22
+ // RBAC) OR when we're not local — in-cluster/Cloud can't bind a local listener,
23
+ // but we still surface a copy-paste `kubectl port-forward` command.
24
+ const showPortForward = canPortForward || !isLocal
25
+ // Curl dials the Service directly from in-cluster, so it's only available when
26
+ // Radar runs in-cluster/Cloud — locally you'd port-forward instead.
27
+ const showCurl = !isLocal
28
+ // Which port's inline curl panel is open (one at a time). `closing` keeps the
29
+ // panel mounted through its collapse animation before we drop it.
30
+ const [curl, setCurl] = useState<{ port: number; closing: boolean } | null>(null)
31
+ const closeCurl = useCallback(() => {
32
+ setCurl((p) => (p ? { ...p, closing: true } : null))
33
+ // Only drop the panel if it's still the one closing. Opening another port
34
+ // (which sets closing:false) before this fires must not clear the new panel.
35
+ window.setTimeout(() => setCurl((p) => (p?.closing ? null : p)), 220)
36
+ }, [])
37
+ const spec = data.spec || {}
38
+ const shouldLoadEndpointSlices = Boolean(
39
+ namespace &&
40
+ serviceName &&
41
+ spec.type !== 'ExternalName' &&
42
+ (!spec.selector || Object.keys(spec.selector).length === 0)
43
+ )
44
+ const { data: endpointSlices, isLoading: endpointSlicesLoading } = useResources<any>(
45
+ 'endpointslices',
46
+ namespace,
47
+ 'discovery.k8s.io',
48
+ { enabled: shouldLoadEndpointSlices, refetchInterval: 30000 }
49
+ )
50
+ const matchingEndpointSlices = useMemo(
51
+ () => (endpointSlices || []).filter((slice: any) => slice.metadata?.labels?.['kubernetes.io/service-name'] === serviceName),
52
+ [endpointSlices, serviceName]
53
+ )
54
+
11
55
  return (
12
56
  <BaseServiceRenderer
13
57
  data={data}
14
58
  onCopy={onCopy}
15
59
  copied={copied}
16
- renderPortAction={({ namespace, serviceName, port, protocol }) => (
17
- <PortForwardInlineButton
18
- namespace={namespace}
19
- serviceName={serviceName}
20
- port={port}
21
- protocol={protocol}
22
- />
60
+ endpointSlices={matchingEndpointSlices}
61
+ endpointSlicesLoading={endpointSlicesLoading}
62
+ onNavigate={onNavigate}
63
+ renderPortAction={({ port, name, appProtocol, protocol }) => (
64
+ <>
65
+ {showCurl && isHttpishPort(port, name, appProtocol, protocol) && (
66
+ <CurlButton
67
+ active={curl?.port === port && !curl.closing}
68
+ onClick={() => {
69
+ if (curl?.port === port && !curl.closing) closeCurl()
70
+ else setCurl({ port, closing: false })
71
+ }}
72
+ />
73
+ )}
74
+ {showPortForward && (
75
+ <PortForwardInlineButton
76
+ namespace={namespace}
77
+ serviceName={serviceName}
78
+ port={port}
79
+ protocol={protocol}
80
+ />
81
+ )}
82
+ </>
23
83
  )}
84
+ renderPortPanel={({ port, name, appProtocol }) =>
85
+ curl?.port === port ? (
86
+ <CurlPanel
87
+ namespace={namespace}
88
+ serviceName={serviceName}
89
+ port={port}
90
+ initialScheme={defaultScheme(port, name, appProtocol)}
91
+ initialPath={defaultPathForPort(port, name, appProtocol)}
92
+ open={!curl.closing}
93
+ onClose={closeCurl}
94
+ />
95
+ ) : null
96
+ }
24
97
  />
25
98
  )
26
99
  }
@@ -1,7 +1,11 @@
1
1
  import { WorkloadRenderer as BaseWorkloadRenderer } from '@skyhook-io/k8s-ui/components/resources/renderers/WorkloadRenderer'
2
2
  import { useNavigate } from 'react-router-dom'
3
- import { useScaleWorkload } from '../../../api/client'
4
- import { useQueryClient } from '@tanstack/react-query'
3
+ import { useScaleWorkload, fetchJSON } from '../../../api/client'
4
+ import { useRBACSubject } from '../../../api/rbac'
5
+ import { useQueries, useQueryClient } from '@tanstack/react-query'
6
+ import { kindToPlural } from '@skyhook-io/k8s-ui/utils/navigation'
7
+ import type { Relationships, ResourceRef, ResourceWithRelationships } from '../../../types'
8
+ import type { ScalerDiagnosis } from '@skyhook-io/k8s-ui/components/resources/renderers/WorkloadRenderer'
5
9
 
6
10
  // Map plural lowercase kind to singular PascalCase for ownerReferences matching
7
11
  function getOwnerKind(kind: string): string {
@@ -18,10 +22,12 @@ function getOwnerKind(kind: string): string {
18
22
  interface WorkloadRendererProps {
19
23
  kind: string
20
24
  data: any
21
- onNavigate?: (ref: { kind: string; namespace: string; name: string }) => void
25
+ onNavigate?: (ref: ResourceRef) => void
26
+ relationships?: Relationships
27
+ scaleBlockedBy?: ResourceRef[]
22
28
  }
23
29
 
24
- export function WorkloadRenderer({ kind, data, onNavigate }: WorkloadRendererProps) {
30
+ export function WorkloadRenderer({ kind, data, onNavigate, scaleBlockedBy }: WorkloadRendererProps) {
25
31
  const navigate = useNavigate()
26
32
  const queryClient = useQueryClient()
27
33
  const scaleMutation = useScaleWorkload()
@@ -29,12 +35,53 @@ export function WorkloadRenderer({ kind, data, onNavigate }: WorkloadRendererPro
29
35
  const metadata = data.metadata || {}
30
36
  const viewPodsUrl = `/resources/pods?ownerKind=${encodeURIComponent(getOwnerKind(kind))}&ownerName=${encodeURIComponent(metadata.name || '')}&namespace=${encodeURIComponent(metadata.namespace || '')}`
31
37
 
38
+ // SA reverse-lookup for the workload's pod template. "default" when unset
39
+ // (matches PodRenderer's semantics — the SA every Pod uses by default).
40
+ const saName = data?.spec?.template?.spec?.serviceAccountName || 'default'
41
+ const namespace = metadata.namespace ?? ''
42
+ const { data: rbacData, isLoading: rbacLoading, error: rbacError } = useRBACSubject(
43
+ 'ServiceAccount', namespace, saName, !!namespace,
44
+ )
45
+ const hpaRefs = (scaleBlockedBy ?? []).filter(ref => {
46
+ const refKind = ref.kind.toLowerCase()
47
+ return refKind === 'horizontalpodautoscaler' || refKind === 'hpa'
48
+ })
49
+ const hpaQueries = useQueries({
50
+ queries: hpaRefs.map(ref => ({
51
+ queryKey: ['resource', kindToPlural(ref.kind), ref.namespace, ref.name, ref.group],
52
+ queryFn: () => {
53
+ const ns = ref.namespace || '_'
54
+ const params = new URLSearchParams()
55
+ if (ref.group) params.set('group', ref.group)
56
+ const query = params.toString()
57
+ return fetchJSON<ResourceWithRelationships<any>>(`/resources/${kindToPlural(ref.kind)}/${ns}/${ref.name}${query ? `?${query}` : ''}`)
58
+ },
59
+ enabled: Boolean(ref.kind && ref.name),
60
+ staleTime: 10000,
61
+ retry: false,
62
+ })),
63
+ })
64
+ const scalerDiagnostics: ScalerDiagnosis[] = hpaRefs.map((ref, index) => {
65
+ const query = hpaQueries[index]
66
+ return {
67
+ ref,
68
+ diagnosis: query.data?.hpaDiagnosis,
69
+ loading: query.isLoading,
70
+ error: query.isError ? (query.error instanceof Error ? query.error.message : 'Failed to fetch HPA') : undefined,
71
+ }
72
+ })
73
+
32
74
  return (
33
75
  <BaseWorkloadRenderer
34
76
  kind={kind}
35
77
  data={data}
36
78
  onNavigate={onNavigate}
37
79
  onViewPods={() => navigate(viewPodsUrl)}
80
+ rbacData={rbacData ?? null}
81
+ rbacLoading={rbacLoading}
82
+ rbacError={rbacError as Error | null}
83
+ scaleBlockedBy={scaleBlockedBy}
84
+ scalerDiagnostics={scalerDiagnostics}
38
85
  onScale={async (replicas) => {
39
86
  await scaleMutation.mutateAsync({
40
87
  kind,
@@ -7,6 +7,7 @@ export { ConfigMapRenderer } from './ConfigMapRenderer'
7
7
  export { SecretRenderer } from './SecretRenderer'
8
8
  export { JobRenderer } from './JobRenderer'
9
9
  export { CronJobRenderer } from './CronJobRenderer'
10
+ export { CronWorkflowRenderer } from './CronWorkflowRenderer'
10
11
  export { HPARenderer } from './HPARenderer'
11
12
  export { NodeRenderer } from './NodeRenderer'
12
13
  export { PVCRenderer } from './PVCRenderer'
@@ -28,6 +29,7 @@ export { WorkflowTemplateRenderer } from './WorkflowTemplateRenderer'
28
29
  export { NetworkPolicyRenderer } from './NetworkPolicyRenderer'
29
30
  export { PodDisruptionBudgetRenderer } from './PodDisruptionBudgetRenderer'
30
31
  export { ServiceAccountRenderer } from './ServiceAccountRenderer'
32
+ export { NamespaceRenderer } from './NamespaceRenderer'
31
33
  export { RoleRenderer } from './RoleRenderer'
32
34
  export { RoleBindingRenderer } from './RoleBindingRenderer'
33
35
  export { EventRenderer } from './EventRenderer'
@@ -1,5 +1,6 @@
1
1
  // Re-export all resource utilities from the shared @skyhook-io/k8s-ui package.
2
2
  export * from '@skyhook-io/k8s-ui/components/resources/resource-utils'
3
3
 
4
- // Backward compatibility: re-export formatBytes (previously re-exported here)
4
+ // formatBytes lives in utils/format but is re-exported here so consumers
5
+ // can import it from the same module as the rest of the resource utilities.
5
6
  export { formatBytes } from '@skyhook-io/k8s-ui/utils/format'