style(usage): unify name column header + DeletedTag across breakdown tables
This commit is contained in:
@@ -64,6 +64,10 @@ export interface ResourceBreakdownItem extends ResourceBreakdownSummary {
|
|||||||
volume_name?: string;
|
volume_name?: string;
|
||||||
user_id?: number;
|
user_id?: number;
|
||||||
user_name?: string;
|
user_name?: string;
|
||||||
|
// The grouped entity (instance / volume / user) no longer exists. The name
|
||||||
|
// fields keep the clean (stale) name; the tables show a DeletedTag off this
|
||||||
|
// flag plus the id, matching the Tokens tab.
|
||||||
|
deleted?: boolean;
|
||||||
// Grouped-trend rows carry the sub-group label (sku / instance / user / …)
|
// Grouped-trend rows carry the sub-group label (sku / instance / user / …)
|
||||||
// alongside ``date`` so the chart can pivot one series per group.
|
// alongside ``date`` so the chart can pivot one series per group.
|
||||||
group?: string;
|
group?: string;
|
||||||
@@ -277,12 +281,16 @@ function flattenItem(
|
|||||||
};
|
};
|
||||||
if (it.date) flat.date = it.date;
|
if (it.date) flat.date = it.date;
|
||||||
const id = it.id ?? undefined;
|
const id = it.id ?? undefined;
|
||||||
// Deleted entities get a "(Deleted)" suffix, matching the Token breakdown.
|
const deleted = !!it.deleted;
|
||||||
const rawKey = it.key ?? undefined;
|
const rawKey = it.key ?? undefined;
|
||||||
const key = it.deleted && rawKey != null ? `${rawKey} (Deleted)` : rawKey;
|
// The chart series legend keeps the "(Deleted)" suffix (a legend can't render
|
||||||
|
// a tag); the tables show a DeletedTag off ``flat.deleted`` + the id and so
|
||||||
|
// use the clean name.
|
||||||
|
const key = deleted && rawKey != null ? `${rawKey} (Deleted)` : rawKey;
|
||||||
// Generic group label — for a compound (date + dim) trend row the key is the
|
// Generic group label — for a compound (date + dim) trend row the key is the
|
||||||
// sub-group value (the switch below targets single-dimension table rows).
|
// sub-group value (the switch below targets single-dimension table rows).
|
||||||
if (rawKey != null) flat.group = key;
|
if (rawKey != null) flat.group = key;
|
||||||
|
flat.deleted = deleted;
|
||||||
switch (groupBy) {
|
switch (groupBy) {
|
||||||
case 'resource_type':
|
case 'resource_type':
|
||||||
flat.resource_type = key;
|
flat.resource_type = key;
|
||||||
@@ -292,15 +300,15 @@ function flattenItem(
|
|||||||
flat.gpu_type = key;
|
flat.gpu_type = key;
|
||||||
break;
|
break;
|
||||||
case 'instance':
|
case 'instance':
|
||||||
flat.instance_name = key;
|
flat.instance_name = rawKey;
|
||||||
flat.instance_id = id;
|
flat.instance_id = id;
|
||||||
break;
|
break;
|
||||||
case 'volume':
|
case 'volume':
|
||||||
flat.volume_name = key;
|
flat.volume_name = rawKey;
|
||||||
flat.volume_id = id;
|
flat.volume_id = id;
|
||||||
break;
|
break;
|
||||||
case 'user':
|
case 'user':
|
||||||
flat.user_name = key;
|
flat.user_name = rawKey;
|
||||||
flat.user_id = id;
|
flat.user_id = id;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const DeletedTag: React.FC<DeletedTagProps> = ({ id }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{id != null && (
|
{!!id && (
|
||||||
<span className="text-tertiary">
|
<span className="text-tertiary">
|
||||||
<span style={{ margin: '0 2px' }}>·</span>#{id}
|
<span style={{ margin: '0 2px' }}>·</span>#{id}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
// columns.ts
|
// columns.ts
|
||||||
import { AutoTooltip } from '@gpustack/core-ui';
|
import { AutoTooltip } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Tag } from 'antd';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import DeletedTag from '../components/deleted-tag';
|
||||||
import { BreakdownItem as ListItem } from '../config/types';
|
import { BreakdownItem as ListItem } from '../config/types';
|
||||||
|
|
||||||
const useModelsColumns = (): Array<{
|
const useModelsColumns = () => {
|
||||||
title: string;
|
|
||||||
dataIndex: string | string[];
|
|
||||||
key: string;
|
|
||||||
}> => {
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
@@ -19,23 +15,18 @@ const useModelsColumns = (): Array<{
|
|||||||
dataIndex: ['api_key', 'identity', 'value', 'api_key_name'],
|
dataIndex: ['api_key', 'identity', 'value', 'api_key_name'],
|
||||||
key: 'api_key_name',
|
key: 'api_key_name',
|
||||||
render: (text: string, record: ListItem) => (
|
render: (text: string, record: ListItem) => (
|
||||||
<span className="flex items-center">
|
<span className="flex items-center gap-8">
|
||||||
<AutoTooltip ghost title={<span>{text}</span>}>
|
<AutoTooltip ghost title={<span>{text}</span>}>
|
||||||
<span className="text-primary">{text}</span>
|
<span
|
||||||
|
className={
|
||||||
|
record.api_key?.deleted ? 'text-tertiary' : 'text-primary'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
{record.api_key?.deleted && (
|
{record.api_key?.deleted && (
|
||||||
<Tag
|
<DeletedTag id={record.api_key?.identity?.current?.api_key_id} />
|
||||||
style={{
|
|
||||||
marginLeft: 8,
|
|
||||||
borderRadius: 12,
|
|
||||||
color: 'var(--ant-color-text-tertiary)',
|
|
||||||
borderColor: 'var(--ant-color-split)',
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}}
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: 'usage.table.deleted' })}
|
|
||||||
</Tag>
|
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import { getGPUStackPlugin } from '@/plugins';
|
import { getGPUStackPlugin } from '@/plugins';
|
||||||
import { AutoTooltip } from '@gpustack/core-ui';
|
import { AutoTooltip } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Tag } from 'antd';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import DeletedTag from '../components/deleted-tag';
|
||||||
import { BreakdownItem as ListItem } from '../config/types';
|
import { BreakdownItem as ListItem } from '../config/types';
|
||||||
|
|
||||||
// Plugin slot: enterprise plugins can contribute extra columns to the
|
// Plugin slot: enterprise plugins can contribute extra columns to the
|
||||||
@@ -51,27 +51,22 @@ const useModelsColumns = (): ColumnDef[] => {
|
|||||||
dataIndex: ['route', 'label'],
|
dataIndex: ['route', 'label'],
|
||||||
key: 'route_name',
|
key: 'route_name',
|
||||||
render: (text: string, record: ListItem) => (
|
render: (text: string, record: ListItem) => (
|
||||||
<span className="flex items-center">
|
<span className="flex items-center gap-8">
|
||||||
<AutoTooltip
|
<AutoTooltip
|
||||||
ghost
|
ghost
|
||||||
style={{ maxWidth: 400 }}
|
style={{ maxWidth: 400 }}
|
||||||
title={<span>{text}</span>}
|
title={<span>{text}</span>}
|
||||||
>
|
>
|
||||||
<span className="text-primary">{text}</span>
|
<span
|
||||||
|
className={
|
||||||
|
record.route?.deleted ? 'text-tertiary' : 'text-primary'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
{record.route?.deleted && (
|
{record.route?.deleted && (
|
||||||
<Tag
|
<DeletedTag id={record.route?.identity?.current?.route_id} />
|
||||||
style={{
|
|
||||||
marginLeft: 8,
|
|
||||||
borderRadius: 12,
|
|
||||||
color: 'var(--ant-color-text-tertiary)',
|
|
||||||
borderColor: 'var(--ant-color-split)',
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}}
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: 'usage.table.deleted' })}
|
|
||||||
</Tag>
|
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
// columns.ts
|
// columns.ts
|
||||||
import { AutoTooltip } from '@gpustack/core-ui';
|
import { AutoTooltip } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Tag } from 'antd';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import DeletedTag from '../components/deleted-tag';
|
||||||
import { BreakdownItem as ListItem } from '../config/types';
|
import { BreakdownItem as ListItem } from '../config/types';
|
||||||
|
|
||||||
interface ColumnsHookProps {
|
interface ColumnsHookProps {
|
||||||
sortOrder: string[];
|
sortOrder: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const useModelsColumns = (): Array<{
|
const useModelsColumns = () => {
|
||||||
title: string;
|
|
||||||
dataIndex: string | string[];
|
|
||||||
key: string;
|
|
||||||
}> => {
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
@@ -23,27 +19,22 @@ const useModelsColumns = (): Array<{
|
|||||||
dataIndex: ['user', 'identity', 'value', 'user_name'],
|
dataIndex: ['user', 'identity', 'value', 'user_name'],
|
||||||
key: 'user_name',
|
key: 'user_name',
|
||||||
render: (text: string, record: ListItem) => (
|
render: (text: string, record: ListItem) => (
|
||||||
<span className="flex items-center">
|
<span className="flex items-center gap-8">
|
||||||
<AutoTooltip
|
<AutoTooltip
|
||||||
ghost
|
ghost
|
||||||
style={{ maxWidth: 400 }}
|
style={{ maxWidth: 400 }}
|
||||||
title={<span>{text}</span>}
|
title={<span>{text}</span>}
|
||||||
>
|
>
|
||||||
<span className="text-primary">{text}</span>
|
<span
|
||||||
|
className={
|
||||||
|
record.user?.deleted ? 'text-tertiary' : 'text-primary'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
{record.user?.deleted && (
|
{record.user?.deleted && (
|
||||||
<Tag
|
<DeletedTag id={record.user?.identity?.current?.user_id} />
|
||||||
style={{
|
|
||||||
marginLeft: 8,
|
|
||||||
borderRadius: 12,
|
|
||||||
color: 'var(--ant-color-text-tertiary)',
|
|
||||||
borderColor: 'var(--ant-color-split)',
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}}
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: 'usage.table.deleted' })}
|
|
||||||
</Tag>
|
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import {
|
|||||||
buildInstanceTypeRecordFromMiB,
|
buildInstanceTypeRecordFromMiB,
|
||||||
renderInstanceType
|
renderInstanceType
|
||||||
} from '@/pages/gpu-service/instances/utils/render-instance-type';
|
} from '@/pages/gpu-service/instances/utils/render-instance-type';
|
||||||
|
import { AutoTooltip } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { ResourceBreakdownItem } from '../../apis/resource';
|
import { ResourceBreakdownItem } from '../../apis/resource';
|
||||||
|
import DeletedTag from '../../components/deleted-tag';
|
||||||
import { instanceTypeSeriesLabel } from '../../utils/format-instance-type';
|
import { instanceTypeSeriesLabel } from '../../utils/format-instance-type';
|
||||||
import { parseRollup } from '../../utils/time-buckets';
|
import { parseRollup } from '../../utils/time-buckets';
|
||||||
|
|
||||||
@@ -108,6 +110,22 @@ const useInstancesColumns = (groupKey: GroupKey) => {
|
|||||||
key: 'last_active',
|
key: 'last_active',
|
||||||
render: (v?: string) => (v ? parseRollup(v).format('YYYY-MM-DD') : '-')
|
render: (v?: string) => (v ? parseRollup(v).format('YYYY-MM-DD') : '-')
|
||||||
};
|
};
|
||||||
|
// Name cell with a DeletedTag when the entity no longer exists — mirrors the
|
||||||
|
// Tokens tab. The id keeps two deleted rows sharing a stale name distinct.
|
||||||
|
const renderName = (text: string, id?: number, deleted?: boolean) => (
|
||||||
|
<span className="flex items-center gap-8">
|
||||||
|
<AutoTooltip
|
||||||
|
ghost
|
||||||
|
style={{
|
||||||
|
maxWidth: 400,
|
||||||
|
...(deleted ? { color: 'var(--ant-color-text-tertiary)' } : null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text || '-'}
|
||||||
|
</AutoTooltip>
|
||||||
|
{deleted && <DeletedTag id={id ?? null} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
if (groupKey === 'gpu_type') {
|
if (groupKey === 'gpu_type') {
|
||||||
return [
|
return [
|
||||||
instanceTypeColType,
|
instanceTypeColType,
|
||||||
@@ -123,9 +141,11 @@ const useInstancesColumns = (groupKey: GroupKey) => {
|
|||||||
if (groupKey === 'instance') {
|
if (groupKey === 'instance') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'usage.table.instance' }),
|
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||||
dataIndex: 'instance_name',
|
dataIndex: 'instance_name',
|
||||||
key: 'instance_name'
|
key: 'instance_name',
|
||||||
|
render: (text: string, row: ResourceBreakdownItem) =>
|
||||||
|
renderName(text, row.instance_id, row.deleted)
|
||||||
},
|
},
|
||||||
instanceTypeColInstance,
|
instanceTypeColInstance,
|
||||||
...baseValueCols,
|
...baseValueCols,
|
||||||
@@ -135,9 +155,11 @@ const useInstancesColumns = (groupKey: GroupKey) => {
|
|||||||
// user tab
|
// user tab
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'usage.table.user' }),
|
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||||
dataIndex: 'user_name',
|
dataIndex: 'user_name',
|
||||||
key: 'user_name'
|
key: 'user_name',
|
||||||
|
render: (text: string, row: ResourceBreakdownItem) =>
|
||||||
|
renderName(text, row.user_id, row.deleted)
|
||||||
},
|
},
|
||||||
...baseValueCols,
|
...baseValueCols,
|
||||||
lastActiveCol
|
lastActiveCol
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { AutoTooltip } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { ResourceBreakdownItem } from '../../apis/resource';
|
import { ResourceBreakdownItem } from '../../apis/resource';
|
||||||
|
import DeletedTag from '../../components/deleted-tag';
|
||||||
import { parseRollup } from '../../utils/time-buckets';
|
import { parseRollup } from '../../utils/time-buckets';
|
||||||
|
|
||||||
type GroupKey = 'volume' | 'user';
|
type GroupKey = 'volume' | 'user';
|
||||||
@@ -39,12 +41,30 @@ const useStorageColumns = (groupKey: GroupKey) => {
|
|||||||
key: 'last_active',
|
key: 'last_active',
|
||||||
render: (v?: string) => (v ? parseRollup(v).format('YYYY-MM-DD') : '-')
|
render: (v?: string) => (v ? parseRollup(v).format('YYYY-MM-DD') : '-')
|
||||||
};
|
};
|
||||||
|
// Name cell with a DeletedTag when the entity no longer exists — mirrors the
|
||||||
|
// Tokens tab. The id keeps two deleted rows sharing a stale name distinct.
|
||||||
|
const renderName = (text: string, id?: number, deleted?: boolean) => (
|
||||||
|
<span className="flex items-center gap-8">
|
||||||
|
<AutoTooltip
|
||||||
|
ghost
|
||||||
|
style={{
|
||||||
|
maxWidth: 400,
|
||||||
|
...(deleted ? { color: 'var(--ant-color-text-tertiary)' } : null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text || '-'}
|
||||||
|
</AutoTooltip>
|
||||||
|
{deleted && <DeletedTag id={id ?? null} />}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
if (groupKey === 'volume') {
|
if (groupKey === 'volume') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'usage.tabs.storage' }),
|
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||||
dataIndex: 'volume_name',
|
dataIndex: 'volume_name',
|
||||||
key: 'volume_name'
|
key: 'volume_name',
|
||||||
|
render: (text: string, row: ResourceBreakdownItem) =>
|
||||||
|
renderName(text, row.volume_id, row.deleted)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'usage.table.type' }),
|
title: intl.formatMessage({ id: 'usage.table.type' }),
|
||||||
@@ -65,9 +85,11 @@ const useStorageColumns = (groupKey: GroupKey) => {
|
|||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'usage.table.user' }),
|
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||||
dataIndex: 'user_name',
|
dataIndex: 'user_name',
|
||||||
key: 'user_name'
|
key: 'user_name',
|
||||||
|
render: (text: string, row: ResourceBreakdownItem) =>
|
||||||
|
renderName(text, row.user_id, row.deleted)
|
||||||
},
|
},
|
||||||
...valueCols,
|
...valueCols,
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user