Files
headlamp-intel-gpu-plugin/src/components/PodDetailSection.tsx
T
DevContainer User 488bf90abc fix: resolve eslint errors and apply formatting to match shared config
Auto-fix import ordering, quote style, and indentation via eslint --fix
and prettier --write. Remove unused variable in NodesPage and PodsPage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:50:29 +00:00

115 lines
3.2 KiB
TypeScript

/**
* PodDetailSection — injected into Headlamp's native Pod detail page.
*
* Shows Intel GPU resource requests and limits per container, plus
* a link to the node's GPU summary.
* Returns null for pods that don't request Intel GPU resources.
*/
import {
NameValueTable,
SectionBox,
StatusLabel,
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
import React from 'react';
import { formatGpuResourceName, INTEL_GPU_RESOURCE_PREFIX, isGpuRequestingPod } from '../api/k8s';
interface PodDetailSectionProps {
resource: {
kind?: string;
metadata?: { name?: string; namespace?: string };
jsonData?: unknown;
};
}
export default function PodDetailSection({ resource }: PodDetailSectionProps) {
// Extract raw Kubernetes JSON
const rawPod =
resource.jsonData && typeof resource.jsonData === 'object' ? resource.jsonData : resource;
// Only render for pods that request Intel GPU resources
if (!isGpuRequestingPod(rawPod)) return null;
const pod = rawPod as {
metadata: { name: string; namespace?: string };
spec?: {
nodeName?: string;
containers?: Array<{
name: string;
resources?: {
requests?: Record<string, string>;
limits?: Record<string, string>;
};
}>;
};
status?: { phase?: string };
};
const containers = pod.spec?.containers ?? [];
const gpuContainers = containers.filter(c => {
const all = { ...c.resources?.requests, ...c.resources?.limits };
return Object.keys(all).some(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX));
});
if (gpuContainers.length === 0) return null;
// Build rows: one per container per GPU resource
const rows: Array<{ name: string; value: React.ReactNode }> = [];
for (const c of gpuContainers) {
const requests = c.resources?.requests ?? {};
const limits = c.resources?.limits ?? {};
const allGpuKeys = new Set([
...Object.keys(requests).filter(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX)),
...Object.keys(limits).filter(k => k.startsWith(INTEL_GPU_RESOURCE_PREFIX)),
]);
for (const key of allGpuKeys) {
const req = requests[key];
const lim = limits[key];
const resourceName = formatGpuResourceName(key);
rows.push({
name: `${c.name}${resourceName} request`,
value: req ?? '—',
});
if (lim && lim !== req) {
rows.push({
name: `${c.name}${resourceName} limit`,
value: lim,
});
}
}
}
const phase = pod.status?.phase;
const phaseStatus: 'success' | 'warning' | 'error' =
phase === 'Running' || phase === 'Succeeded'
? 'success'
: phase === 'Pending'
? 'warning'
: 'error';
return (
<SectionBox title="Intel GPU Resources">
<NameValueTable
rows={[
{
name: 'Phase',
value: <StatusLabel status={phaseStatus}>{phase ?? 'Unknown'}</StatusLabel>,
},
{
name: 'Scheduled Node',
value: pod.spec?.nodeName ?? '—',
},
{
name: 'GPU Containers',
value: String(gpuContainers.length),
},
...rows,
]}
/>
</SectionBox>
);
}