feat: native Headlamp integration, TrueNAS API, docs, and CI for v0.2.0
Native Headlamp integrations: - registerResourceTableColumnsProcessor: add Protocol/Pool/Server columns to native StorageClass table and Protocol/Volume Handle to PV table - registerDetailsViewSection: inject TNS-CSI section into PV detail pages - registerDetailsViewSection: inject driver role/status into tns-csi Pod pages - registerDetailsViewHeaderAction: Benchmark shortcut on StorageClass detail - registerAppBarAction: driver health badge (N/Nc M/Mn, color-coded) - Trim sidebar from 6 → 4 entries (Overview, Snapshots, Metrics, Benchmark) TrueNAS API integration: - src/api/truenas.ts: ConfigStore-backed settings, WebSocket JSON-RPC client for pool.query (auth.login_with_api_key + pool.query) - src/components/TnsCsiSettings.tsx: API key + server override settings UI with connection test button - TnsCsiDataContext: fetch real pool stats (size/allocated/free/status) - OverviewPage: three-tier pool capacity display (real data → error → metrics fallback) Documentation: - README, CHANGELOG, CONTRIBUTING, SECURITY - docs/: architecture, deployment (Helm), getting-started, user-guide, troubleshooting CI: - .github/workflows/ci.yaml: lint + type-check + test on PR/push - .github/workflows/release.yaml: workflow_dispatch versioned release Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* PVDetailSection — injected into Headlamp's PersistentVolume detail view.
|
||||
*
|
||||
* Shown only when the PV uses tns.csi.io as the CSI driver.
|
||||
* Uses registerDetailsViewSection in index.tsx.
|
||||
*/
|
||||
|
||||
import {
|
||||
NameValueTable,
|
||||
SectionBox,
|
||||
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import React from 'react';
|
||||
import { formatProtocol, TNS_CSI_PROVISIONER } from '../api/k8s';
|
||||
|
||||
interface PVDetailSectionProps {
|
||||
resource: {
|
||||
kind?: string;
|
||||
metadata?: { name?: string; namespace?: string };
|
||||
spec?: {
|
||||
csi?: {
|
||||
driver?: string;
|
||||
volumeHandle?: string;
|
||||
volumeAttributes?: Record<string, string>;
|
||||
};
|
||||
storageClassName?: string;
|
||||
capacity?: { storage?: string };
|
||||
persistentVolumeReclaimPolicy?: string;
|
||||
};
|
||||
// KubeObject instance — raw JSON lives under jsonData
|
||||
jsonData?: {
|
||||
spec?: {
|
||||
csi?: {
|
||||
driver?: string;
|
||||
volumeHandle?: string;
|
||||
volumeAttributes?: Record<string, string>;
|
||||
};
|
||||
storageClassName?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default function PVDetailSection({ resource }: PVDetailSectionProps) {
|
||||
// Extract from jsonData (KubeObject instance) or fall back to direct properties
|
||||
const spec = resource?.jsonData?.spec ?? resource?.spec;
|
||||
const csi = spec?.csi;
|
||||
|
||||
if (!csi || csi.driver !== TNS_CSI_PROVISIONER) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const attrs = csi.volumeAttributes ?? {};
|
||||
const protocol = formatProtocol(attrs['protocol']);
|
||||
const otherAttrs = Object.entries(attrs).filter(
|
||||
([k]) => !['protocol', 'server', 'pool'].includes(k)
|
||||
);
|
||||
|
||||
return (
|
||||
<SectionBox title="TNS-CSI Storage Details">
|
||||
<NameValueTable
|
||||
rows={[
|
||||
{ name: 'Driver', value: TNS_CSI_PROVISIONER },
|
||||
{ name: 'Protocol', value: protocol },
|
||||
{ name: 'Server', value: attrs['server'] ?? '—' },
|
||||
{ name: 'Pool', value: attrs['pool'] ?? '—' },
|
||||
{ name: 'Volume Handle', value: csi.volumeHandle ?? '—' },
|
||||
{ name: 'Storage Class', value: spec?.storageClassName ?? '—' },
|
||||
...otherAttrs.map(([k, v]) => ({ name: k, value: v ?? '—' })),
|
||||
]}
|
||||
/>
|
||||
</SectionBox>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user