feat(gpu-service): instance-type spec popover with per-card specs
Replace the raw flavor slug in the GPU Instances list with the product name
("<product> x <count>") plus an info-icon popover that breaks the spec down by
category (GPU / CPU / Memory / Disk): per-card VRAM, whole-instance CPU/RAM,
system / ephemeral / persistent disks (persistent size resolved from the
referenced PV). Extract the cell into a shared InstanceTypeCell and centralize
memory formatting in formatMemoryDisplay so the GPU Instances list and the
Usage tab render identical sizes.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { AutoTooltip, IconFont } from '@gpustack/core-ui';
|
||||
import { Flex, Tooltip } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export type InstanceTypeSection = {
|
||||
icon: string;
|
||||
name: string;
|
||||
// [label, value] — a null label renders a single value with no sub-label;
|
||||
// rows whose value is falsy or "-" are dropped.
|
||||
rows: [string | null, string | undefined][];
|
||||
};
|
||||
|
||||
/**
|
||||
* "Instance Type" cell shared by the GPU Instances list and the Usage GPU
|
||||
* Instances table: a primary product label (e.g. "NVIDIA-GeForce-RTX-5090-D x
|
||||
* 1") plus a question/info icon whose dark popover breaks the spec down by
|
||||
* category (GPU / CPU / Memory / Disk), titled with the instance name.
|
||||
*/
|
||||
const InstanceTypeCell: React.FC<{
|
||||
title: string;
|
||||
name?: string;
|
||||
sections: InstanceTypeSection[];
|
||||
}> = ({ title, name, sections }) => {
|
||||
const specInfo = (
|
||||
<div style={{ minWidth: 200 }}>
|
||||
{name && <div style={{ fontWeight: 600, marginBottom: 8 }}>{name}</div>}
|
||||
{sections.map((sec) => {
|
||||
const rows = sec.rows.filter(([, v]) => v && v !== '-');
|
||||
if (!rows.length) return null;
|
||||
return (
|
||||
<div
|
||||
key={sec.name}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
gap: 16,
|
||||
marginBottom: 6
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
minWidth: 88,
|
||||
lineHeight: '22px'
|
||||
}}
|
||||
>
|
||||
<IconFont type={sec.icon} />
|
||||
<span>{sec.name}</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
{rows.map(([label, value], i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{ display: 'flex', gap: 16, lineHeight: '22px' }}
|
||||
>
|
||||
<span style={{ opacity: 0.65, minWidth: 96 }}>
|
||||
{label || ''}
|
||||
</span>
|
||||
<span>{value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex align="center" style={{ gap: 6 }}>
|
||||
<AutoTooltip ghost title={<span>{title}</span>}>
|
||||
<span className="text-primary">{title}</span>
|
||||
</AutoTooltip>
|
||||
<Tooltip
|
||||
title={specInfo}
|
||||
styles={{ container: { width: 'max-content', maxWidth: 480 } }}
|
||||
>
|
||||
<InfoCircleOutlined
|
||||
style={{ color: 'var(--ant-color-primary)', cursor: 'pointer' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default InstanceTypeCell;
|
||||
@@ -3,12 +3,9 @@ import { useIntl } from '@umijs/max';
|
||||
import { Flex } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { manufactureColorMap } from '../../templates/config';
|
||||
import { convertKiToGi } from '../config';
|
||||
import { formatMemoryDisplay } from '../config';
|
||||
import { InstanceTypeItem as InstanceTypeItemModel } from '../config/types';
|
||||
|
||||
const toDisplayUnit = (value?: string | null) =>
|
||||
value ? value.replace(/Gi$/, 'GB').replace(/Ti$/, 'TB') : value;
|
||||
|
||||
const Title = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -136,8 +133,7 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
|
||||
icon="icon-gpu1"
|
||||
label={intl.formatMessage({ id: 'gpuservice.instance.memory' })}
|
||||
value={
|
||||
toDisplayUnit(convertKiToGi(specData?.memory ?? undefined)) ??
|
||||
'-'
|
||||
formatMemoryDisplay(specData?.memory ?? undefined) ?? '-'
|
||||
}
|
||||
/>
|
||||
<MetaItem
|
||||
|
||||
Reference in New Issue
Block a user