| @@ -22,6 +22,7 @@ export { requestConfig as request } from './requestConfig'; | |||
| // const isDev = process.env.NODE_ENV === 'development'; | |||
| import { type GlobalInitialState } from '@/types'; | |||
| import { menuItemRender } from '@/utils/menuRender'; | |||
| import ErrorBoundary from './components/ErrorBoundary'; | |||
| import { gotoLoginPage } from './utils/ui'; | |||
| /** | |||
| @@ -65,6 +66,7 @@ export async function getInitialState(): Promise<GlobalInitialState> { | |||
| // ProLayout 支持的api https://procomponents.ant.design/components/layout | |||
| export const layout: RuntimeConfig['layout'] = ({ initialState }) => { | |||
| return { | |||
| ErrorBoundary: ErrorBoundary, | |||
| rightContentRender: false, | |||
| waterMarkProps: { | |||
| // content: initialState?.currentUser?.nickName, | |||
| @@ -0,0 +1,78 @@ | |||
| import KFEmpty, { EmptyType } from '@/components/KFEmpty'; | |||
| import { Button } from 'antd'; | |||
| import { Component, ReactNode } from 'react'; | |||
| interface ErrorBoundaryProps { | |||
| children: ReactNode; | |||
| fallback?: ReactNode; // Optional fallback UI to show in case of error | |||
| } | |||
| interface ErrorBoundaryState { | |||
| hasError: boolean; | |||
| error: Error | null; | |||
| } | |||
| class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { | |||
| constructor(props: ErrorBoundaryProps) { | |||
| super(props); | |||
| this.state = { | |||
| hasError: false, | |||
| error: null, | |||
| }; | |||
| } | |||
| static getDerivedStateFromError(error: Error): ErrorBoundaryState { | |||
| // Update state so the next render shows the fallback UI | |||
| return { hasError: true, error }; | |||
| } | |||
| // componentDidCatch(error: Error, errorInfo: ErrorInfo) { | |||
| // // You can log the error to an error reporting service here | |||
| // console.error('Error caught by ErrorBoundary:', error.message, errorInfo.componentStack); | |||
| // } | |||
| render() { | |||
| if (this.state.hasError) { | |||
| return this.props.fallback || <ErrorBoundaryFallback error={this.state.error} />; | |||
| } | |||
| return this.props.children; | |||
| } | |||
| } | |||
| function ErrorBoundaryFallback({ error }: { error: Error | null }) { | |||
| const message = error && error instanceof Error ? error.message : 'Unknown error'; | |||
| const errorMsg = | |||
| process.env.NODE_ENV === 'development' ? message : '非常抱歉,程序运行错误,\n我们会尽快修复。'; | |||
| return ( | |||
| <KFEmpty | |||
| style={{ height: '100vh' }} | |||
| type={EmptyType.NotFound} | |||
| title="出错了" | |||
| content={errorMsg} | |||
| footer={() => { | |||
| return ( | |||
| <> | |||
| <Button | |||
| type="default" | |||
| onClick={() => { | |||
| window.history.pushState({}, '', '/'); | |||
| window.location.reload(); | |||
| }} | |||
| > | |||
| 返回首页 | |||
| </Button> | |||
| <Button | |||
| type="primary" | |||
| style={{ marginLeft: 20 }} | |||
| onClick={() => window.location.reload()} | |||
| > | |||
| 刷新 | |||
| </Button> | |||
| </> | |||
| ); | |||
| }} | |||
| ></KFEmpty> | |||
| ); | |||
| } | |||
| export default ErrorBoundary; | |||
| @@ -18,6 +18,7 @@ | |||
| } | |||
| &__content { | |||
| max-width: 50%; | |||
| margin-top: 15px; | |||
| color: @text-color-secondary; | |||
| font-size: 15px; | |||
| @@ -37,7 +37,7 @@ function KFEmpty({ | |||
| type, | |||
| title, | |||
| content, | |||
| hasFooter = false, | |||
| hasFooter = true, | |||
| footer, | |||
| buttonTitle = '刷新', | |||
| onRefresh, | |||
| @@ -1,146 +1,159 @@ | |||
| import BasicInfo, { BasicInfoData } from '@/components/BasicInfo'; | |||
| import SubAreaTitle from '@/components/SubAreaTitle'; | |||
| import { ResourceData, ResourceType } from '@/pages/Dataset/config'; | |||
| import { DatasetData, ModelData, ResourceType } from '@/pages/Dataset/config'; | |||
| import styles from './index.less'; | |||
| type ResourceIntroProps = { | |||
| resourceType: ResourceType; | |||
| info: ResourceData; | |||
| info: DatasetData | ModelData; | |||
| }; | |||
| const formatArray = (arr?: string[]) => { | |||
| // const formatArray = (arr?: ResourceData[]) => { | |||
| // if (!arr || arr.length === 0) { | |||
| // return '--'; | |||
| // } | |||
| // return arr.map((item) => item.name).join('\n'); | |||
| // }; | |||
| const formatDataset = (arr?: DatasetData[]) => { | |||
| if (!arr || arr.length === 0) { | |||
| return '--'; | |||
| return undefined; | |||
| } | |||
| return arr.join('\n'); | |||
| return arr.map((item) => item.name).join('\n'); | |||
| }; | |||
| const formatMap = (map?: Record<string, string>) => { | |||
| if (!map || Object.keys(map).length === 0) { | |||
| return '--'; | |||
| return undefined; | |||
| } | |||
| return Object.entries(map) | |||
| .map(([key, value]) => `${key} = ${value}`) | |||
| .join('\n'); | |||
| }; | |||
| function ResourceIntro({ resourceType, info }: ResourceIntroProps) { | |||
| const datasetDatas: BasicInfoData[] = [ | |||
| { | |||
| label: '数据集名称', | |||
| value: info.name, | |||
| }, | |||
| { | |||
| label: '版本', | |||
| value: info.version, | |||
| }, | |||
| { | |||
| label: '创建人', | |||
| value: info.create_by, | |||
| }, | |||
| { | |||
| label: '更新时间', | |||
| value: info.update_time, | |||
| }, | |||
| { | |||
| label: '数据来源', | |||
| value: info.dataset_source, | |||
| }, | |||
| { | |||
| label: '处理代码', | |||
| value: info.processing_code, | |||
| }, | |||
| { | |||
| label: '数据集分类', | |||
| value: info.data_type, | |||
| }, | |||
| { | |||
| label: '研究方向', | |||
| value: info.data_tag, | |||
| }, | |||
| { | |||
| label: '数据集描述', | |||
| value: info.description, | |||
| }, | |||
| { | |||
| label: '版本描述', | |||
| value: info.version_desc, | |||
| }, | |||
| ]; | |||
| const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ | |||
| { | |||
| label: '数据集名称', | |||
| value: data.name, | |||
| }, | |||
| { | |||
| label: '版本', | |||
| value: data.version, | |||
| }, | |||
| { | |||
| label: '创建人', | |||
| value: data.create_by, | |||
| }, | |||
| { | |||
| label: '更新时间', | |||
| value: data.update_time, | |||
| }, | |||
| { | |||
| label: '数据来源', | |||
| value: data.dataset_source, | |||
| }, | |||
| { | |||
| label: '处理代码', | |||
| value: data.processing_code, | |||
| }, | |||
| { | |||
| label: '数据集分类', | |||
| value: data.data_type, | |||
| }, | |||
| { | |||
| label: '研究方向', | |||
| value: data.data_tag, | |||
| }, | |||
| { | |||
| label: '数据集描述', | |||
| value: data.description, | |||
| }, | |||
| { | |||
| label: '版本描述', | |||
| value: data.version_desc, | |||
| }, | |||
| ]; | |||
| const modelDatas: BasicInfoData[] = [ | |||
| { | |||
| label: '模型名称', | |||
| value: info.name, | |||
| }, | |||
| { | |||
| label: '版本', | |||
| value: info.version, | |||
| }, | |||
| { | |||
| label: '创建人', | |||
| value: info.create_by, | |||
| }, | |||
| { | |||
| label: '更新时间', | |||
| value: info.update_time, | |||
| }, | |||
| { | |||
| label: '训练镜像', | |||
| value: info.image, | |||
| }, | |||
| { | |||
| label: '训练代码', | |||
| value: info.code, | |||
| }, | |||
| { | |||
| label: '训练数据集', | |||
| value: info.train_datasets, | |||
| format: formatArray, | |||
| }, | |||
| { | |||
| label: '测试数据集', | |||
| value: info.test_datasets, | |||
| format: formatArray, | |||
| }, | |||
| { | |||
| label: '参数', | |||
| value: info.params, | |||
| format: formatMap, | |||
| }, | |||
| { | |||
| label: '指标', | |||
| value: info.metrics, | |||
| format: formatMap, | |||
| }, | |||
| { | |||
| label: '训练任务', | |||
| value: info.train_task, | |||
| }, | |||
| { | |||
| label: '模型来源', | |||
| value: info.model_source, | |||
| }, | |||
| { | |||
| label: '模型框架', | |||
| value: info.model_type, | |||
| }, | |||
| { | |||
| label: '模型能力', | |||
| value: info.model_tag, | |||
| }, | |||
| { | |||
| label: '模型描述', | |||
| value: info.description, | |||
| }, | |||
| { | |||
| label: '版本描述', | |||
| value: info.version_desc, | |||
| }, | |||
| ]; | |||
| const getModelDatas = (data: ModelData): BasicInfoData[] => [ | |||
| { | |||
| label: '模型名称', | |||
| value: data.name, | |||
| }, | |||
| { | |||
| label: '版本', | |||
| value: data.version, | |||
| }, | |||
| { | |||
| label: '创建人', | |||
| value: data.create_by, | |||
| }, | |||
| { | |||
| label: '更新时间', | |||
| value: data.update_time, | |||
| }, | |||
| { | |||
| label: '训练镜像', | |||
| value: data.image, | |||
| }, | |||
| { | |||
| label: '训练代码', | |||
| value: data.code, | |||
| }, | |||
| { | |||
| label: '训练数据集', | |||
| value: data.train_datasets, | |||
| format: formatDataset, | |||
| }, | |||
| { | |||
| label: '测试数据集', | |||
| value: data.test_datasets, | |||
| format: formatDataset, | |||
| }, | |||
| { | |||
| label: '参数', | |||
| value: data.params, | |||
| format: formatMap, | |||
| }, | |||
| { | |||
| label: '指标', | |||
| value: data.metrics, | |||
| format: formatMap, | |||
| }, | |||
| { | |||
| label: '训练任务', | |||
| value: data.train_task, | |||
| format: (value?: any) => value?.name, | |||
| externalLink: data.train_task | |||
| ? `${location.origin}/pipeline/experiment/instance/${data.train_task.task_id}/${data.train_task.ins_id}` | |||
| : '', | |||
| }, | |||
| { | |||
| label: '模型来源', | |||
| value: data.model_source, | |||
| }, | |||
| { | |||
| label: '模型框架', | |||
| value: data.model_type, | |||
| }, | |||
| { | |||
| label: '模型能力', | |||
| value: data.model_tag, | |||
| }, | |||
| { | |||
| label: '模型描述', | |||
| value: data.description, | |||
| }, | |||
| { | |||
| label: '版本描述', | |||
| value: data.version_desc, | |||
| }, | |||
| ]; | |||
| function ResourceIntro({ resourceType, info }: ResourceIntroProps) { | |||
| const basicDatas: BasicInfoData[] = | |||
| resourceType === ResourceType.Dataset ? datasetDatas : modelDatas; | |||
| resourceType === ResourceType.Dataset | |||
| ? getDatasetDatas(info as DatasetData) | |||
| : getModelDatas(info as ModelData); | |||
| return ( | |||
| <div className={styles['resource-intro']}> | |||
| @@ -128,7 +128,7 @@ export type CategoryData = { | |||
| }; | |||
| // 数据集、模型列表数据 | |||
| export type ResourceData = { | |||
| export interface ResourceData { | |||
| id: number; | |||
| name: string; | |||
| identifier: string; | |||
| @@ -142,25 +142,34 @@ export type ResourceData = { | |||
| version_desc?: string; | |||
| usage?: string; | |||
| relative_paths?: string; | |||
| // 数据集 | |||
| resourceType: ResourceType.Dataset | ResourceType.Model; | |||
| } | |||
| // 数据集数据 | |||
| export interface DatasetData extends ResourceData { | |||
| resourceType: ResourceType.Dataset; // 用于区别类型 | |||
| data_type?: string; // 数据集分类 | |||
| data_tag?: string; // 研究方向 | |||
| processing_code?: string; // 处理代码 | |||
| dataset_source?: string; // 数据来源 | |||
| dataset_version_vos: ResourceFileData[]; | |||
| // 模型 | |||
| dataset_version_vos?: ResourceFileData[]; | |||
| } | |||
| // 模型数据 | |||
| export interface ModelData extends ResourceData { | |||
| resourceType: ResourceType.Model; // 用于区别类型 | |||
| model_type?: string; // 模型框架 | |||
| model_tag?: string; // 模型能力 | |||
| image?: string; // 训练镜像 | |||
| code?: string; // 训练镜像 | |||
| train_datasets?: string[]; // 训练数据集 | |||
| test_datasets?: string[]; // 测试数据集 | |||
| train_datasets?: DatasetData[]; // 训练数据集 | |||
| test_datasets?: DatasetData[]; // 测试数据集 | |||
| params?: Record<string, string>; // 参数 | |||
| metrics?: Record<string, string>; // 指标 | |||
| train_task?: string; // 训练任务 | |||
| train_task?: TrainTask; // 训练任务 | |||
| model_source?: string; // 模型来源 | |||
| model_version_vos: ResourceFileData[]; | |||
| }; | |||
| model_version_vos?: ResourceFileData[]; | |||
| } | |||
| // 版本数据 | |||
| export type ResourceVersionData = { | |||
| @@ -177,3 +186,10 @@ export type ResourceFileData = { | |||
| url: string; | |||
| update_time?: string; | |||
| }; | |||
| // 训练任务 | |||
| export type TrainTask = { | |||
| ins_id: number; | |||
| name: string; | |||
| task_id: string; | |||
| }; | |||
| @@ -1,3 +1,4 @@ | |||
| import { TrainTask } from '@/pages/Dataset/config'; | |||
| import { changePropertyName, fittingString } from '@/utils'; | |||
| import { EdgeConfig, GraphData, LayoutConfig, NodeConfig, TreeGraphData, Util } from '@antv/g6'; | |||
| // @ts-ignore | |||
| @@ -31,12 +32,6 @@ export type Rect = { | |||
| height: number; | |||
| }; | |||
| export type TrainTask = { | |||
| ins_id: number; | |||
| name: string; | |||
| task_id: string; | |||
| }; | |||
| export interface TrainDataset extends NodeConfig { | |||
| repo_id: number; | |||
| name: string; | |||