Files
Chris Farhood e5d1fcb11c Implement headlamp-tns-csi-plugin
Full plugin implementation with 6 pages, K8s resource filtering,
Prometheus metrics parsing, kbench benchmark runner, and 67 unit tests.

## Pages
- Overview: driver health, storage summary, protocol distribution chart, non-Bound PVC alerts
- Storage Classes: tns-csi SC table with slide-in detail panel + protocol notes
- Volumes: PV table with full CSI attribute detail panel
- Snapshots: VolumeSnapshot CRDs with graceful degradation if not installed
- Metrics: Prometheus text format parser + WebSocket/Volume/CSI operation cards
- Benchmark: kbench Job+PVC lifecycle, FIO log parser, past benchmarks list

## API modules
- k8s.ts: typed resource shapes, filtering helpers, formatting utilities
- metrics.ts: Prometheus text format parser, tns-csi metric extraction
- kbench.ts: Job/PVC manifests, lifecycle management, FIO summary parser
- TnsCsiDataContext.tsx: shared React context with memoized filtered resources

## Quality
- TypeScript strict mode, zero any, discriminated union for benchmark state
- 67 tests passing (vitest + @testing-library/react)
- registerDetailsViewSection injects TNS-CSI details on PVC pages
- Graceful degradation for missing CSIDriver and VolumeSnapshot CRDs

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>
2026-02-18 07:45:19 -05:00

44 lines
1.1 KiB
TypeScript

import '@testing-library/jest-dom';
// Node 22+ ships a minimal built-in `localStorage` global (property-bag only,
// no getItem/setItem/removeItem/clear) that shadows jsdom's Web Storage
// implementation. Provide a spec-compliant shim so code under test works.
if (typeof localStorage !== 'undefined' && typeof localStorage.getItem !== 'function') {
const store = new Map<string, string>();
const storage = {
getItem(key: string): string | null {
return store.get(key) ?? null;
},
setItem(key: string, value: string): void {
store.set(key, String(value));
},
removeItem(key: string): void {
store.delete(key);
},
clear(): void {
store.clear();
},
get length(): number {
return store.size;
},
key(index: number): string | null {
return [...store.keys()][index] ?? null;
},
};
Object.defineProperty(globalThis, 'localStorage', {
value: storage,
writable: true,
configurable: true,
});
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'localStorage', {
value: storage,
writable: true,
configurable: true,
});
}
}