diff --git a/src/api/RookCephDataContext.tsx b/src/api/RookCephDataContext.tsx index 70d85c8..ffa3169 100644 --- a/src/api/RookCephDataContext.tsx +++ b/src/api/RookCephDataContext.tsx @@ -166,7 +166,9 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // Operator pods try { const opList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_OPERATOR_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_OPERATOR_SELECTOR + )}` ); if (!cancelled && isKubeList(opList)) setOperatorPods(opList.items as RookCephPod[]); } catch { @@ -176,7 +178,9 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // MON pods try { const monList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_MON_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_MON_SELECTOR + )}` ); if (!cancelled && isKubeList(monList)) setMonPods(monList.items as RookCephPod[]); } catch { @@ -186,7 +190,9 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // OSD pods try { const osdList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_OSD_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_OSD_SELECTOR + )}` ); if (!cancelled && isKubeList(osdList)) setOsdPods(osdList.items as RookCephPod[]); } catch { @@ -196,7 +202,9 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // MGR pods try { const mgrList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_MGR_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_MGR_SELECTOR + )}` ); if (!cancelled && isKubeList(mgrList)) setMgrPods(mgrList.items as RookCephPod[]); } catch { @@ -206,9 +214,12 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // CSI RBD provisioner pods try { const csiRbdList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_CSI_RBD_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_CSI_RBD_SELECTOR + )}` ); - if (!cancelled && isKubeList(csiRbdList)) setCsiRbdPods(csiRbdList.items as RookCephPod[]); + if (!cancelled && isKubeList(csiRbdList)) + setCsiRbdPods(csiRbdList.items as RookCephPod[]); } catch { if (!cancelled) setCsiRbdPods([]); } @@ -216,9 +227,12 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } // CSI CephFS provisioner pods try { const csiCephfsList = await ApiProxy.request( - `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent(ROOK_CSI_CEPHFS_SELECTOR)}` + `/api/v1/namespaces/${ROOK_CEPH_NAMESPACE}/pods?labelSelector=${encodeURIComponent( + ROOK_CSI_CEPHFS_SELECTOR + )}` ); - if (!cancelled && isKubeList(csiCephfsList)) setCsiCephfsPods(csiCephfsList.items as RookCephPod[]); + if (!cancelled && isKubeList(csiCephfsList)) + setCsiCephfsPods(csiCephfsList.items as RookCephPod[]); } catch { if (!cancelled) setCsiCephfsPods([]); } @@ -232,7 +246,9 @@ export function RookCephDataProvider({ children }: { children: React.ReactNode } } void fetchAsync(); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [refreshKey]); // --------------------------------------------------------------------------- diff --git a/src/api/k8s.ts b/src/api/k8s.ts index d30d505..912439c 100644 --- a/src/api/k8s.ts +++ b/src/api/k8s.ts @@ -129,9 +129,12 @@ export interface CephCluster extends KubeObject { export function healthToStatus(health: string | undefined): 'success' | 'warning' | 'error' { switch (health) { - case 'HEALTH_OK': return 'success'; - case 'HEALTH_WARN': return 'warning'; - default: return 'error'; + case 'HEALTH_OK': + return 'success'; + case 'HEALTH_WARN': + return 'warning'; + default: + return 'error'; } } @@ -331,9 +334,7 @@ export function findBoundPv( ): RookCephPersistentVolume | undefined { const ns = pvc.metadata.namespace ?? ''; const name = pvc.metadata.name; - return rookPvs.find( - pv => pv.spec.claimRef?.namespace === ns && pv.spec.claimRef?.name === name - ); + return rookPvs.find(pv => pv.spec.claimRef?.namespace === ns && pv.spec.claimRef?.name === name); } // --------------------------------------------------------------------------- @@ -368,15 +369,11 @@ export interface RookCephPod extends KubeObject { } export function isPodReady(pod: RookCephPod): boolean { - return ( - pod.status?.conditions?.some(c => c.type === 'Ready' && c.status === 'True') ?? false - ); + return pod.status?.conditions?.some(c => c.type === 'Ready' && c.status === 'True') ?? false; } export function getPodRestarts(pod: RookCephPod): number { - return ( - pod.status?.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) ?? 0 - ); + return pod.status?.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) ?? 0; } export function getPodImage(pod: RookCephPod): string { @@ -441,11 +438,16 @@ export function parseStorageToBytes(storage: string): number { const suffix = match[2] ?? ''; const multipliers: Record = { '': 1, - K: 1e3, Ki: 1024, - M: 1e6, Mi: 1024 ** 2, - G: 1e9, Gi: 1024 ** 3, - T: 1e12, Ti: 1024 ** 4, - P: 1e15, Pi: 1024 ** 5, + K: 1e3, + Ki: 1024, + M: 1e6, + Mi: 1024 ** 2, + G: 1e9, + Gi: 1024 ** 3, + T: 1e12, + Ti: 1024 ** 4, + P: 1e15, + Pi: 1024 ** 5, }; return value * (multipliers[suffix] ?? 1); } @@ -453,9 +455,12 @@ export function parseStorageToBytes(storage: string): number { /** Returns display label for storage type (rbd → Block, cephfs → Filesystem). */ export function formatStorageType(type: 'rbd' | 'cephfs' | 'unknown'): string { switch (type) { - case 'rbd': return 'Block (RBD)'; - case 'cephfs': return 'Filesystem (CephFS)'; - default: return 'Unknown'; + case 'rbd': + return 'Block (RBD)'; + case 'cephfs': + return 'Filesystem (CephFS)'; + default: + return 'Unknown'; } } diff --git a/src/components/AppBarClusterBadge.tsx b/src/components/AppBarClusterBadge.tsx index cb0611a..a2e38a2 100644 --- a/src/components/AppBarClusterBadge.tsx +++ b/src/components/AppBarClusterBadge.tsx @@ -14,10 +14,14 @@ import { useRookCephContext } from '../api/RookCephDataContext'; function getHealthColor(health: string | undefined): string { switch (health) { - case 'HEALTH_OK': return '#4caf50'; - case 'HEALTH_WARN': return '#ff9800'; - case 'HEALTH_ERR': return '#f44336'; - default: return '#9e9e9e'; + case 'HEALTH_OK': + return '#4caf50'; + case 'HEALTH_WARN': + return '#ff9800'; + case 'HEALTH_ERR': + return '#f44336'; + default: + return '#9e9e9e'; } } diff --git a/src/components/BlockPoolsPage.tsx b/src/components/BlockPoolsPage.tsx index 2b9934b..4be866a 100644 --- a/src/components/BlockPoolsPage.tsx +++ b/src/components/BlockPoolsPage.tsx @@ -19,7 +19,10 @@ function BlockPoolDetail({ pool, onClose }: { pool: CephBlockPool; onClose: () =
-
+
{pool.metadata.name} @@ -132,10 +154,22 @@ export default function BlockPoolsPage() { ), }, - { label: 'Replicas', getter: (p: CephBlockPool) => String(p.spec?.replicated?.size ?? '—') }, - { label: 'Failure Domain', getter: (p: CephBlockPool) => p.spec?.failureDomain ?? '—' }, - { label: 'Mirroring', getter: (p: CephBlockPool) => p.spec?.mirroring?.enabled ? 'Enabled' : 'Disabled' }, - { label: 'Age', getter: (p: CephBlockPool) => formatAge(p.metadata.creationTimestamp) }, + { + label: 'Replicas', + getter: (p: CephBlockPool) => String(p.spec?.replicated?.size ?? '—'), + }, + { + label: 'Failure Domain', + getter: (p: CephBlockPool) => p.spec?.failureDomain ?? '—', + }, + { + label: 'Mirroring', + getter: (p: CephBlockPool) => (p.spec?.mirroring?.enabled ? 'Enabled' : 'Disabled'), + }, + { + label: 'Age', + getter: (p: CephBlockPool) => formatAge(p.metadata.creationTimestamp), + }, ]} data={blockPools} /> @@ -145,7 +179,12 @@ export default function BlockPoolsPage() { {selected && ( <>
setSelected(null)} /> setSelected(null)} /> diff --git a/src/components/CephPodDetailSection.tsx b/src/components/CephPodDetailSection.tsx index b2e2b21..62d5eb3 100644 --- a/src/components/CephPodDetailSection.tsx +++ b/src/components/CephPodDetailSection.tsx @@ -80,16 +80,17 @@ export default function CephPodDetailSection({ resource }: CephPodDetailSectionP const role = ROLE_LABELS[appLabel] ?? appLabel; const phase = raw.status?.phase ?? 'Unknown'; const isReady = - raw.status?.conditions?.some((c) => c.type === 'Ready' && c.status === 'True') ?? false; - const restarts = - raw.status?.containerStatuses?.reduce((s, c) => s + c.restartCount, 0) ?? 0; + raw.status?.conditions?.some(c => c.type === 'Ready' && c.status === 'True') ?? false; + const restarts = raw.status?.containerStatuses?.reduce((s, c) => s + c.restartCount, 0) ?? 0; - const containerRows = (raw.status?.containerStatuses ?? []).map((cs) => { + const containerRows = (raw.status?.containerStatuses ?? []).map(cs => { let stateStr = 'Unknown'; if (cs.state?.running) stateStr = 'Running'; else if (cs.state?.waiting) stateStr = `Waiting: ${cs.state.waiting.reason ?? ''}`; else if (cs.state?.terminated) - stateStr = `Terminated: ${cs.state.terminated.reason ?? ''} (exit ${cs.state.terminated.exitCode ?? ''})`; + stateStr = `Terminated: ${cs.state.terminated.reason ?? ''} (exit ${ + cs.state.terminated.exitCode ?? '' + })`; return { name: cs.name, @@ -111,11 +112,7 @@ export default function CephPodDetailSection({ resource }: CephPodDetailSectionP }, { name: 'Phase', - value: ( - - {phase} - - ), + value: {phase}, }, { name: 'Node', value: raw.spec?.nodeName ?? '—' }, { name: 'Restarts', value: String(restarts) }, diff --git a/src/components/ClusterStatusCard.tsx b/src/components/ClusterStatusCard.tsx index 179d965..d452f30 100644 --- a/src/components/ClusterStatusCard.tsx +++ b/src/components/ClusterStatusCard.tsx @@ -11,7 +11,15 @@ import { } from '@kinvolk/headlamp-plugin/lib/CommonComponents'; import React from 'react'; import type { CephCluster, RookCephPod } from '../api/k8s'; -import { formatAge, formatBytes, getPodImage, getPodRestarts, healthToStatus, isPodReady, phaseToStatus } from '../api/k8s'; +import { + formatAge, + formatBytes, + getPodImage, + getPodRestarts, + healthToStatus, + isPodReady, + phaseToStatus, +} from '../api/k8s'; interface ClusterStatusCardProps { cephClusters: CephCluster[]; @@ -26,17 +34,14 @@ interface ClusterStatusCardProps { function PodStatusBadge({ pod }: { pod: RookCephPod }) { const ready = isPodReady(pod); const phase = pod.status?.phase ?? 'Unknown'; - return ( - - {phase} - - ); + return {phase}; } function PodSummaryRow({ pods, label }: { pods: RookCephPod[]; label: string }) { const ready = pods.filter(isPodReady).length; const total = pods.length; - const status = total === 0 ? 'error' : ready === total ? 'success' : ready > 0 ? 'warning' : 'error'; + const status = + total === 0 ? 'error' : ready === total ? 'success' : ready > 0 ? 'warning' : 'error'; return { name: label, value: ( @@ -84,12 +89,12 @@ export default function ClusterStatusCard({ { name: 'Phase', value: ( - - {phase ?? 'Unknown'} - + {phase ?? 'Unknown'} ), }, - ...(cluster.status?.message ? [{ name: 'Message', value: cluster.status.message }] : []), + ...(cluster.status?.message + ? [{ name: 'Message', value: cluster.status.message }] + : []), { name: 'Ceph Version', value: version }, { name: 'Namespace', value: cluster.metadata.namespace ?? '—' }, { name: 'Age', value: formatAge(cluster.metadata.creationTimestamp) }, @@ -102,7 +107,11 @@ export default function ClusterStatusCard({
80 ? '#f44336' : '#1976d2' }, + { + name: 'Used', + value: bytesUsed, + fill: usedPct > 80 ? '#f44336' : '#1976d2', + }, { name: 'Free', value: bytesAvail, fill: '#e0e0e0' }, ]} total={bytesTotal} @@ -142,7 +151,9 @@ export function PodDetailRows({ pods, label }: { pods: RookCephPod[]; label: str return ( No pods found }]} + rows={[ + { name: 'Status', value: No pods found }, + ]} /> ); diff --git a/src/components/FilesystemsPage.tsx b/src/components/FilesystemsPage.tsx index 0690fb0..2b191ac 100644 --- a/src/components/FilesystemsPage.tsx +++ b/src/components/FilesystemsPage.tsx @@ -19,7 +19,10 @@ function FilesystemDetail({ fs, onClose }: { fs: CephFilesystem; onClose: () =>
padding: '24px', }} > -
+
{fs.metadata.name} @@ -140,10 +168,22 @@ export default function FilesystemsPage() { ), }, - { label: 'Active MDS', getter: (f: CephFilesystem) => String(f.spec?.metadataServer?.activeCount ?? '—') }, - { label: 'Active Standby', getter: (f: CephFilesystem) => String(f.spec?.metadataServer?.activeStandby ?? '—') }, - { label: 'Data Pools', getter: (f: CephFilesystem) => String(f.spec?.dataPools?.length ?? 0) }, - { label: 'Age', getter: (f: CephFilesystem) => formatAge(f.metadata.creationTimestamp) }, + { + label: 'Active MDS', + getter: (f: CephFilesystem) => String(f.spec?.metadataServer?.activeCount ?? '—'), + }, + { + label: 'Active Standby', + getter: (f: CephFilesystem) => String(f.spec?.metadataServer?.activeStandby ?? '—'), + }, + { + label: 'Data Pools', + getter: (f: CephFilesystem) => String(f.spec?.dataPools?.length ?? 0), + }, + { + label: 'Age', + getter: (f: CephFilesystem) => formatAge(f.metadata.creationTimestamp), + }, ]} data={filesystems} /> @@ -153,7 +193,12 @@ export default function FilesystemsPage() { {selected && ( <>
setSelected(null)} /> setSelected(null)} /> diff --git a/src/components/ObjectStoresPage.tsx b/src/components/ObjectStoresPage.tsx index 6f76dc6..4e9b74f 100644 --- a/src/components/ObjectStoresPage.tsx +++ b/src/components/ObjectStoresPage.tsx @@ -23,7 +23,10 @@ function ObjectStoreDetail({ store, onClose }: { store: CephObjectStore; onClose
-
+
{store.metadata.name} @@ -137,9 +162,18 @@ export default function ObjectStoresPage() { ), }, - { label: 'Gateway Port', getter: (o: CephObjectStore) => String(o.spec?.gateway?.port ?? '—') }, - { label: 'Instances', getter: (o: CephObjectStore) => String(o.spec?.gateway?.instances ?? '—') }, - { label: 'Age', getter: (o: CephObjectStore) => formatAge(o.metadata.creationTimestamp) }, + { + label: 'Gateway Port', + getter: (o: CephObjectStore) => String(o.spec?.gateway?.port ?? '—'), + }, + { + label: 'Instances', + getter: (o: CephObjectStore) => String(o.spec?.gateway?.instances ?? '—'), + }, + { + label: 'Age', + getter: (o: CephObjectStore) => formatAge(o.metadata.creationTimestamp), + }, ]} data={objectStores} /> @@ -149,7 +183,12 @@ export default function ObjectStoresPage() { {selected && ( <>
setSelected(null)} /> setSelected(null)} /> diff --git a/src/components/OverviewPage.tsx b/src/components/OverviewPage.tsx index 5397ea6..3a94f72 100644 --- a/src/components/OverviewPage.tsx +++ b/src/components/OverviewPage.tsx @@ -15,7 +15,13 @@ import { StatusLabel, } from '@kinvolk/headlamp-plugin/lib/CommonComponents'; import React from 'react'; -import { formatAge, formatBytes, healthToStatus, phaseToStatus, storageClassType } from '../api/k8s'; +import { + formatAge, + formatBytes, + healthToStatus, + phaseToStatus, + storageClassType, +} from '../api/k8s'; import { useRookCephContext } from '../api/RookCephDataContext'; import ClusterStatusCard from './ClusterStatusCard'; @@ -70,7 +76,14 @@ export default function OverviewPage() { return ( <> -
+
@@ -115,11 +152,24 @@ export default function StorageClassesPage() { ), }, { label: 'Provisioner', getter: (sc: RookCephStorageClass) => sc.provisioner }, - { label: 'Pool', getter: (sc: RookCephStorageClass) => sc.parameters?.['pool'] ?? '—' }, + { + label: 'Pool', + getter: (sc: RookCephStorageClass) => sc.parameters?.['pool'] ?? '—', + }, { label: 'Reclaim', getter: (sc: RookCephStorageClass) => sc.reclaimPolicy ?? '—' }, - { label: 'Expansion', getter: (sc: RookCephStorageClass) => sc.allowVolumeExpansion ? 'Yes' : 'No' }, - { label: 'PVs', getter: (sc: RookCephStorageClass) => String(pvCountByClass.get(sc.metadata.name) ?? 0) }, - { label: 'Age', getter: (sc: RookCephStorageClass) => formatAge(sc.metadata.creationTimestamp) }, + { + label: 'Expansion', + getter: (sc: RookCephStorageClass) => (sc.allowVolumeExpansion ? 'Yes' : 'No'), + }, + { + label: 'PVs', + getter: (sc: RookCephStorageClass) => + String(pvCountByClass.get(sc.metadata.name) ?? 0), + }, + { + label: 'Age', + getter: (sc: RookCephStorageClass) => formatAge(sc.metadata.creationTimestamp), + }, ]} data={storageClasses} /> @@ -129,7 +179,12 @@ export default function StorageClassesPage() { {selected && ( <>
setSelected(null)} /> -
+
{pv.metadata.name} ), }, - { label: 'Capacity', getter: (pv: RookCephPersistentVolume) => pv.spec.capacity?.storage ?? '—' }, - { label: 'Access Modes', getter: (pv: RookCephPersistentVolume) => formatAccessModes(pv.spec.accessModes) }, + { + label: 'Capacity', + getter: (pv: RookCephPersistentVolume) => pv.spec.capacity?.storage ?? '—', + }, + { + label: 'Access Modes', + getter: (pv: RookCephPersistentVolume) => formatAccessModes(pv.spec.accessModes), + }, { label: 'Phase', getter: (pv: RookCephPersistentVolume) => ( @@ -124,10 +150,25 @@ export default function VolumesPage() { ), }, - { label: 'Reclaim', getter: (pv: RookCephPersistentVolume) => pv.spec.persistentVolumeReclaimPolicy ?? '—' }, - { label: 'Pool', getter: (pv: RookCephPersistentVolume) => pv.spec.csi?.volumeAttributes?.['pool'] ?? '—' }, - { label: 'Claim', getter: (pv: RookCephPersistentVolume) => pv.spec.claimRef ? `${pv.spec.claimRef.namespace}/${pv.spec.claimRef.name}` : '—' }, - { label: 'Age', getter: (pv: RookCephPersistentVolume) => formatAge(pv.metadata.creationTimestamp) }, + { + label: 'Reclaim', + getter: (pv: RookCephPersistentVolume) => + pv.spec.persistentVolumeReclaimPolicy ?? '—', + }, + { + label: 'Pool', + getter: (pv: RookCephPersistentVolume) => + pv.spec.csi?.volumeAttributes?.['pool'] ?? '—', + }, + { + label: 'Claim', + getter: (pv: RookCephPersistentVolume) => + pv.spec.claimRef ? `${pv.spec.claimRef.namespace}/${pv.spec.claimRef.name}` : '—', + }, + { + label: 'Age', + getter: (pv: RookCephPersistentVolume) => formatAge(pv.metadata.creationTimestamp), + }, ]} data={persistentVolumes} /> @@ -137,7 +178,12 @@ export default function VolumesPage() { {selected && ( <>
setSelected(null)} /> setSelected(null)} /> diff --git a/src/components/integrations/StorageClassColumns.tsx b/src/components/integrations/StorageClassColumns.tsx index afce31a..8126981 100644 --- a/src/components/integrations/StorageClassColumns.tsx +++ b/src/components/integrations/StorageClassColumns.tsx @@ -64,7 +64,7 @@ export function buildStorageClassColumns() { }, { label: 'Pool', - getValue: (item: unknown) => getField(item, 'parameters', 'pool') as string | null ?? null, + getValue: (item: unknown) => (getField(item, 'parameters', 'pool') as string | null) ?? null, render: (item: unknown) => { if (!isRookRow(item)) return ; const pool = getField(item, 'parameters', 'pool') as string | undefined; @@ -73,12 +73,17 @@ export function buildStorageClassColumns() { }, { label: 'Cluster', - getValue: (item: unknown) => getField(item, 'parameters', 'clusterID') as string | null ?? null, + getValue: (item: unknown) => + (getField(item, 'parameters', 'clusterID') as string | null) ?? null, render: (item: unknown) => { if (!isRookRow(item)) return ; const clusterID = getField(item, 'parameters', 'clusterID') as string | undefined; if (!clusterID) return ; - return {clusterID.length > 16 ? `${clusterID.slice(0, 16)}…` : clusterID}; + return ( + + {clusterID.length > 16 ? `${clusterID.slice(0, 16)}…` : clusterID} + + ); }, }, ]; @@ -101,10 +106,13 @@ export function buildPVColumns() { }, { label: 'Pool', - getValue: (item: unknown) => getField(item, 'spec', 'csi', 'volumeAttributes', 'pool') as string | null ?? null, + getValue: (item: unknown) => + (getField(item, 'spec', 'csi', 'volumeAttributes', 'pool') as string | null) ?? null, render: (item: unknown) => { if (!isRookPvRow(item)) return ; - const pool = getField(item, 'spec', 'csi', 'volumeAttributes', 'pool') as string | undefined; + const pool = getField(item, 'spec', 'csi', 'volumeAttributes', 'pool') as + | string + | undefined; return {pool ?? '—'}; }, }, diff --git a/src/index.tsx b/src/index.tsx index a5c3967..b12477a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -16,7 +16,10 @@ import { RookCephDataProvider } from './api/RookCephDataContext'; import BlockPoolsPage from './components/BlockPoolsPage'; import CephPodDetailSection from './components/CephPodDetailSection'; import FilesystemsPage from './components/FilesystemsPage'; -import { buildPVColumns, buildStorageClassColumns } from './components/integrations/StorageClassColumns'; +import { + buildPVColumns, + buildStorageClassColumns, +} from './components/integrations/StorageClassColumns'; import ObjectStoresPage from './components/ObjectStoresPage'; import OverviewPage from './components/OverviewPage'; import PodsPage from './components/PodsPage'; @@ -207,11 +210,18 @@ registerDetailsViewSection(({ resource }) => { // takes priority and falls back to the existing one (for mixed-driver tables). function mergeColumns( existing: T[], - incoming: Array<{ label: string; getValue: (r: unknown) => unknown; render: (r: unknown) => React.ReactNode }> + incoming: Array<{ + label: string; + getValue: (r: unknown) => unknown; + render: (r: unknown) => React.ReactNode; + }> ): T[] { - type ObjCol = { label: string; getValue: (r: unknown) => unknown; render: (r: unknown) => React.ReactNode }; - const isObjCol = (c: unknown): c is ObjCol => - typeof c === 'object' && c !== null && 'label' in c; + type ObjCol = { + label: string; + getValue: (r: unknown) => unknown; + render: (r: unknown) => React.ReactNode; + }; + const isObjCol = (c: unknown): c is ObjCol => typeof c === 'object' && c !== null && 'label' in c; const result = [...existing]; const toAppend: typeof incoming = []; for (const col of incoming) { @@ -221,7 +231,7 @@ function mergeColumns( result[idx] = { label: col.label, getValue: (r: unknown) => col.getValue(r) ?? prev.getValue(r), - render: (r: unknown) => col.getValue(r) !== null ? col.render(r) : prev.render(r), + render: (r: unknown) => (col.getValue(r) !== null ? col.render(r) : prev.render(r)), } as unknown as T; } else { toAppend.push(col); @@ -239,4 +249,3 @@ registerResourceTableColumnsProcessor(({ id, columns }) => { } return columns; }); -