feat: benchmark detail actions
This commit is contained in:
@@ -10,6 +10,7 @@ type AddModalProps = {
|
||||
action: PageActionType;
|
||||
open: boolean;
|
||||
currentData?: ListItem; // Used when action is EDIT
|
||||
clusterList?: Global.BaseOption<number>[];
|
||||
onOk: (values: FormData) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
@@ -18,6 +19,7 @@ const AddBenchmark: React.FC<AddModalProps> = ({
|
||||
action,
|
||||
open,
|
||||
currentData,
|
||||
clusterList,
|
||||
onOk,
|
||||
onCancel
|
||||
}) => {
|
||||
@@ -51,6 +53,7 @@ const AddBenchmark: React.FC<AddModalProps> = ({
|
||||
action={action}
|
||||
open={open}
|
||||
currentData={currentData}
|
||||
clusterList={clusterList}
|
||||
onFinish={handleOk}
|
||||
/>
|
||||
</FormDrawer>
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||
import { useIntl, useSearchParams } from '@umijs/max';
|
||||
import { Tabs, TabsProps } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import DetailContext from '../config/detail-context';
|
||||
import { BenchmarkListItem } from '../config/types';
|
||||
import useQueryDetail from '../services/use-query-detail';
|
||||
import React, { useState } from 'react';
|
||||
import Environment from './environment';
|
||||
import Summary from './summary';
|
||||
|
||||
const Details: React.FC<{ currentData?: BenchmarkListItem }> = ({
|
||||
currentData
|
||||
}) => {
|
||||
const Details: React.FC<{
|
||||
tabBarExtraContent: {
|
||||
right: React.ReactNode;
|
||||
};
|
||||
}> = ({ tabBarExtraContent }) => {
|
||||
const intl = useIntl();
|
||||
const [searchParams] = useSearchParams();
|
||||
const id = searchParams.get('id');
|
||||
const { loading, detailData, cancelRequest, fetchData } = useQueryDetail();
|
||||
const {
|
||||
clusterList,
|
||||
fetchClusterList,
|
||||
cancelRequest: cancelClusterRequest
|
||||
} = useQueryClusterList();
|
||||
const [activeKey, setActiveKey] = useState('summary');
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
@@ -36,45 +27,21 @@ const Details: React.FC<{ currentData?: BenchmarkListItem }> = ({
|
||||
children: <Environment />,
|
||||
icon: <IconFont type="icon-server02" />
|
||||
}
|
||||
// {
|
||||
// key: 'logs',
|
||||
// label: intl.formatMessage({ id: 'benchmark.detail.logs.title' }),
|
||||
// children: <Logs />,
|
||||
// icon: <IconFont type="icon-logs" />
|
||||
// }
|
||||
];
|
||||
|
||||
const handleChangeTab = (key: string) => {
|
||||
setActiveKey(key);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchData(id);
|
||||
fetchClusterList({ page: -1 });
|
||||
} else {
|
||||
cancelRequest();
|
||||
cancelClusterRequest();
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<DetailContext.Provider
|
||||
value={{
|
||||
detailData: detailData || {},
|
||||
clusterList: clusterList,
|
||||
loading: loading,
|
||||
id: Number(id)
|
||||
}}
|
||||
>
|
||||
<Tabs
|
||||
size="small"
|
||||
activeKey={activeKey}
|
||||
onChange={handleChangeTab}
|
||||
items={items}
|
||||
type="card"
|
||||
/>
|
||||
</DetailContext.Provider>
|
||||
<Tabs
|
||||
size="small"
|
||||
activeKey={activeKey}
|
||||
onChange={handleChangeTab}
|
||||
items={items}
|
||||
type="card"
|
||||
tabBarExtraContent={tabBarExtraContent}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation-name: fade-in;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import './fade-in.less';
|
||||
|
||||
type FadeInProps = PropsWithChildren<{
|
||||
duration?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}>;
|
||||
|
||||
const FadeIn: React.FC<FadeInProps> = ({
|
||||
children,
|
||||
duration = 200,
|
||||
delay = 0,
|
||||
className
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`fade-in ${className || ''}`}
|
||||
style={{
|
||||
animationDuration: `${duration}ms`,
|
||||
animationDelay: `${delay}ms`
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FadeIn;
|
||||
@@ -53,15 +53,18 @@ const actionList = [
|
||||
|
||||
interface RowActionsProps {
|
||||
record: ListItem;
|
||||
page?: 'detail' | 'list';
|
||||
handleSelect: (key: string, record: ListItem) => void;
|
||||
}
|
||||
|
||||
const RowActions: React.FC<RowActionsProps> = (props) => {
|
||||
const { record, handleSelect } = props;
|
||||
const { record, handleSelect, page = 'list' } = props;
|
||||
const { onDownloadLog, contextHolder } = useDownloadLogs();
|
||||
|
||||
const actions = actionList.filter((action) => {
|
||||
if (action.status && action.status.length > 0) {
|
||||
if (page === 'detail' && action.key === 'edit') {
|
||||
return false;
|
||||
} else if (action.status && action.status.length > 0) {
|
||||
return action.status?.includes(record.state);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Descriptions, Flex, Tag } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
|
||||
const calcTotalVram = (vram: Record<string, number>) => {
|
||||
return _.sum(_.values(vram));
|
||||
};
|
||||
|
||||
const Instance: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const { detailData } = useDetailContext();
|
||||
|
||||
@@ -1,14 +1,45 @@
|
||||
import DeleteModal from '@/components/delete-modal';
|
||||
import BaseSelect from '@/components/seal-form/base/select';
|
||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { PageContainerInner } from '../_components/page-box';
|
||||
import PageBreadcrumb from '../_components/page-breadcrumb';
|
||||
import { deleteBenchmark } from './apis';
|
||||
import DetailContent from './components/detail-content';
|
||||
import FadeIn from './components/fade-in';
|
||||
import RowActions from './components/row-actions';
|
||||
import ViewLogsModal from './components/view-logs-modal';
|
||||
import DetailContext from './config/detail-context';
|
||||
import { BenchmarkListItem } from './config/types';
|
||||
import useViewLogs from './hooks/use-view-logs';
|
||||
import useQueryBenchmarkList from './services/use-query-benchmarks';
|
||||
import useQueryDetail from './services/use-query-detail';
|
||||
import useStopBenchmark from './services/use-stop-benchmark';
|
||||
|
||||
const Details: React.FC = () => {
|
||||
const modalRef = useRef<any>(null);
|
||||
const navigate = useNavigate();
|
||||
const intl = useIntl();
|
||||
const {
|
||||
dataList: benchmarkList,
|
||||
fetchData: fetchBenchmarkList,
|
||||
cancelRequest: cancelBenchmarkRequest
|
||||
} = useQueryBenchmarkList();
|
||||
const { loading, detailData, cancelRequest, fetchData } = useQueryDetail();
|
||||
const { openViewLogsModal, closeViewLogsModal, openViewLogsModalStatus } =
|
||||
useViewLogs();
|
||||
const { handleStopBenchmark } = useStopBenchmark();
|
||||
const [searchParams] = useSearchParams();
|
||||
const name = searchParams.get('name');
|
||||
const id = searchParams.get('id');
|
||||
|
||||
const handleOnChange = (value: number, option: any) => {
|
||||
navigate(
|
||||
`/models/benchmark/detail?id=${option.value}&name=${option.label}`,
|
||||
{ state: 'benchmark-details', replace: true }
|
||||
);
|
||||
};
|
||||
|
||||
const breadcrumbItems = [
|
||||
{
|
||||
@@ -16,20 +47,114 @@ const Details: React.FC = () => {
|
||||
onClick: () => navigate(-1)
|
||||
},
|
||||
{
|
||||
title: name
|
||||
title: (
|
||||
<BaseSelect
|
||||
size="small"
|
||||
variant="borderless"
|
||||
options={benchmarkList}
|
||||
value={name}
|
||||
style={{ minWidth: 100 }}
|
||||
popupMatchSelectWidth={false}
|
||||
onChange={handleOnChange}
|
||||
></BaseSelect>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const handleDelete = (row: BenchmarkListItem) => {
|
||||
modalRef.current?.show({
|
||||
content: 'benchmark.title',
|
||||
operation: 'common.delete.single.confirm',
|
||||
name: row.name,
|
||||
async onOk() {
|
||||
await deleteBenchmark(row.id);
|
||||
fetchBenchmarkList({ page: -1 }).then((items) => {
|
||||
if (items.length === 0) {
|
||||
navigate(-1);
|
||||
} else {
|
||||
handleOnChange(items[0].id, {
|
||||
value: items[0].id,
|
||||
label: items[0].name
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelect = useMemoizedFn((val: any, row: BenchmarkListItem) => {
|
||||
if (val === 'delete') {
|
||||
handleDelete({ ...row, name: row.name });
|
||||
} else if (val === 'viewlog') {
|
||||
openViewLogsModal(row);
|
||||
} else if (val === 'stop') {
|
||||
handleStopBenchmark(row.id);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${intl.formatMessage({ id: 'benchmark.title' })} - ${name}`;
|
||||
}, [name, intl]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchBenchmarkList({ page: -1 });
|
||||
return () => {
|
||||
cancelBenchmarkRequest();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchData(id);
|
||||
} else {
|
||||
cancelRequest();
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<PageContainerInner
|
||||
header={{
|
||||
title: <PageBreadcrumb items={breadcrumbItems} />
|
||||
}}
|
||||
>
|
||||
<DetailContent></DetailContent>
|
||||
<DetailContext.Provider
|
||||
value={{
|
||||
detailData: detailData || {},
|
||||
clusterList: [],
|
||||
loading: loading,
|
||||
id: Number(id)
|
||||
}}
|
||||
>
|
||||
<DetailContent
|
||||
tabBarExtraContent={{
|
||||
right: (
|
||||
<FadeIn>
|
||||
<div
|
||||
style={{
|
||||
opacity: loading ? 0 : 1,
|
||||
position: 'relative',
|
||||
bottom: -2,
|
||||
right: -1
|
||||
}}
|
||||
>
|
||||
<RowActions
|
||||
page="detail"
|
||||
record={detailData as any}
|
||||
handleSelect={handleSelect}
|
||||
></RowActions>
|
||||
</div>
|
||||
</FadeIn>
|
||||
)
|
||||
}}
|
||||
></DetailContent>
|
||||
</DetailContext.Provider>
|
||||
<ViewLogsModal
|
||||
open={openViewLogsModalStatus.open}
|
||||
url={openViewLogsModalStatus.url}
|
||||
tail={openViewLogsModalStatus.tail}
|
||||
onCancel={closeViewLogsModal}
|
||||
></ViewLogsModal>
|
||||
<DeleteModal ref={modalRef}></DeleteModal>
|
||||
</PageContainerInner>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ import SealSelect from '@/components/seal-form/seal-select';
|
||||
import { PageAction } from '@/config';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { ClusterStatusValueMap } from '@/pages/cluster-management/config';
|
||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
@@ -15,13 +14,7 @@ const BasicForm: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const form = Form.useFormInstance();
|
||||
const { getRuleMessage } = useAppUtils();
|
||||
const { action, open } = useFormContext();
|
||||
const {
|
||||
loading: clusterLoading,
|
||||
fetchClusterList,
|
||||
cancelRequest: cancelClusterRequest,
|
||||
clusterList
|
||||
} = useQueryClusterList();
|
||||
const { action, open, clusterList } = useFormContext();
|
||||
|
||||
useEffect(() => {
|
||||
const initClusterId = (list: any[]) => {
|
||||
@@ -37,18 +30,14 @@ const BasicForm: React.FC = () => {
|
||||
|
||||
return cluster_id;
|
||||
};
|
||||
fetchClusterList({ page: -1 }).then((list) => {
|
||||
if (list.length > 0 && action === PageAction.CREATE) {
|
||||
form.setFieldValue('cluster_id', initClusterId(list));
|
||||
}
|
||||
});
|
||||
}, [form, action]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
cancelClusterRequest();
|
||||
if (
|
||||
clusterList &&
|
||||
clusterList?.length > 0 &&
|
||||
action === PageAction.CREATE
|
||||
) {
|
||||
form.setFieldValue('cluster_id', initClusterId(clusterList));
|
||||
}
|
||||
}, [open]);
|
||||
}, [form, action, clusterList]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -78,7 +67,6 @@ const BasicForm: React.FC = () => {
|
||||
>
|
||||
<SealSelect
|
||||
disabled={action === PageAction.EDIT}
|
||||
loading={clusterLoading}
|
||||
options={clusterList}
|
||||
label={intl.formatMessage({ id: 'clusters.title' })}
|
||||
required
|
||||
|
||||
@@ -23,6 +23,7 @@ interface ProviderFormProps {
|
||||
action: PageActionType;
|
||||
currentData?: ListItem; // Used when action is EDIT
|
||||
open?: boolean;
|
||||
clusterList?: Global.BaseOption<number>[];
|
||||
onFinish: (values: FormData) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ const TABKeysMap = {
|
||||
};
|
||||
|
||||
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||
const { action, currentData, onFinish, open } = props;
|
||||
const { action, currentData, onFinish, open, clusterList } = props;
|
||||
const intl = useIntl();
|
||||
const [form] = Form.useForm();
|
||||
const profile = Form.useWatch('profile', form);
|
||||
@@ -109,7 +110,8 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||
<FormContext.Provider
|
||||
value={{
|
||||
action,
|
||||
open
|
||||
open,
|
||||
clusterList: clusterList
|
||||
}}
|
||||
>
|
||||
<Form
|
||||
|
||||
@@ -29,9 +29,12 @@ const defaultColumns: string[] = [
|
||||
];
|
||||
const fixedColumns: string[] = [];
|
||||
|
||||
const useColumnSettings = (options: { contentHeight: number }) => {
|
||||
const useColumnSettings = (options: {
|
||||
contentHeight: number;
|
||||
clusterList: Global.BaseOption<number>[];
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { contentHeight } = options;
|
||||
const { contentHeight, clusterList } = options;
|
||||
const [selectedColumns, setSelectedColumns] =
|
||||
React.useState<string[]>(defaultColumns);
|
||||
|
||||
@@ -241,22 +244,22 @@ const useColumnSettings = (options: { contentHeight: number }) => {
|
||||
title: renderTitle(intl.formatMessage({ id: 'clusters.title' })),
|
||||
pos: 1,
|
||||
dataIndex: 'cluster_id',
|
||||
render: (text: string) => (
|
||||
render: (text: number) => (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
</AutoTooltip>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: renderTitle(intl.formatMessage({ id: 'resources.worker' })),
|
||||
pos: 2,
|
||||
dataIndex: 'worker_id',
|
||||
render: (text: string) => (
|
||||
<AutoTooltip ghost minWidth={20}>
|
||||
{text}
|
||||
{clusterList?.find((item) => item.value === text)?.label || text}
|
||||
</AutoTooltip>
|
||||
)
|
||||
},
|
||||
// {
|
||||
// title: renderTitle(intl.formatMessage({ id: 'resources.worker' })),
|
||||
// pos: 2,
|
||||
// dataIndex: 'worker_id',
|
||||
// render: (text: string) => (
|
||||
// <AutoTooltip ghost minWidth={20}>
|
||||
// {text}
|
||||
// </AutoTooltip>
|
||||
// )
|
||||
// },
|
||||
{
|
||||
title: renderTitle(
|
||||
intl.formatMessage({ id: 'benchmark.detail.modelName' })
|
||||
@@ -364,9 +367,8 @@ const useColumnSettings = (options: { contentHeight: number }) => {
|
||||
);
|
||||
// Sort by pos
|
||||
selected.sort((a, b) => (a.pos || 0) - (b.pos || 0));
|
||||
console.log('columns===', selected);
|
||||
return selected;
|
||||
}, [selectedColumns]);
|
||||
}, [selectedColumns, clusterList]);
|
||||
|
||||
const SettingsButton = (
|
||||
<ColumnSettings
|
||||
|
||||
@@ -12,6 +12,7 @@ import _ from 'lodash';
|
||||
import { useEffect } from 'react';
|
||||
import NoResult from '../_components/no-result';
|
||||
import PageBox from '../_components/page-box';
|
||||
import { useQueryClusterList } from '../cluster-management/services/use-query-cluster-list';
|
||||
import {
|
||||
BENCHMARKS_API,
|
||||
createBenchmark,
|
||||
@@ -63,17 +64,26 @@ const Benchmark: React.FC = () => {
|
||||
});
|
||||
const { openViewLogsModal, closeViewLogsModal, openViewLogsModalStatus } =
|
||||
useViewLogs();
|
||||
const { SettingsButton, columns: selectedColumns } = useColumnSettings({
|
||||
contentHeight: 320
|
||||
});
|
||||
const { handleStopBenchmark } = useStopBenchmark();
|
||||
|
||||
const { datasetList, fetchDatasetData } = useQueryDataset();
|
||||
const { exportData } = useExportBenchmark();
|
||||
const {
|
||||
fetchClusterList,
|
||||
cancelRequest: cancelClusterRequest,
|
||||
clusterList
|
||||
} = useQueryClusterList();
|
||||
const { SettingsButton, columns: selectedColumns } = useColumnSettings({
|
||||
contentHeight: 320,
|
||||
clusterList
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchModelList({ page: -1 });
|
||||
fetchClusterList({ page: -1 });
|
||||
fetchDatasetData();
|
||||
return () => {
|
||||
cancelClusterRequest();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleAddBenchmark = () => {
|
||||
@@ -110,7 +120,7 @@ const Benchmark: React.FC = () => {
|
||||
closeBenchmarkModal();
|
||||
};
|
||||
|
||||
const handleEditUser = (row: ListItem) => {
|
||||
const handleEdit = (row: ListItem) => {
|
||||
openBenchmarkModal(
|
||||
PageAction.EDIT,
|
||||
intl.formatMessage({ id: 'benchmark.button.edit' }),
|
||||
@@ -120,7 +130,7 @@ const Benchmark: React.FC = () => {
|
||||
|
||||
const handleSelect = useMemoizedFn((val: any, row: ListItem) => {
|
||||
if (val === 'edit') {
|
||||
handleEditUser(row);
|
||||
handleEdit(row);
|
||||
} else if (val === 'delete') {
|
||||
handleDelete({ ...row, name: row.name });
|
||||
} else if (val === 'viewlog') {
|
||||
@@ -134,7 +144,8 @@ const Benchmark: React.FC = () => {
|
||||
(record: ListItem, dataIndex: string) => {
|
||||
if (dataIndex === 'name') {
|
||||
navigate(
|
||||
`/models/benchmark/detail?id=${record.id}&name=${record.name}`
|
||||
`/models/benchmark/detail?id=${record.id}&name=${record.name}`,
|
||||
{ state: 'benchmark-details' }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -230,6 +241,7 @@ const Benchmark: React.FC = () => {
|
||||
</ConfigProvider>
|
||||
</PageBox>
|
||||
<AddBenchmarkModal
|
||||
clusterList={clusterList}
|
||||
open={openBenchmarkModalStatus.open}
|
||||
action={openBenchmarkModalStatus.action}
|
||||
title={openBenchmarkModalStatus.title}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||
import { queryBenchmarkList } from '../apis';
|
||||
import { BenchmarkListItem as ListItem } from '../config/types';
|
||||
|
||||
export const useQueryBenchmarkList = (optons?: {
|
||||
getLabel?: (item: ListItem) => string;
|
||||
getValue?: (item: ListItem) => any;
|
||||
}) => {
|
||||
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
||||
ListItem,
|
||||
Global.SearchParams
|
||||
>({
|
||||
key: 'benchmarkList',
|
||||
fetchList: queryBenchmarkList
|
||||
});
|
||||
|
||||
return {
|
||||
dataList,
|
||||
loading,
|
||||
fetchData,
|
||||
cancelRequest
|
||||
};
|
||||
};
|
||||
|
||||
export default useQueryBenchmarkList;
|
||||
Reference in New Issue
Block a user