fix: show cpu only spec info

This commit is contained in:
jialin
2026-06-17 20:11:06 +08:00
committed by jialin
parent c532732ce9
commit cb19cd2476
2 changed files with 48 additions and 12 deletions
@@ -85,6 +85,9 @@ const formatResources = (
}; };
}; };
// Spec popover categories, in render order.
type SpecCategory = 'gpu' | 'cpu' | 'ram' | 'disk';
export const renderInstanceType = ( export const renderInstanceType = (
record: ListItem, record: ListItem,
options: { options: {
@@ -92,22 +95,31 @@ export const renderInstanceType = (
// name → capacity (e.g. "20Gi") for referenced persistent volumes, so the // name → capacity (e.g. "20Gi") for referenced persistent volumes, so the
// Disk → Persistent row can show the size instead of just the PV name. // Disk → Persistent row can show the size instead of just the PV name.
pvCapacityByName?: Record<string, string>; pvCapacityByName?: Record<string, string>;
// Limit the spec popover to these categories (default: all). The Instance
// Types breakdown only wants CPU + RAM, for example.
categories?: SpecCategory[];
// Override the primary label (default: derived "<product> x <count>" /
// "CPU Only"). The Instance Types breakdown keeps its plain product name.
title?: string;
} }
) => { ) => {
const { intl, pvCapacityByName } = options; const { intl, pvCapacityByName, categories } = options;
const description = const description =
parseJsonSafe<any>(record?.description || '{}', {}).spec || {}; parseJsonSafe<any>(record?.description || '{}', {}).spec || {};
const resources = formatResources({ spec: description }, record); const resources = formatResources({ spec: description }, record);
const accelerator = record.spec?.resources?.accelerator; const accelerator = record.spec?.resources?.accelerator;
const title = description.acceleratable const title =
? `${description.product} x ${accelerator}` options.title ??
: 'CPU Only'; (description.acceleratable
? `${description.product} x ${accelerator}`
: 'CPU Only');
const volume = (record.spec as any)?.volume; const volume = (record.spec as any)?.volume;
// Spec popover grouped by category (GPU / CPU / Memory / Disk), mirroring // Spec popover grouped by category (GPU / CPU / Memory / Disk), mirroring
// the Deployments instance info icon: dark tooltip, per-category icon, // the Deployments instance info icon: dark tooltip, per-category icon,
// instance name as the title. Rows with no value are dropped. // instance name as the title. Rows with no value are dropped.
type Section = { type Section = {
key: SpecCategory;
icon: string; icon: string;
name: string; name: string;
rows: [string | null, string | undefined][]; rows: [string | null, string | undefined][];
@@ -115,6 +127,7 @@ export const renderInstanceType = (
const sections: Section[] = []; const sections: Section[] = [];
if (description.acceleratable) { if (description.acceleratable) {
sections.push({ sections.push({
key: 'gpu',
icon: 'icon-gpu', icon: 'icon-gpu',
name: 'GPU', name: 'GPU',
rows: [ rows: [
@@ -134,16 +147,19 @@ export const renderInstanceType = (
}); });
} }
sections.push({ sections.push({
key: 'cpu',
icon: 'icon-cpu', icon: 'icon-cpu',
name: 'CPU', name: 'CPU',
rows: [[null, resources.cpu]] rows: [[null, resources.cpu]]
}); });
sections.push({ sections.push({
key: 'ram',
icon: 'icon-ram-02', icon: 'icon-ram-02',
name: intl.formatMessage({ id: 'gpuservice.instance.ram' }), name: intl.formatMessage({ id: 'gpuservice.instance.ram' }),
rows: [[null, resources.ram]] rows: [[null, resources.ram]]
}); });
sections.push({ sections.push({
key: 'disk',
icon: 'icon-hard-disk', icon: 'icon-hard-disk',
name: intl.formatMessage({ id: 'gpuservice.instance.disk' }), name: intl.formatMessage({ id: 'gpuservice.instance.disk' }),
rows: [ rows: [
@@ -170,8 +186,16 @@ export const renderInstanceType = (
] ]
}); });
const visibleSections = categories
? sections.filter((s) => categories.includes(s.key))
: sections;
return ( return (
<InstanceTypeCell title={title} name={record.name} sections={sections} /> <InstanceTypeCell
title={title}
name={record.name}
sections={visibleSections}
/>
); );
}; };
@@ -36,18 +36,30 @@ const useInstancesColumns = (groupKey: GroupKey) => {
render: (v: number) => (v ?? 0).toFixed(2) render: (v: number) => (v ?? 0).toFixed(2)
} }
]; ];
// Instance Types breakdown: just the pretty product name (or flavor slug // Instance Types breakdown: the pretty product name (or flavor slug for
// for older rows) — no spec sub-line. CPU-only flavors (no GPU cards) show // older rows; "CPU Only" when no GPU cards) plus a CPU + RAM spec popover —
// "CPU Only", matching the canonical GPU Instances renderer. // rendered through the canonical renderer so the formatting matches the GPU
// Instances list, but limited to the CPU/RAM categories.
const instanceTypeColType = { const instanceTypeColType = {
title: intl.formatMessage({ id: 'usage.table.instanceType' }), title: intl.formatMessage({ id: 'usage.table.instanceType' }),
dataIndex: 'gpu_type', dataIndex: 'gpu_type',
key: 'gpu_type', key: 'gpu_type',
render: (_v: string, row: ResourceBreakdownItem) => render: (_v: string, row: ResourceBreakdownItem) =>
(row.gpu_count ?? 0) > 0 ? ( renderInstanceType(
instanceTypeLabel(row) buildInstanceTypeRecordFromMiB({
) : ( name: row.instance_name,
<span className="text-primary">CPU Only</span> product: row.product || row.gpu_type,
gpuCount: row.gpu_count,
unitCpuMilli: row.unit_cpu_milli,
unitMemoryMib: row.unit_memory_mib,
vramMib: row.vram_mib
}),
{
intl,
categories: ['cpu', 'ram'],
title:
(row.gpu_count ?? 0) > 0 ? instanceTypeLabel(row) : 'CPU Only'
}
) )
}; };
// Instances breakdown: render through the canonical GPU Instances list // Instances breakdown: render through the canonical GPU Instances list