fix: details layout

This commit is contained in:
jialin
2026-01-30 18:48:55 +08:00
parent 5747cae87a
commit d173e2d49b
14 changed files with 103 additions and 33 deletions
+10
View File
@@ -120,3 +120,13 @@ export async function exportBenchmarkList(
cancelToken: options?.token cancelToken: options?.token
}); });
} }
export async function stopBenchmark(params: {
id: number;
data: Record<string, any>;
}) {
return request(`${BENCHMARKS_API}/${params.id}/state`, {
method: 'PATCH',
data: params.data
});
}
@@ -40,11 +40,9 @@ const Environment: React.FC = () => {
}, [snapshot]); }, [snapshot]);
const subWorkers = useMemo(() => { const subWorkers = useMemo(() => {
const [[mainWorkerName, mainWorkerInfo]] = Object.entries(snapshot.workers); const [[instanceName, instanceData]] = Object.entries(snapshot.instances);
const subOrdinaryWorkers = Object.values(snapshot.instances).filter( const subOrdinaryWorkers = instanceData?.subordinate_workers || [];
(instance) => instance.worker_name === mainWorkerName
);
return subOrdinaryWorkers.map((worker) => { return subOrdinaryWorkers.map((worker) => {
const gpuData = Object.values(snapshot.gpus).filter( const gpuData = Object.values(snapshot.gpus).filter(
@@ -130,7 +128,7 @@ const Environment: React.FC = () => {
return ( return (
<AutoTooltip <AutoTooltip
ghost ghost
>{`${record.os.name} (${record.os.version})`}</AutoTooltip> >{`${record.os?.name || ''} (${record.os?.version || ''})`}</AutoTooltip>
); );
} }
}, },
@@ -140,7 +138,7 @@ const Environment: React.FC = () => {
key: 'runtime_version', key: 'runtime_version',
span: 3, span: 3,
render: (val: any, record: any) => { render: (val: any, record: any) => {
return <AutoTooltip ghost>{record.runtime_version}</AutoTooltip>; return <AutoTooltip ghost>{record.runtime_version || ''}</AutoTooltip>;
} }
}, },
{ {
@@ -149,7 +147,7 @@ const Environment: React.FC = () => {
key: 'driver_version', key: 'driver_version',
span: 3, span: 3,
render: (val: any, record: any) => { render: (val: any, record: any) => {
return <AutoTooltip ghost>{record.driver_version}</AutoTooltip>; return <AutoTooltip ghost>{record.driver_version || ''}</AutoTooltip>;
} }
}, },
{ {
@@ -13,6 +13,12 @@ const actionList = [
label: 'common.button.edit', label: 'common.button.edit',
icon: icons.EditOutlined icon: icons.EditOutlined
}, },
{
label: 'common.button.stop',
key: 'stop',
icon: icons.Stop,
status: [BenchmarkStatusValueMap.Claimed, BenchmarkStatusValueMap.Running]
},
{ {
label: 'common.button.viewlog', label: 'common.button.viewlog',
key: 'viewlog', key: 'viewlog',
@@ -55,7 +61,7 @@ const RowActions: React.FC<RowActionsProps> = (props) => {
const { onDownloadLog, contextHolder } = useDownloadLogs(); const { onDownloadLog, contextHolder } = useDownloadLogs();
const actions = actionList.filter((action) => { const actions = actionList.filter((action) => {
if (action.key === 'viewlog' || action.key === 'download') { if (action.status && action.status.length > 0) {
return action.status?.includes(record.state); return action.status?.includes(record.state);
} }
@@ -64,12 +64,20 @@ const Instance: React.FC = () => {
key: '1', key: '1',
label: 'Backend Parameters', label: 'Backend Parameters',
children: ( children: (
<Flex gap={8} wrap="wrap"> <Flex
gap={8}
wrap="wrap"
style={{
backgroundColor: 'var(--ant-color-fill-quaternary)',
padding: '4px',
borderRadius: '2px'
}}
>
{instanceData?.backend_parameters?.map( {instanceData?.backend_parameters?.map(
(param: string, index: number) => ( (param: string, index: number) => (
<Tag key={index} style={{ margin: 0 }}> <span key={index} style={{ margin: 0 }}>
{param} {param}
</Tag> </span>
) )
)} )}
</Flex> </Flex>
@@ -142,7 +142,7 @@ const requestFields = [
dataIndex: 'total_requests', dataIndex: 'total_requests',
path: 'total_requests', path: 'total_requests',
precision: 0, precision: 0,
render: (value: number) => round(value, 0), render: (value: number) => round(value, 0) || 0,
unit: '' unit: ''
}, },
{ {
@@ -151,7 +151,7 @@ const requestFields = [
dataIndex: 'successful_requests', dataIndex: 'successful_requests',
path: ['raw_metrics', 'benchmarks', '0'], path: ['raw_metrics', 'benchmarks', '0'],
render: (value: number) => render: (value: number) =>
round(_.get(value, ['metrics', 'request_totals', 'successful']), 0), round(_.get(value, ['metrics', 'request_totals', 'successful']), 0) || 0,
precision: 0, precision: 0,
color: 'var(--ant-color-success)', color: 'var(--ant-color-success)',
unit: '' unit: ''
@@ -162,7 +162,7 @@ const requestFields = [
dataIndex: 'failed_requests', dataIndex: 'failed_requests',
path: ['raw_metrics', 'benchmarks', '0'], path: ['raw_metrics', 'benchmarks', '0'],
render: (value: number) => render: (value: number) =>
round(_.get(value, ['metrics', 'request_totals', 'errored']), 0), round(_.get(value, ['metrics', 'request_totals', 'errored']), 0) || 0,
precision: 0, precision: 0,
color: 'var(--ant-color-error)', color: 'var(--ant-color-error)',
unit: '' unit: ''
@@ -173,7 +173,8 @@ const requestFields = [
dataIndex: 'request_concurrency', dataIndex: 'request_concurrency',
path: ['raw_metrics', 'benchmarks', '0'], path: ['raw_metrics', 'benchmarks', '0'],
render: (value: number) => render: (value: number) =>
round(_.get(value, 'metrics.request_concurrency.successful.mean'), 0), round(_.get(value, 'metrics.request_concurrency.successful.mean'), 0) ||
0,
precision: 0, precision: 0,
unit: '' unit: ''
} }
@@ -281,15 +282,15 @@ const PercentileResult: React.FC = () => {
<Box> <Box>
<Descriptions <Descriptions
styles={descriptionStyles} styles={descriptionStyles}
title="Throughput" title="Latency"
items={throughputItems} items={latencyItems}
colon={false} colon={false}
column={1} column={1}
></Descriptions> ></Descriptions>
<Descriptions <Descriptions
styles={descriptionStyles} styles={descriptionStyles}
title="Latency" title="Throughput"
items={latencyItems} items={throughputItems}
colon={false} colon={false}
column={1} column={1}
></Descriptions> ></Descriptions>
@@ -85,7 +85,7 @@ const PercentileResult: React.FC = () => {
title: 'Percentile', title: 'Percentile',
dataIndex: 'percentile', dataIndex: 'percentile',
render: (value: string) => ( render: (value: string) => (
<span style={{ fontWeight: 500 }}>{value}</span> <span style={{ fontWeight: 400 }}>{value}</span>
) )
}, },
...columns ...columns
@@ -100,6 +100,7 @@ const PercentileResult: React.FC = () => {
}, },
cell: { cell: {
fontWeight: 400, fontWeight: 400,
height: 40,
borderBottom: '1px solid var(--ant-color-split)' borderBottom: '1px solid var(--ant-color-split)'
} }
}, },
@@ -1,4 +1,3 @@
import { BulbOutlined } from '@ant-design/icons';
import styled from 'styled-components'; import styled from 'styled-components';
const Content = styled.div` const Content = styled.div`
@@ -8,14 +7,15 @@ const Content = styled.div`
`; `;
const Title: React.FC<{ children: React.ReactNode }> = ({ children }) => { const Title: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return ( // return (
<Content> // <Content>
<BulbOutlined // <BulbOutlined
style={{ marginRight: 8, color: 'var(--ant-color-text-tertiary)' }} // style={{ marginRight: 8, color: 'var(--ant-color-text-tertiary)' }}
/> // />
{children} // {children}
</Content> // </Content>
); // );
return <span></span>;
}; };
export default Title; export default Title;
+1 -1
View File
@@ -31,7 +31,7 @@ export interface InstancesData {
env: any; env: any;
extended_kv_cache: any; extended_kv_cache: any;
speculative_config: any; speculative_config: any;
subordinate_workers: any; subordinate_workers: any[];
} }
export interface WorkerData { export interface WorkerData {
+2
View File
@@ -1,5 +1,6 @@
import SealInput from '@/components/seal-form/seal-input'; import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form } from 'antd'; import { Form } from 'antd';
@@ -77,6 +78,7 @@ const DatasetForm: React.FC = () => {
]} ]}
> >
<SealSelect <SealSelect
disabled={action === PageAction.EDIT}
onChange={handleProfileChange} onChange={handleProfileChange}
options={profilesOptions} options={profilesOptions}
label={intl.formatMessage({ id: 'benchmark.form.profile' })} label={intl.formatMessage({ id: 'benchmark.form.profile' })}
+5 -1
View File
@@ -78,7 +78,11 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
useEffect(() => { useEffect(() => {
if (action === PageAction.EDIT && currentData) { if (action === PageAction.EDIT && currentData) {
form.setFieldsValue({ form.setFieldsValue({
...currentData ...currentData,
model_instance: [
currentData.model_name,
currentData.model_instance_name
]
}); });
} }
}, [form, currentData, action]); }, [form, currentData, action]);
@@ -1,4 +1,5 @@
import SealCascader from '@/components/seal-form/seal-cascader'; import SealCascader from '@/components/seal-form/seal-cascader';
import { PageAction } from '@/config';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import { import {
InstanceStatusMap, InstanceStatusMap,
@@ -133,6 +134,7 @@ const ModelInstanceForm: React.FC = () => {
<SealCascader <SealCascader
required required
showSearch showSearch
disabled={action === PageAction.EDIT}
loading={modelLoading || instanceLoading} loading={modelLoading || instanceLoading}
changeOnSelect={false} changeOnSelect={false}
expandTrigger="hover" expandTrigger="hover"
@@ -1,9 +1,11 @@
import SealInputNumber from '@/components/seal-form/input-number'; import SealInputNumber from '@/components/seal-form/input-number';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form } from 'antd'; import { Form } from 'antd';
import React from 'react'; import React, { useMemo } from 'react';
import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types'; import { FormData } from '../config/types';
const RandomSettingsForm: React.FC<{ const RandomSettingsForm: React.FC<{
@@ -13,11 +15,16 @@ const RandomSettingsForm: React.FC<{
}> = (props) => { }> = (props) => {
const { datasetList, datasetLoading, handleOnDataSetChange } = props; const { datasetList, datasetLoading, handleOnDataSetChange } = props;
const intl = useIntl(); const intl = useIntl();
const { action, open } = useFormContext();
const form = Form.useFormInstance(); const form = Form.useFormInstance();
const profile = Form.useWatch('profile', form); const profile = Form.useWatch('profile', form);
const { getRuleMessage } = useAppUtils(); const { getRuleMessage } = useAppUtils();
const disabled = profile !== 'Custom' && Boolean(profile); const disabled = useMemo(() => {
return (
(profile !== 'Custom' && Boolean(profile)) || action === PageAction.EDIT
);
}, [profile, action]);
return ( return (
<> <>
+4
View File
@@ -30,6 +30,7 @@ import useCreateBenchmark from './hooks/use-create-benchmark';
import useViewLogs from './hooks/use-view-logs'; import useViewLogs from './hooks/use-view-logs';
import { useExportBenchmark } from './services/use-export-benchmark'; import { useExportBenchmark } from './services/use-export-benchmark';
import useQueryDataset from './services/use-query-dataset'; import useQueryDataset from './services/use-query-dataset';
import useStopBenchmark from './services/use-stop-benchmark';
const Benchmark: React.FC = () => { const Benchmark: React.FC = () => {
const { const {
@@ -63,6 +64,7 @@ const Benchmark: React.FC = () => {
const { openViewLogsModal, closeViewLogsModal, openViewLogsModalStatus } = const { openViewLogsModal, closeViewLogsModal, openViewLogsModalStatus } =
useViewLogs(); useViewLogs();
const { SettingsButton, selectedColumns } = useColumnSettings(); const { SettingsButton, selectedColumns } = useColumnSettings();
const { handleStopBenchmark } = useStopBenchmark();
const { datasetList, fetchDatasetData } = useQueryDataset(); const { datasetList, fetchDatasetData } = useQueryDataset();
const { exportData } = useExportBenchmark(); const { exportData } = useExportBenchmark();
@@ -114,6 +116,8 @@ const Benchmark: React.FC = () => {
handleDelete({ ...row, name: row.name }); handleDelete({ ...row, name: row.name });
} else if (val === 'viewlog') { } else if (val === 'viewlog') {
openViewLogsModal(row); openViewLogsModal(row);
} else if (val === 'stop') {
handleStopBenchmark(row.id);
} }
}); });
@@ -0,0 +1,27 @@
import { useIntl } from '@umijs/max';
import { message } from 'antd';
import { stopBenchmark } from '../apis';
import { BenchmarkStatusValueMap } from '../config';
const useStopBenchmark = () => {
const intl = useIntl();
const handleStopBenchmark = async (id: number) => {
try {
await stopBenchmark({
id,
data: {
state: BenchmarkStatusValueMap.Stopped
}
});
message.success(intl.formatMessage({ id: 'common.message.success' }));
} catch (error) {}
};
const handleBatchStopBenchmark = async (ids: number[]) => {};
return {
handleStopBenchmark
};
};
export default useStopBenchmark;