diff --git a/react-ui/src/pages/AutoML/Create/index.tsx b/react-ui/src/pages/AutoML/Create/index.tsx
index 743d8377..26e1866c 100644
--- a/react-ui/src/pages/AutoML/Create/index.tsx
+++ b/react-ui/src/pages/AutoML/Create/index.tsx
@@ -10,6 +10,7 @@ import { addAutoMLReq, getDatasetInfoReq, updateAutoMLReq } from '@/services/aut
import { parseJsonText, trimCharacter } from '@/utils';
import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise';
+import SessionStorage from '@/utils/sessionStorage';
import { useNavigate, useParams } from '@umijs/max';
import { App, Button, Form } from 'antd';
import { omit } from 'lodash';
@@ -29,13 +30,25 @@ function CreateAutoML() {
const id = safeInvoke(Number)(params.id);
useEffect(() => {
- if (id) {
- getAutoMLInfo();
+ // 复制和新建
+ const recordId = SessionStorage.getItem(SessionStorage.autoMLRecordIDKey);
+ if (recordId && !Number.isNaN(Number(recordId))) {
+ getAutoMLInfo(Number(recordId), true);
+ }
+ return () => {
+ SessionStorage.removeItem(SessionStorage.autoMLRecordIDKey);
+ };
+ }, []);
+
+ useEffect(() => {
+ // 编辑
+ if (id && !Number.isNaN(id)) {
+ getAutoMLInfo(id, false);
}
}, [id]);
// 获取服务详情
- const getAutoMLInfo = async () => {
+ const getAutoMLInfo = async (id: number, isCopy = false) => {
const [res] = await to(getDatasetInfoReq({ id }));
if (res && res.data) {
const autoMLInfo: AutoMLData = res.data;
@@ -47,6 +60,8 @@ function CreateAutoML() {
exclude_feature_preprocessor: exclude_feature_preprocessor_str,
exclude_regressor: exclude_regressor_str,
metrics: metrics_str,
+ ml_name: ml_name_str,
+ ...rest
} = autoMLInfo;
const include_classifier = include_classifier_str?.split(',').filter(Boolean);
const include_feature_preprocessor = include_feature_preprocessor_str
@@ -63,9 +78,10 @@ function CreateAutoML() {
name: key,
value,
}));
+ const ml_name = isCopy ? `${ml_name_str}-copy` : ml_name_str;
const formData = {
- ...autoMLInfo,
+ ...rest,
include_classifier,
include_feature_preprocessor,
include_regressor,
@@ -73,6 +89,7 @@ function CreateAutoML() {
exclude_feature_preprocessor,
exclude_regressor,
metrics,
+ ml_name,
};
form.setFieldsValue(formData);
@@ -135,7 +152,7 @@ function CreateAutoML() {
let buttonText = '新建';
let title = '新增实验';
if (id) {
- title = '更新实验';
+ title = '编辑实验';
buttonText = '更新';
}
diff --git a/react-ui/src/pages/AutoML/List/index.tsx b/react-ui/src/pages/AutoML/List/index.tsx
index 9ef6eda6..be76e591 100644
--- a/react-ui/src/pages/AutoML/List/index.tsx
+++ b/react-ui/src/pages/AutoML/List/index.tsx
@@ -9,6 +9,7 @@ import { useCacheState } from '@/hooks/pageCacheState';
import { deleteAutoMLReq, getAutoMLListReq } from '@/services/autoML';
import themes from '@/styles/theme.less';
import { to } from '@/utils/promise';
+import SessionStorage from '@/utils/sessionStorage';
import tableCellRender, { TableCellValueType } from '@/utils/table';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
@@ -90,7 +91,7 @@ function AutoMLList() {
// 处理删除
const handleAutoMLDelete = (record: AutoMLData) => {
modalConfirm({
- title: '删除后,该服务将不可恢复',
+ title: '删除后,该实验将不可恢复',
content: '是否确认删除?',
onOk: () => {
deleteService(record);
@@ -99,15 +100,21 @@ function AutoMLList() {
};
// 创建、编辑
- const createService = (record?: AutoMLData) => {
+ const createService = (record?: AutoMLData, isCopy: boolean = false) => {
setCacheState({
pagination,
searchText,
});
if (record) {
- navigate(`/pipeline/autoML/edit/${record.id}`);
+ if (isCopy) {
+ SessionStorage.setItem(SessionStorage.autoMLRecordIDKey, record.id, false);
+ navigate(`/pipeline/autoML/create`);
+ } else {
+ navigate(`/pipeline/autoML/edit/${record.id}`);
+ }
} else {
+ SessionStorage.setItem(SessionStorage.autoMLRecordIDKey, '', false);
navigate(`/pipeline/autoML/create`);
}
};
@@ -139,7 +146,7 @@ function AutoMLList() {
title: '序号',
dataIndex: 'index',
key: 'index',
- width: '20%',
+ width: 80,
render: tableCellRender(false, TableCellValueType.Index, {
page: pagination.current! - 1,
pageSize: pagination.pageSize!,
@@ -166,7 +173,7 @@ function AutoMLList() {
title: '状态',
dataIndex: 'run_state',
key: 'run_state',
- width: '20%',
+ width: 100,
render: RunStatusCell,
},
{
@@ -207,7 +214,7 @@ function AutoMLList() {
size="small"
key="edit"
icon={}
- onClick={() => createService(record)}
+ onClick={() => createService(record, false)}
>
编辑
@@ -216,17 +223,11 @@ function AutoMLList() {
size="small"
key="copy"
icon={}
- onClick={() => toDetail(record)}
+ onClick={() => createService(record, true)}
>
复制
- }
- onClick={() => toDetail(record)}
- >
+ }>
停止
-
+ form.resetFields(['metrics'])}>
分类
回归
diff --git a/react-ui/src/pages/AutoML/components/CreateForm/TrialConfig.tsx b/react-ui/src/pages/AutoML/components/CreateForm/TrialConfig.tsx
index d65b62e8..9201009a 100644
--- a/react-ui/src/pages/AutoML/components/CreateForm/TrialConfig.tsx
+++ b/react-ui/src/pages/AutoML/components/CreateForm/TrialConfig.tsx
@@ -8,6 +8,14 @@ import styles from './index.less';
function TrialConfig() {
const form = Form.useFormInstance();
const task_type = Form.useWatch('task_type', form);
+ const metrics = Form.useWatch('metrics', form) || [];
+ const selectedMetrics = metrics
+ .map((item: { name: string; value: number }) => item?.name)
+ .filter(Boolean);
+ const allMetricsOptions =
+ task_type === AutoMLTaskType.Classification ? classificationMetrics : regressionMetrics;
+ const metricsOptions = allMetricsOptions.filter((item) => !selectedMetrics.includes(item.label));
+
return (
<>
-
@@ -30,9 +37,9 @@ function TrialConfig() {
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }, index) => (
-
+
- :
+ :
-
+
)}
-
+
))}
{fields.length === 0 && (
diff --git a/react-ui/src/pages/AutoML/components/CreateForm/index.less b/react-ui/src/pages/AutoML/components/CreateForm/index.less
index 8e8414a5..5ee9aacc 100644
--- a/react-ui/src/pages/AutoML/components/CreateForm/index.less
+++ b/react-ui/src/pages/AutoML/components/CreateForm/index.less
@@ -6,136 +6,136 @@
}
}
-.command {
- width: 83.33%;
- margin-bottom: 20px;
- border: 1px solid rgba(234, 234, 234, 0.8);
- border-radius: 4px;
- &__header {
- height: 50px;
- padding-left: 8px;
- color: @text-color;
- font-size: @font-size;
- background: #f8f8f9;
- border-radius: 4px 4px 0px 0px;
-
- &__name {
- flex: none;
- width: 100px;
- }
- &__command {
- flex: 1;
- margin-right: 15px;
- }
-
- &__operation {
- flex: none;
- width: 100px;
- }
- }
- &__body {
- padding: 8px;
- border-bottom: 1px solid rgba(234, 234, 234, 0.8);
-
- &:last-child {
- border-bottom: none;
- }
-
- &__name {
- flex: none;
- width: 100px;
- }
-
- &__command {
- flex: 1;
- margin-right: 15px;
- margin-bottom: 0 !important;
- }
-
- &__operation {
- flex: none;
- width: 100px;
- }
- }
-
- &__add {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 15px 0;
- }
-}
-
-.hyper-parameter {
- width: 83.33%;
- margin-bottom: 20px;
- border: 1px solid rgba(234, 234, 234, 0.8);
- border-radius: 4px;
- &__header {
- height: 50px;
- padding-left: 8px;
- color: @text-color;
- font-size: @font-size;
- background: #f8f8f9;
- border-radius: 4px 4px 0px 0px;
-
- &__name,
- &__type,
- &__space {
- flex: 1;
- margin-right: 15px;
- }
-
- &__operation {
- flex: none;
- width: 100px;
- }
- }
- &__body {
- padding: 8px;
- border-bottom: 1px solid rgba(234, 234, 234, 0.8);
-
- &:last-child {
- border-bottom: none;
- }
-
- &__name,
- &__type,
- &__space {
- flex: 1;
- margin-right: 15px;
- margin-bottom: 0 !important;
- }
-
- &__operation {
- flex: none;
- width: 100px;
- }
- }
-
- &__add {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 15px 0;
- }
-}
-
-.trial-metrics {
- width: calc(41.67% - 6px);
- margin-bottom: 20px;
- padding: 0 20px;
- border: 1px dashed #e0e0e0;
- border-radius: 8px;
-}
-
-.upload-tip {
- margin-top: 5px;
- color: @text-color-secondary;
- font-size: 14px;
-}
-
-.upload-button {
- height: 46px;
- font-size: 15px;
-}
+// .command {
+// width: 83.33%;
+// margin-bottom: 20px;
+// border: 1px solid rgba(234, 234, 234, 0.8);
+// border-radius: 4px;
+// &__header {
+// height: 50px;
+// padding-left: 8px;
+// color: @text-color;
+// font-size: @font-size;
+// background: #f8f8f9;
+// border-radius: 4px 4px 0px 0px;
+
+// &__name {
+// flex: none;
+// width: 100px;
+// }
+// &__command {
+// flex: 1;
+// margin-right: 15px;
+// }
+
+// &__operation {
+// flex: none;
+// width: 100px;
+// }
+// }
+// &__body {
+// padding: 8px;
+// border-bottom: 1px solid rgba(234, 234, 234, 0.8);
+
+// &:last-child {
+// border-bottom: none;
+// }
+
+// &__name {
+// flex: none;
+// width: 100px;
+// }
+
+// &__command {
+// flex: 1;
+// margin-right: 15px;
+// margin-bottom: 0 !important;
+// }
+
+// &__operation {
+// flex: none;
+// width: 100px;
+// }
+// }
+
+// &__add {
+// display: flex;
+// align-items: center;
+// justify-content: center;
+// padding: 15px 0;
+// }
+// }
+
+// .hyper-parameter {
+// width: 83.33%;
+// margin-bottom: 20px;
+// border: 1px solid rgba(234, 234, 234, 0.8);
+// border-radius: 4px;
+// &__header {
+// height: 50px;
+// padding-left: 8px;
+// color: @text-color;
+// font-size: @font-size;
+// background: #f8f8f9;
+// border-radius: 4px 4px 0px 0px;
+
+// &__name,
+// &__type,
+// &__space {
+// flex: 1;
+// margin-right: 15px;
+// }
+
+// &__operation {
+// flex: none;
+// width: 100px;
+// }
+// }
+// &__body {
+// padding: 8px;
+// border-bottom: 1px solid rgba(234, 234, 234, 0.8);
+
+// &:last-child {
+// border-bottom: none;
+// }
+
+// &__name,
+// &__type,
+// &__space {
+// flex: 1;
+// margin-right: 15px;
+// margin-bottom: 0 !important;
+// }
+
+// &__operation {
+// flex: none;
+// width: 100px;
+// }
+// }
+
+// &__add {
+// display: flex;
+// align-items: center;
+// justify-content: center;
+// padding: 15px 0;
+// }
+// }
+
+// .trial-metrics {
+// width: calc(41.67% - 6px);
+// margin-bottom: 20px;
+// padding: 0 20px;
+// border: 1px dashed #e0e0e0;
+// border-radius: 8px;
+// }
+
+// .upload-tip {
+// margin-top: 5px;
+// color: @text-color-secondary;
+// font-size: 14px;
+// }
+
+// .upload-button {
+// height: 46px;
+// font-size: 15px;
+// }
diff --git a/react-ui/src/pages/AutoML/components/ExecuteScheduleCell/index.tsx b/react-ui/src/pages/AutoML/components/ExecuteScheduleCell/index.tsx
index b1b9ae29..c2af2074 100644
--- a/react-ui/src/pages/AutoML/components/ExecuteScheduleCell/index.tsx
+++ b/react-ui/src/pages/AutoML/components/ExecuteScheduleCell/index.tsx
@@ -6,18 +6,19 @@
import styles from './index.less';
-function ExecuteScheduleCell(status?: any) {
+function ExecuteScheduleCell(progress?: number) {
+ const width = (progress || 0) * 100 + '%';
return (
);
}
diff --git a/react-ui/src/pages/AutoML/types.ts b/react-ui/src/pages/AutoML/types.ts
index 59496c64..bd61f941 100644
--- a/react-ui/src/pages/AutoML/types.ts
+++ b/react-ui/src/pages/AutoML/types.ts
@@ -51,4 +51,7 @@ export type AutoMLData = {
exclude_feature_preprocessor?: string;
exclude_regressor?: string;
dataset?: string;
-};
+} & Omit<
+ FormData,
+ 'metrics|dataset|include_classifier|include_feature_preprocessor|include_regressor|exclude_classifier|exclude_feature_preprocessor|exclude_regressor'
+>;
diff --git a/react-ui/src/utils/sessionStorage.ts b/react-ui/src/utils/sessionStorage.ts
index 8ffa8836..b71a35fd 100644
--- a/react-ui/src/utils/sessionStorage.ts
+++ b/react-ui/src/utils/sessionStorage.ts
@@ -11,6 +11,8 @@ export default class SessionStorage {
static readonly editorUrlKey = 'editor-url';
// 客户端信息
static readonly clientInfoKey = 'client-info';
+ // 自动机器学习记录ID
+ static readonly autoMLRecordIDKey = 'auto-ml-record-id';
static getItem(key: string, isObject: boolean = false) {
const jsonStr = sessionStorage.getItem(key);