diff --git a/src/components/integrations/StorageClassColumns.tsx b/src/components/integrations/StorageClassColumns.tsx
index d973e76..afce31a 100644
--- a/src/components/integrations/StorageClassColumns.tsx
+++ b/src/components/integrations/StorageClassColumns.tsx
@@ -4,10 +4,14 @@
* Adds Rook-Ceph-specific columns to the native Headlamp StorageClass table
* ('headlamp-storageclasses') and PV table ('headlamp-persistentvolumes').
* Non-Rook-Ceph rows show '—'.
+ *
+ * Column names (Protocol, Pool) are intentionally shared with the tns-csi
+ * column processor so both plugins contribute to the same logical columns
+ * on a mixed-driver cluster.
*/
import React from 'react';
-import { formatStorageType, isRookCephProvisioner } from '../../api/k8s';
+import { isRookCephProvisioner } from '../../api/k8s';
/** Safely read a nested field from either a KubeObject instance or plain object. */
function getField(item: unknown, ...path: string[]): unknown {
@@ -36,23 +40,26 @@ function isRookPvRow(item: unknown): boolean {
return typeof driver === 'string' && isRookCephProvisioner(driver);
}
+function rookProtocol(s: string | undefined): string {
+ if (!s) return '—';
+ if (s.includes('.rbd.')) return 'RBD';
+ if (s.includes('.cephfs.')) return 'CephFS';
+ return '—';
+}
+
export function buildStorageClassColumns() {
return [
{
- label: 'Type',
+ label: 'Protocol',
getValue: (item: unknown) => {
if (!isRookRow(item)) return null;
const provisioner = getField(item, 'provisioner') as string | undefined;
- if (!provisioner) return null;
- const type = provisioner.includes('.rbd.') ? 'rbd' : provisioner.includes('.cephfs.') ? 'cephfs' : 'unknown';
- return formatStorageType(type as 'rbd' | 'cephfs' | 'unknown');
+ return rookProtocol(provisioner);
},
render: (item: unknown) => {
if (!isRookRow(item)) return —;
const provisioner = getField(item, 'provisioner') as string | undefined;
- if (!provisioner) return —;
- const type = provisioner.includes('.rbd.') ? 'rbd' : provisioner.includes('.cephfs.') ? 'cephfs' : 'unknown';
- return {formatStorageType(type as 'rbd' | 'cephfs' | 'unknown')};
+ return {rookProtocol(provisioner)};
},
},
{
@@ -71,7 +78,6 @@ export function buildStorageClassColumns() {
if (!isRookRow(item)) return —;
const clusterID = getField(item, 'parameters', 'clusterID') as string | undefined;
if (!clusterID) return —;
- // Truncate long cluster IDs
return {clusterID.length > 16 ? `${clusterID.slice(0, 16)}…` : clusterID};
},
},
@@ -81,20 +87,16 @@ export function buildStorageClassColumns() {
export function buildPVColumns() {
return [
{
- label: 'Type',
+ label: 'Protocol',
getValue: (item: unknown) => {
if (!isRookPvRow(item)) return null;
const driver = getField(item, 'spec', 'csi', 'driver') as string | undefined;
- if (!driver) return null;
- const type = driver.includes('.rbd.') ? 'rbd' : driver.includes('.cephfs.') ? 'cephfs' : 'unknown';
- return formatStorageType(type as 'rbd' | 'cephfs' | 'unknown');
+ return rookProtocol(driver);
},
render: (item: unknown) => {
if (!isRookPvRow(item)) return —;
const driver = getField(item, 'spec', 'csi', 'driver') as string | undefined;
- if (!driver) return —;
- const type = driver.includes('.rbd.') ? 'rbd' : driver.includes('.cephfs.') ? 'cephfs' : 'unknown';
- return {formatStorageType(type as 'rbd' | 'cephfs' | 'unknown')};
+ return {rookProtocol(driver)};
},
},
{