diff --git a/react-ui/.eslintignore b/react-ui/.eslintignore index 8336e935..3bc705a6 100644 --- a/react-ui/.eslintignore +++ b/react-ui/.eslintignore @@ -5,4 +5,5 @@ public dist .umi -mock \ No newline at end of file +mock +/src/iconfont/ \ No newline at end of file diff --git a/react-ui/.eslintrc.js b/react-ui/.eslintrc.js index 564a28d2..85537dd8 100644 --- a/react-ui/.eslintrc.js +++ b/react-ui/.eslintrc.js @@ -1,10 +1,16 @@ module.exports = { - extends: [require.resolve('@umijs/lint/dist/config/eslint')], + extends: [ + require.resolve('@umijs/lint/dist/config/eslint'), + 'plugin:react/recommended', + "plugin:react-hooks/recommended" + ], globals: { page: true, REACT_APP_ENV: true, }, rules: { '@typescript-eslint/no-use-before-define': 'off', + 'react/react-in-jsx-scope': 'off', + 'react/display-name': 'off' }, }; diff --git a/react-ui/package.json b/react-ui/package.json index 1a8d7ebc..fbc014d1 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -114,6 +114,7 @@ "@umijs/max": "^4.0.66", "cross-env": "^7.0.3", "eslint": "^8.39.0", + "eslint-plugin-react-hooks": "~5.2.0", "eslint-plugin-storybook": "~0.11.2", "express": "^4.18.2", "gh-pages": "^5.0.0", diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index 26dfa334..7c026d3d 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -168,7 +168,7 @@ export const onRouteChange: RuntimeConfig['onRouteChange'] = async (e) => { } }; -export const patchRoutes: RuntimeConfig['patchRoutes'] = (e) => { +export const patchRoutes: RuntimeConfig['patchRoutes'] = () => { //console.log('patchRoutes', e); }; @@ -232,7 +232,7 @@ export const antd: RuntimeAntdConfig = (memo) => { memo.theme.components.Table = { headerBg: 'rgba(242, 244, 247, 0.36)', headerBorderRadius: 4, - rowSelectedBg: 'rgba(22, 100, 255, 0.05)', + // rowSelectedBg: 'rgba(22, 100, 255, 0.05)', 固定列时,横向滑动导致重叠 }; memo.theme.components.Tabs = { titleFontSize: 16, diff --git a/react-ui/src/components/CodeSelectorModal/index.tsx b/react-ui/src/components/CodeSelectorModal/index.tsx index c983093e..430971e6 100644 --- a/react-ui/src/components/CodeSelectorModal/index.tsx +++ b/react-ui/src/components/CodeSelectorModal/index.tsx @@ -33,23 +33,23 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { const [inputText, setInputText] = useState(undefined); useEffect(() => { + // 获取数据请求 + const getDataList = async () => { + const params = { + page: pagination.current! - 1, + size: pagination.pageSize, + code_repo_name: searchText || undefined, + }; + const [res] = await to(getCodeConfigListReq(params)); + if (res && res.data && res.data.content) { + setDataList(res.data.content); + setTotal(res.data.totalElements); + } + }; + getDataList(); }, [pagination, searchText]); - // 获取数据请求 - const getDataList = async () => { - const params = { - page: pagination.current! - 1, - size: pagination.pageSize, - code_repo_name: searchText || undefined, - }; - const [res] = await to(getCodeConfigListReq(params)); - if (res && res.data && res.data.content) { - setDataList(res.data.content); - setTotal(res.data.totalElements); - } - }; - // 搜索 const handleSearch = (value: string) => { setSearchText(value); diff --git a/react-ui/src/components/IFramePage/index.tsx b/react-ui/src/components/IFramePage/index.tsx index ef96c914..aa292d47 100644 --- a/react-ui/src/components/IFramePage/index.tsx +++ b/react-ui/src/components/IFramePage/index.tsx @@ -45,23 +45,20 @@ type IframePageProps = { function IframePage({ type, className, style }: IframePageProps) { const [iframeUrl, setIframeUrl] = useState(''); const [loading, setLoading] = useState(false); + useEffect(() => { - requestIframeUrl(); - return () => { - if (type === IframePageType.DevEnv) { - SessionStorage.removeItem(SessionStorage.editorUrlKey); + const requestIframeUrl = async () => { + setLoading(true); + const [res] = await to(getRequestAPI(type)()); + if (res && res.data) { + setIframeUrl(res.data); + } else { + setLoading(false); } }; - }, []); - const requestIframeUrl = async () => { - setLoading(true); - const [res] = await to(getRequestAPI(type)()); - if (res && res.data) { - setIframeUrl(res.data); - } else { - setLoading(false); - } - }; + + requestIframeUrl(); + }, [type]); const hideLoading = () => { setLoading(false); diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx index 182db352..f1902e5c 100644 --- a/react-ui/src/components/ParameterSelect/index.tsx +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -39,8 +39,20 @@ function ParameterSelect({ const valueText = typeof value === 'object' && value !== null ? value.value : value; useEffect(() => { + // 获取下拉数据 + const getSelectOptions = async () => { + if (!propsConfig) { + return; + } + const getOptions = propsConfig.getOptions; + const [res] = await to(getOptions()); + if (res) { + setOptions(res); + } + }; + getSelectOptions(); - }, []); + }, [propsConfig]); const handleChange = (text: string) => { if (typeof value === 'object' && value !== null) { @@ -53,18 +65,7 @@ function ParameterSelect({ } }; - // 获取下拉数据 - const getSelectOptions = async () => { - if (!propsConfig) { - return; - } - const getOptions = propsConfig.getOptions; - const [res] = await to(getOptions()); - if (res) { - setOptions(res); - } - }; - + // 只用于展示,FormInfo 组件带有 Tooltip if (display) { return ( { const resource = selectedResource; diff --git a/react-ui/src/components/ResourceSelectorModal/index.tsx b/react-ui/src/components/ResourceSelectorModal/index.tsx index 24e97a4d..bbc78db3 100644 --- a/react-ui/src/components/ResourceSelectorModal/index.tsx +++ b/react-ui/src/components/ResourceSelectorModal/index.tsx @@ -91,16 +91,7 @@ function ResourceSelectorModal({ const treeRef = useRef(null); const config = selectorTypeConfig[type]; - useEffect(() => { - setExpandedKeys([]); - setCheckedKeys([]); - setLoadedKeys([]); - setFiles([]); - setVersionPath(''); - setSearchText(''); - getTreeData(); - }, [activeTab, type]); - + // 搜索 const treeData = useMemo( () => originTreeData.filter((v) => @@ -109,19 +100,45 @@ function ResourceSelectorModal({ [originTreeData, searchText], ); - // 获取数据集\模型\镜像列表 - const getTreeData = async () => { - const isPublic = activeTab === CommonTabKeys.Private ? false : true; - const [res] = await to(config.getList(isPublic)); - if (res) { - setOriginTreeData(res); + useEffect(() => { + // 获取数据集\模型\镜像列表 + const getTreeData = async () => { + const isPublic = activeTab === CommonTabKeys.Private ? false : true; + const [res] = await to(config.getList(isPublic)); + if (res) { + setOriginTreeData(res); - // 恢复上一次的 Expand 操作 - restoreLastExpand(); - } else { - setOriginTreeData([]); - } - }; + // 恢复上一次的 Expand 操作 + setFirstLoadList(true); + } else { + setOriginTreeData([]); + } + }; + + setExpandedKeys([]); + setCheckedKeys([]); + setLoadedKeys([]); + setFiles([]); + setVersionPath(''); + setSearchText(''); + getTreeData(); + }, [activeTab, config]); + + useEffect(() => { + // 恢复上一次的 Expand 操作 + // 判断是否有 defaultExpandedKeys,如果有,设置 expandedKeys + // fisrtLoadList 标志位 + const restoreLastExpand = () => { + if (firstLoadList && Array.isArray(defaultExpandedKeys) && defaultExpandedKeys.length > 0) { + setExpandedKeys(defaultExpandedKeys); + // 延时滑动到 defaultExpandedKeys,不然不会加载 defaultExpandedKeys,不然不会加载版本 + setTimeout(() => { + treeRef.current?.scrollTo({ key: defaultExpandedKeys[0], align: 'bottom' }); + }, 100); + } + }; + restoreLastExpand(); + }, [firstLoadList, defaultExpandedKeys]); // 获取数据集\模型\镜像版本列表 const getVersions = async (parentId: string, parentNode: any) => { @@ -136,10 +153,10 @@ function ResourceSelectorModal({ setLoadedKeys((prev) => prev.concat(parentId)); } - // 恢复上一次的 Check 操作 + // 恢复上一次的 Check 操作,需要延时以便 TreeData 更新完 setTimeout(() => { restoreLastCheck(parentId, res); - }, 300); + }, 100); } else { setExpandedKeys([]); return Promise.reject(error); @@ -158,7 +175,7 @@ function ResourceSelectorModal({ } }; - // 动态加载 tree children + // 展开时,动态加载 tree children const onLoadData = ({ key, children, ...rest }: TreeDataNode) => { if (children) { return Promise.resolve(); @@ -187,42 +204,25 @@ function ResourceSelectorModal({ } }; - // 恢复上一次的 Expand 操作 - // 判断是否有 defaultExpandedKeys,如果有,设置 expandedKeys - // fisrtLoadList 标志位 - const restoreLastExpand = () => { - if (!firstLoadList && defaultExpandedKeys.length > 0) { - setTimeout(() => { - setExpandedKeys(defaultExpandedKeys); - setFirstLoadList(true); - setTimeout(() => { - treeRef.current?.scrollTo({ key: defaultExpandedKeys[0], align: 'bottom' }); - }, 100); - }, 0); - } - }; - // 恢复上一次的 Check 操作 // 判断是否有 defaultCheckedKeys,如果有,设置 checkedKeys,并且调用获取文件列表接口 // fisrtLoadVersions 标志位 const restoreLastCheck = (parentId: string, versions: TreeDataNode[]) => { - if (!firstLoadVersions && defaultCheckedKeys.length > 0) { + if (!firstLoadVersions && Array.isArray(defaultCheckedKeys) && defaultCheckedKeys.length > 0) { const last = defaultCheckedKeys[0] as string; const { id } = getIdAndVersion(last); // 判断正在打开的 id 和 defaultCheckedKeys 的 id 是否一致 if (id === parentId) { + setCheckedKeys(defaultCheckedKeys); + const parentNode = versions.find((v) => v.key === last); + getFiles(last, parentNode); + setFirstLoadVersions(true); setTimeout(() => { - setCheckedKeys(defaultCheckedKeys); - const parentNode = versions.find((v) => v.key === last); - getFiles(last, parentNode); - setFirstLoadVersions(true); - setTimeout(() => { - treeRef?.current?.scrollTo({ - key: defaultCheckedKeys[0], - align: 'bottom', - }); - }, 100); - }, 0); + treeRef?.current?.scrollTo({ + key: defaultCheckedKeys[0], + align: 'bottom', + }); + }, 100); } } }; diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index f5ef64af..59ba1d6e 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -105,6 +105,7 @@ export function useDomSize( return () => { window.removeEventListener('resize', debounceFunc); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [domRef, ...deps]); return [domRef, { width, height }] as const; @@ -136,10 +137,10 @@ export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => { * Executes the effect function when the specified condition is true. * * @param effect - The effect function to execute. - * @param deps - The dependencies for the effect. * @param when - The condition to trigger the effect. + * @param deps - The dependencies for the effect. */ -export const useEffectWhen = (effect: () => void, deps: React.DependencyList, when: boolean) => { +export const useEffectWhen = (effect: () => void, when: boolean, deps: React.DependencyList) => { const requestFns = useRef<(() => void)[]>([]); useEffect(() => { if (when) { @@ -147,6 +148,7 @@ export const useEffectWhen = (effect: () => void, deps: React.DependencyList, wh } else { requestFns.current.splice(0, 1, effect); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); useEffect(() => { @@ -185,7 +187,7 @@ export const useCheck = (list: T[]) => { } }); }, - [selected, isSingleChecked], + [isSingleChecked], ); return [ diff --git a/react-ui/src/hooks/resource.ts b/react-ui/src/hooks/resource.ts index 82a3ee78..cb4434ab 100644 --- a/react-ui/src/hooks/resource.ts +++ b/react-ui/src/hooks/resource.ts @@ -5,40 +5,39 @@ */ import { getComputingResourceReq } from '@/services/pipeline'; -import computingResourceState, { setComputingResource } from '@/state/computingResourceStore'; import { ComputingResource } from '@/types'; import { to } from '@/utils/promise'; import { type SelectProps } from 'antd'; import { useCallback, useEffect, useState } from 'react'; -import { useSnapshot } from 'umi'; + +const computingResource: ComputingResource[] = []; // 获取资源规格 export function useComputingResource() { const [resourceStandardList, setResourceStandardList] = useState([]); - const snap = useSnapshot(computingResourceState); useEffect(() => { - if (snap.computingResource.length > 0) { - setResourceStandardList(snap.computingResource as ComputingResource[]); + // 获取资源规格列表数据 + const getComputingResource = async () => { + const params = { + page: 0, + size: 1000, + resource_type: '', + }; + const [res] = await to(getComputingResourceReq(params)); + if (res && res.data && res.data.content) { + setResourceStandardList(res.data.content); + computingResource.splice(0, computingResource.length, ...res.data.content); + } + }; + + if (computingResource.length > 0) { + setResourceStandardList(computingResource); } else { getComputingResource(); } }, []); - // 获取资源规格列表数据 - const getComputingResource = useCallback(async () => { - const params = { - page: 0, - size: 1000, - resource_type: '', - }; - const [res] = await to(getComputingResourceReq(params)); - if (res && res.data && res.data.content) { - setResourceStandardList(res.data.content); - setComputingResource(res.data.content); - } - }, []); - // 过滤资源规格 const filterResourceStandard: SelectProps['filterOption'] = useCallback((input: string, option?: ComputingResource) => { diff --git a/react-ui/src/hooks/sessionStorage.ts b/react-ui/src/hooks/sessionStorage.ts deleted file mode 100644 index 8cf3c921..00000000 --- a/react-ui/src/hooks/sessionStorage.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * @Author: 赵伟 - * @Date: 2024-11-06 14:53:37 - * @Description: SessionStorage hook - */ - -import SessionStorage from '@/utils/sessionStorage'; -import { useEffect, useState } from 'react'; - -// 读取缓存数据,组件卸载时清除缓存 -export function useSessionStorage(key: string, isObject: boolean, initialValue: T) { - const [storage, setStorage] = useState(initialValue); - - useEffect(() => { - const res = SessionStorage.getItem(key, isObject); - if (res) { - setStorage(res); - } - return () => { - SessionStorage.removeItem(key); - }; - }, []); - - return [storage]; -} diff --git a/react-ui/src/pages/AutoML/Create/index.tsx b/react-ui/src/pages/AutoML/Create/index.tsx index ec016c3c..b5ceae7c 100644 --- a/react-ui/src/pages/AutoML/Create/index.tsx +++ b/react-ui/src/pages/AutoML/Create/index.tsx @@ -29,60 +29,60 @@ function CreateAutoML() { const isCopy = pathname.includes('copy'); useEffect(() => { + // 获取服务详情 + const getAutoMLInfo = async (id: number) => { + const [res] = await to(getAutoMLInfoReq({ id })); + if (res && res.data) { + const autoMLInfo: AutoMLData = res.data; + const { + include_classifier: include_classifier_str, + include_feature_preprocessor: include_feature_preprocessor_str, + include_regressor: include_regressor_str, + exclude_classifier: exclude_classifier_str, + 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 + ?.split(',') + .filter(Boolean); + const include_regressor = include_regressor_str?.split(',').filter(Boolean); + const exclude_classifier = exclude_classifier_str?.split(',').filter(Boolean); + const exclude_feature_preprocessor = exclude_feature_preprocessor_str + ?.split(',') + .filter(Boolean); + const exclude_regressor = exclude_regressor_str?.split(',').filter(Boolean); + const metricsObj = safeInvoke(parseJsonText)(metrics_str) ?? {}; + const metrics = Object.entries(metricsObj).map(([key, value]) => ({ + name: key, + value, + })); + const ml_name = isCopy ? `${ml_name_str}-copy` : ml_name_str; + + const formData = { + ...rest, + include_classifier, + include_feature_preprocessor, + include_regressor, + exclude_classifier, + exclude_feature_preprocessor, + exclude_regressor, + metrics, + ml_name, + }; + + form.setFieldsValue(formData); + } + }; + // 编辑,复制 if (id && !Number.isNaN(id)) { getAutoMLInfo(id); } - }, [id]); - - // 获取服务详情 - const getAutoMLInfo = async (id: number) => { - const [res] = await to(getAutoMLInfoReq({ id })); - if (res && res.data) { - const autoMLInfo: AutoMLData = res.data; - const { - include_classifier: include_classifier_str, - include_feature_preprocessor: include_feature_preprocessor_str, - include_regressor: include_regressor_str, - exclude_classifier: exclude_classifier_str, - 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 - ?.split(',') - .filter(Boolean); - const include_regressor = include_regressor_str?.split(',').filter(Boolean); - const exclude_classifier = exclude_classifier_str?.split(',').filter(Boolean); - const exclude_feature_preprocessor = exclude_feature_preprocessor_str - ?.split(',') - .filter(Boolean); - const exclude_regressor = exclude_regressor_str?.split(',').filter(Boolean); - const metricsObj = safeInvoke(parseJsonText)(metrics_str) ?? {}; - const metrics = Object.entries(metricsObj).map(([key, value]) => ({ - name: key, - value, - })); - const ml_name = isCopy ? `${ml_name_str}-copy` : ml_name_str; - - const formData = { - ...rest, - include_classifier, - include_feature_preprocessor, - include_regressor, - exclude_classifier, - exclude_feature_preprocessor, - exclude_regressor, - metrics, - ml_name, - }; - - form.setFieldsValue(formData); - } - }; + }, [id, form, isCopy]); // 创建、更新、复制实验 const createExperiment = async (formData: FormData) => { diff --git a/react-ui/src/pages/AutoML/Info/index.tsx b/react-ui/src/pages/AutoML/Info/index.tsx index 0d0ec460..83f7dea0 100644 --- a/react-ui/src/pages/AutoML/Info/index.tsx +++ b/react-ui/src/pages/AutoML/Info/index.tsx @@ -19,18 +19,18 @@ function AutoMLInfo() { const [autoMLInfo, setAutoMLInfo] = useState(undefined); useEffect(() => { + // 获取自动机器学习详情 + const getAutoMLInfo = async () => { + const [res] = await to(getAutoMLInfoReq({ id: autoMLId })); + if (res && res.data) { + setAutoMLInfo(res.data); + } + }; + if (autoMLId) { getAutoMLInfo(); } - }, []); - - // 获取自动机器学习详情 - const getAutoMLInfo = async () => { - const [res] = await to(getAutoMLInfoReq({ id: autoMLId })); - if (res && res.data) { - setAutoMLInfo(res.data); - } - }; + }, [autoMLId]); return (
diff --git a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx index fa694b27..09d0cd6e 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx @@ -25,36 +25,36 @@ type TableData = { function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps) { const [tableData, setTableData] = useState([]); useEffect(() => { + // 获取实验运行历史记录 + const getHistoryFile = async () => { + const [res] = await to(getFileReq(fileUrl)); + if (res) { + const data: any[] = res.data; + const list: TableData[] = data.map((item) => { + return { + id: item[0]?.[0], + accuracy: item[1]?.[5]?.accuracy, + duration: item[1]?.[5]?.duration, + train_loss: item[1]?.[5]?.train_loss, + status: item[1]?.[2]?.['__enum__']?.split('.')?.[1], + }; + }); + list.forEach((item) => { + if (!item.id) return; + const config = (res as any).configs?.[item.id]; + item.feature = config?.['feature_preprocessor:__choice__']; + item.althorithm = isClassification + ? config?.['classifier:__choice__'] + : config?.['regressor:__choice__']; + }); + setTableData(list); + } + }; + if (fileUrl) { getHistoryFile(); } - }, [fileUrl]); - - // 获取实验运行历史记录 - const getHistoryFile = async () => { - const [res] = await to(getFileReq(fileUrl)); - if (res) { - const data: any[] = res.data; - const list: TableData[] = data.map((item) => { - return { - id: item[0]?.[0], - accuracy: item[1]?.[5]?.accuracy, - duration: item[1]?.[5]?.duration, - train_loss: item[1]?.[5]?.train_loss, - status: item[1]?.[2]?.['__enum__']?.split('.')?.[1], - }; - }); - list.forEach((item) => { - if (!item.id) return; - const config = (res as any).configs?.[item.id]; - item.feature = config?.['feature_preprocessor:__choice__']; - item.althorithm = isClassification - ? config?.['classifier:__choice__'] - : config?.['regressor:__choice__']; - }); - setTableData(list); - } - }; + }, [fileUrl, isClassification]); const columns: TableProps['columns'] = [ { diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx index 9c8ea687..aded5f2a 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx @@ -53,7 +53,7 @@ function ExperimentInstanceComponent({ if (allIntanceIds.length === 0) { setSelectedIns([]); } - }, [experimentInsList]); + }, [allIntanceIds, setSelectedIns]); // 删除实验实例确认 const handleRemove = (instance: ExperimentInstance) => { diff --git a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx index bcc85a2f..b4e7f24b 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx @@ -28,7 +28,7 @@ import { } from 'antd'; import { type SearchProps } from 'antd/es/input'; import classNames from 'classnames'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import ExperimentInstance from '../ExperimentInstance'; import { ExperimentListType, experimentListConfig } from './config'; import styles from './index.less'; @@ -58,12 +58,8 @@ function ExperimentList({ type }: ExperimentListProps) { ); const config = experimentListConfig[type]; - useEffect(() => { - getAutoMLList(); - }, [pagination, searchText]); - // 获取自主机器学习或超参数自动优化列表 - const getAutoMLList = async () => { + const getAutoMLList = useCallback(async () => { const params: Record = { page: pagination.current! - 1, size: pagination.pageSize, @@ -76,7 +72,11 @@ function ExperimentList({ type }: ExperimentListProps) { setTableData(content); setTotal(totalElements); } - }; + }, [pagination, searchText, config]); + + useEffect(() => { + getAutoMLList(); + }, [getAutoMLList]); // 搜索 const onSearch: SearchProps['onSearch'] = (value) => { diff --git a/react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx index a826155d..8680bf60 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentResult/index.tsx @@ -22,19 +22,19 @@ function ExperimentResult({ fileUrl, imageUrl, modelPath }: ExperimentResultProp }, [imageUrl]); useEffect(() => { + // 获取实验运行历史记录 + const getResultFile = async () => { + const [res] = await to(getFileReq(fileUrl)); + if (res) { + setResult(res as any as string); + } + }; + if (fileUrl) { getResultFile(); } }, [fileUrl]); - // 获取实验运行历史记录 - const getResultFile = async () => { - const [res] = await to(getFileReq(fileUrl)); - if (res) { - setResult(res as any as string); - } - }; - return (
diff --git a/react-ui/src/pages/CodeConfig/List/index.tsx b/react-ui/src/pages/CodeConfig/List/index.tsx index 0c484e54..3f567465 100644 --- a/react-ui/src/pages/CodeConfig/List/index.tsx +++ b/react-ui/src/pages/CodeConfig/List/index.tsx @@ -13,7 +13,7 @@ import { openAntdModal } from '@/utils/modal'; import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; import { App, Button, Input, Pagination, PaginationProps } from 'antd'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import AddCodeConfigModal, { OperationType } from '../components/AddCodeConfigModal'; import CodeConfigItem from '../components/CodeConfigItem'; import styles from './index.less'; @@ -50,12 +50,8 @@ function CodeConfigList() { const [inputText, setInputText] = useState(undefined); const { message } = App.useApp(); - useEffect(() => { - getDataList(); - }, [pagination, searchText]); - // 获取数据请求 - const getDataList = async () => { + const getDataList = useCallback(async () => { const params = { page: pagination.current! - 1, size: pagination.pageSize, @@ -69,7 +65,11 @@ function CodeConfigList() { setDataList([]); setTotal(0); } - }; + }, [pagination, searchText]); + + useEffect(() => { + getDataList(); + }, [getDataList]); // 删除请求 const deleteRecord = async (id: number) => { diff --git a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx index c0bfdb33..c74a3cc8 100644 --- a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx @@ -18,7 +18,7 @@ import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; import { useParams, useSearchParams } from '@umijs/max'; import { App, Button, Flex, Select, Tabs } from 'antd'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import AddVersionModal from '../AddVersionModal'; import ResourceIntro from '../ResourceIntro'; import ResourceVersion from '../ResourceVersion'; @@ -45,7 +45,7 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { // 模型演化传入的 tab const defaultTab = searchParams.get('tab') || ResourceInfoTabKeys.Introduction; // 模型演化传入的版本 - let versionParam = searchParams.get('version'); + const versionParam = searchParams.get('version'); const name = searchParams.get('name') || ''; const owner = searchParams.get('owner') || ''; const identifier = searchParams.get('identifier') || ''; @@ -57,63 +57,60 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { const typeName = config.name; // 数据集/模型 const { message } = App.useApp(); - useEffect(() => { - getVersionList(); - }, [resourceId, owner, identifier]); - - useEffect(() => { - if (version) { - getResourceDetail({ - id: resourceId, - owner, - name, - identifier, - version, - is_public: is_public, - }); - } - }, [version]); - // 获取详情 - const getResourceDetail = async (params: { - owner: string; - name: string; - id: number; - identifier: string; - version?: string; - is_public: boolean; - }) => { + const getResourceDetail = useCallback(async () => { + const params = { + id: resourceId, + owner, + name, + identifier, + version, + is_public, + }; const request = config.getInfo; const [res] = await to(request(params)); if (res && res.data) { setInfo(res.data); } - }; + }, [config, resourceId, owner, name, identifier, version, is_public]); // 获取版本列表 - const getVersionList = async () => { - const request = config.getVersions; - const [res] = await to( - request({ - owner, - identifier, - }), - ); - if (res && res.data && res.data.length > 0) { - setVersionList(res.data); - if ( - versionParam && - res.data.find((item: ResourceVersionData) => item.name === versionParam) - ) { - setVersion(versionParam); - versionParam = null; + const getVersionList = useCallback( + async (refresh: boolean) => { + const request = config.getVersions; + const [res] = await to( + request({ + owner, + identifier, + }), + ); + if (res && res.data && res.data.length > 0) { + setVersionList(res.data); + if ( + !refresh && + versionParam && + res.data.find((item: ResourceVersionData) => item.name === versionParam) + ) { + setVersion(versionParam); + } else { + setVersion(res.data[0].name); + } } else { - setVersion(res.data[0].name); + setVersion(undefined); } - } else { - setVersion(undefined); + }, + [config, owner, identifier, versionParam], + ); + + useEffect(() => { + if (version) { + getResourceDetail(); } - }; + }, [version, getResourceDetail]); + + useEffect(() => { + getVersionList(false); + }, [getVersionList]); // 新建版本 const showModal = () => { @@ -125,7 +122,7 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { identifier: info.identifier, is_public: is_public, onOk: () => { - getVersionList(); + getVersionList(true); close(); }, }); @@ -172,12 +169,12 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { const [res] = await to(request(params)); if (res) { message.success('删除成功'); - getVersionList(); + getVersionList(true); } }; // 处理删除 - const hanldeDelete = () => { + const handleDelete = () => { modalConfirm({ title: '删除后,该版本将不可恢复', content: '是否确认删除?', @@ -268,7 +265,7 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => {