| @@ -65,3 +65,4 @@ mvnw | |||||
| /react-ui/types/tsconfig.tsbuildinfo | /react-ui/types/tsconfig.tsbuildinfo | ||||
| /react-ui/storybook-static | /react-ui/storybook-static | ||||
| /react-ui/.storybook/scripts | /react-ui/.storybook/scripts | ||||
| /react-ui/dist.zip | |||||
| @@ -1,8 +1,9 @@ | |||||
| import { filterResourceStandard, resourceFieldNames } from '@/hooks/useComputingResource'; | |||||
| import { DatasetData, ModelData } from '@/pages/Dataset/config'; | import { DatasetData, ModelData } from '@/pages/Dataset/config'; | ||||
| import { ServiceData } from '@/pages/ModelDeployment/types'; | import { ServiceData } from '@/pages/ModelDeployment/types'; | ||||
| import { getDatasetList, getModelList } from '@/services/dataset/index.js'; | import { getDatasetList, getModelList } from '@/services/dataset/index.js'; | ||||
| import { getServiceListReq } from '@/services/modelDeployment'; | import { getServiceListReq } from '@/services/modelDeployment'; | ||||
| import type { JCCResourceImage, JCCResourceStandard, JCCResourceType } from '@/state/jcdResource'; | |||||
| import { filterResourceStandard, resourceFieldNames } from '@/state/systemResource'; | |||||
| import { type SelectProps } from 'antd'; | import { type SelectProps } from 'antd'; | ||||
| export type SelectPropsConfig = { | export type SelectPropsConfig = { | ||||
| @@ -10,12 +11,21 @@ export type SelectPropsConfig = { | |||||
| fieldNames?: SelectProps['fieldNames']; // 下拉数据字段 | fieldNames?: SelectProps['fieldNames']; // 下拉数据字段 | ||||
| optionFilterProp?: SelectProps['optionFilterProp']; // 过滤字段名 | optionFilterProp?: SelectProps['optionFilterProp']; // 过滤字段名 | ||||
| filterOption?: SelectProps['filterOption']; // 过滤函数 | filterOption?: SelectProps['filterOption']; // 过滤函数 | ||||
| getValue: (value: any) => string | number; | |||||
| getLabel: (value: any) => string; | |||||
| isObjectValue: boolean; // value 是对象 | isObjectValue: boolean; // value 是对象 | ||||
| getValue?: (value: any) => string | number; // 对象类型时,获取其值 | |||||
| getLabel?: (value: any) => string; // 对象类型时,获取其 label | |||||
| }; | }; | ||||
| export const paramSelectConfig: Record<string, SelectPropsConfig> = { | |||||
| export type ParameterSelectDataType = | |||||
| | 'dataset' | |||||
| | 'model' | |||||
| | 'service' | |||||
| | 'resource' | |||||
| | 'remote-image' | |||||
| | 'remote-resource-type' | |||||
| | 'remote-resource'; | |||||
| export const paramSelectConfig: Record<ParameterSelectDataType, SelectPropsConfig> = { | |||||
| dataset: { | dataset: { | ||||
| getOptions: async () => { | getOptions: async () => { | ||||
| const res = await getDatasetList({ | const res = await getDatasetList({ | ||||
| @@ -72,14 +82,44 @@ export const paramSelectConfig: Record<string, SelectPropsConfig> = { | |||||
| resource: { | resource: { | ||||
| fieldNames: resourceFieldNames, | fieldNames: resourceFieldNames, | ||||
| filterOption: filterResourceStandard as SelectProps['filterOption'], | filterOption: filterResourceStandard as SelectProps['filterOption'], | ||||
| // 不会用到 | |||||
| getValue: () => { | |||||
| return ''; | |||||
| isObjectValue: false, | |||||
| }, | |||||
| 'remote-resource-type': { | |||||
| optionFilterProp: 'label', | |||||
| isObjectValue: false, | |||||
| getValue: (value: JCCResourceType) => { | |||||
| return value.value; | |||||
| }, | }, | ||||
| // 不会用的 | |||||
| getLabel: () => { | |||||
| return ''; | |||||
| getLabel: (value: JCCResourceType) => { | |||||
| return value.label; | |||||
| }, | }, | ||||
| isObjectValue: false, | |||||
| }, | |||||
| 'remote-image': { | |||||
| optionFilterProp: 'label', | |||||
| getValue: (value: JCCResourceImage) => { | |||||
| return value.imageID; | |||||
| }, | |||||
| getLabel: (value: JCCResourceImage) => { | |||||
| return value.name; | |||||
| }, | |||||
| isObjectValue: true, | |||||
| }, | |||||
| 'remote-resource': { | |||||
| optionFilterProp: 'label', | |||||
| getValue: (value: JCCResourceStandard) => { | |||||
| return value.id; | |||||
| }, | |||||
| getLabel: (value: JCCResourceStandard) => { | |||||
| const cpu = value.baseResourceSpecs.find((v) => v.type === 'CPU'); | |||||
| const ram = value.baseResourceSpecs.find((v) => v.type === 'MEMORY' && v.name === 'RAM'); | |||||
| const vram = value.baseResourceSpecs.find((v) => v.type === 'MEMORY' && v.name === 'VRAM'); | |||||
| const cpuText = cpu ? `CPU:${cpu.availableValue}, ` : ''; | |||||
| const ramText = ram ? `内存: ${ram.availableValue}${ram.availableUnit?.toUpperCase()}` : ''; | |||||
| const vramText = vram | |||||
| ? `(显存${vram.availableValue}${vram.availableUnit?.toUpperCase()})` | |||||
| : ''; | |||||
| return `${value.type}: ${value.availableCount}*${value.name}${vramText}, ${cpuText}${ramText}`; | |||||
| }, | |||||
| isObjectValue: true, | |||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -4,19 +4,25 @@ | |||||
| * @Description: 参数下拉选择组件,支持资源规格、数据集、模型、服务 | * @Description: 参数下拉选择组件,支持资源规格、数据集、模型、服务 | ||||
| */ | */ | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import jccResourceState from '@/state/jcdResource'; | |||||
| import systemResourceState, { getSystemResources } from '@/state/systemResource'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { useSnapshot } from '@umijs/max'; | |||||
| import { Select, type SelectProps } from 'antd'; | import { Select, type SelectProps } from 'antd'; | ||||
| import { useEffect, useMemo, useState } from 'react'; | |||||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | |||||
| import FormInfo from '../FormInfo'; | import FormInfo from '../FormInfo'; | ||||
| import { paramSelectConfig } from './config'; | |||||
| import { paramSelectConfig, type ParameterSelectDataType } from './config'; | |||||
| export { type ParameterSelectDataType }; | |||||
| export type ParameterSelectObject = { | export type ParameterSelectObject = { | ||||
| value: any; | value: any; | ||||
| [key: string]: any; | [key: string]: any; | ||||
| }; | }; | ||||
| export type ParameterSelectDataType = 'dataset' | 'model' | 'service' | 'resource'; | |||||
| type SelectOptions = SelectProps['options']; | |||||
| const identityFunc = (value: any) => value; | |||||
| export interface ParameterSelectProps extends SelectProps { | export interface ParameterSelectProps extends SelectProps { | ||||
| /** 类型 */ | /** 类型 */ | ||||
| @@ -25,8 +31,6 @@ export interface ParameterSelectProps extends SelectProps { | |||||
| display?: boolean; | display?: boolean; | ||||
| /** 值,支持对象,对象必须包含 value */ | /** 值,支持对象,对象必须包含 value */ | ||||
| value?: string | ParameterSelectObject; | value?: string | ParameterSelectObject; | ||||
| /** 用于流水线, 流水线资源规格要求 id 为字符串 */ | |||||
| isPipeline?: boolean; | |||||
| /** 修改后回调 */ | /** 修改后回调 */ | ||||
| onChange?: (value: string | ParameterSelectObject) => void; | onChange?: (value: string | ParameterSelectObject) => void; | ||||
| } | } | ||||
| @@ -36,15 +40,14 @@ function ParameterSelect({ | |||||
| dataType, | dataType, | ||||
| display = false, | display = false, | ||||
| value, | value, | ||||
| // isPipeline = false, | |||||
| onChange, | onChange, | ||||
| ...rest | ...rest | ||||
| }: ParameterSelectProps) { | }: ParameterSelectProps) { | ||||
| const [options, setOptions] = useState<SelectProps['options']>([]); | |||||
| const [options, setOptions] = useState<SelectOptions>([]); | |||||
| const propsConfig = paramSelectConfig[dataType]; | const propsConfig = paramSelectConfig[dataType]; | ||||
| const { | const { | ||||
| getLabel, | |||||
| getValue, | |||||
| getLabel = identityFunc, | |||||
| getValue = identityFunc, | |||||
| getOptions, | getOptions, | ||||
| filterOption, | filterOption, | ||||
| fieldNames, | fieldNames, | ||||
| @@ -55,29 +58,45 @@ function ParameterSelect({ | |||||
| // 数据集、模型、服务,对象转换成 json 字符串 | // 数据集、模型、服务,对象转换成 json 字符串 | ||||
| const valueText = | const valueText = | ||||
| typeof selectValue === 'object' && selectValue !== null ? getValue(selectValue) : selectValue; | typeof selectValue === 'object' && selectValue !== null ? getValue(selectValue) : selectValue; | ||||
| const [resourceStandardList] = useComputingResource(); | |||||
| // const computingResource = isPipeline | |||||
| // ? resourceStandardList.map((v) => ({ | |||||
| // ...v, | |||||
| // id: String(v.id), | |||||
| // })) | |||||
| // : resourceStandardList; | |||||
| const jccResourceSnap = useSnapshot(jccResourceState); | |||||
| const { getResourceTypes } = jccResourceSnap; | |||||
| const systemResourceSnap = useSnapshot(systemResourceState); | |||||
| const objectOptions = useMemo(() => { | const objectOptions = useMemo(() => { | ||||
| return options?.map((v) => ({ | |||||
| label: getLabel(v), | |||||
| value: getValue(v), | |||||
| })); | |||||
| }, [getLabel, getValue, options]); | |||||
| return dataType === 'remote-resource-type' | |||||
| ? jccResourceSnap.types | |||||
| : dataType === 'remote-image' | |||||
| ? jccResourceSnap.images | |||||
| : dataType === 'remote-resource' | |||||
| ? jccResourceSnap.resources | |||||
| : options; | |||||
| }, [dataType, options, jccResourceSnap.types, jccResourceSnap.images, jccResourceSnap.resources]); | |||||
| // 将对象类型转换为 Select Options | |||||
| const converObjectToOptions = useCallback( | |||||
| (v: any) => { | |||||
| return { | |||||
| label: getLabel(v), | |||||
| value: getValue(v), | |||||
| }; | |||||
| }, | |||||
| [getLabel, getValue], | |||||
| ); | |||||
| // 数据集、模型、服务获取数据后,进行转换 | |||||
| const objectSelectOptions = useMemo(() => { | |||||
| return objectOptions?.map(converObjectToOptions); | |||||
| }, [converObjectToOptions, objectOptions]); | |||||
| // 快速得到选中的对象 | |||||
| const valueMap = useMemo(() => { | const valueMap = useMemo(() => { | ||||
| const map = new Map<string | number, any>(); | const map = new Map<string | number, any>(); | ||||
| options?.forEach((v) => { | |||||
| objectOptions?.forEach((v) => { | |||||
| map.set(getValue(v), v); | map.set(getValue(v), v); | ||||
| }); | }); | ||||
| return map; | return map; | ||||
| }, [options, getValue]); | |||||
| }, [objectOptions, getValue]); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| // 获取下拉数据 | // 获取下拉数据 | ||||
| @@ -87,13 +106,18 @@ function ParameterSelect({ | |||||
| if (res) { | if (res) { | ||||
| setOptions(res); | setOptions(res); | ||||
| } | } | ||||
| } else if (dataType === 'remote-resource-type') { | |||||
| getResourceTypes(); | |||||
| } else if (dataType === 'resource') { | |||||
| getSystemResources(); | |||||
| } | } | ||||
| }; | }; | ||||
| getSelectOptions(); | getSelectOptions(); | ||||
| }, [getOptions]); | |||||
| }, [getOptions, dataType, getResourceTypes]); | |||||
| const selectOptions = dataType === 'resource' ? resourceStandardList : objectOptions; | |||||
| const selectOptions = ( | |||||
| dataType === 'resource' ? systemResourceSnap.resources : objectSelectOptions | |||||
| ) as SelectOptions; | |||||
| const handleChange = (text: string) => { | const handleChange = (text: string) => { | ||||
| // 数据集、模型、服务,转换成对象 | // 数据集、模型、服务,转换成对象 | ||||
| @@ -4,66 +4,90 @@ | |||||
| * @Description: 资源规格 hook | * @Description: 资源规格 hook | ||||
| */ | */ | ||||
| import { getComputingResourceReq } from '@/services/pipeline'; | |||||
| import { ComputingResource } from '@/types'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { type SelectProps } from 'antd'; | |||||
| import { useCallback, useEffect, useState } from 'react'; | |||||
| // import { getComputingResourceReq } from '@/services/pipeline'; | |||||
| // import { ComputingResource } from '@/types'; | |||||
| // import { to } from '@/utils/promise'; | |||||
| // import { type SelectProps } from 'antd'; | |||||
| // import { useCallback, useEffect, useState } from 'react'; | |||||
| const computingResource: ComputingResource[] = []; | |||||
| // const computingResource: ComputingResource[] = []; | |||||
| /** 过滤资源规格 */ | |||||
| export const filterResourceStandard: SelectProps<string, ComputingResource>['filterOption'] = ( | |||||
| input: string, | |||||
| option?: ComputingResource, | |||||
| ) => { | |||||
| return ( | |||||
| option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false | |||||
| ); | |||||
| }; | |||||
| // /** 过滤资源规格 */ | |||||
| // export const filterResourceStandard: SelectProps<string, ComputingResource>['filterOption'] = ( | |||||
| // input: string, | |||||
| // option?: ComputingResource, | |||||
| // ) => { | |||||
| // return ( | |||||
| // option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false | |||||
| // ); | |||||
| // }; | |||||
| /** 资源规格字段 */ | |||||
| export const resourceFieldNames = { | |||||
| label: 'description', | |||||
| value: 'id', | |||||
| }; | |||||
| // /** 资源规格字段 */ | |||||
| // export const resourceFieldNames = { | |||||
| // label: 'description', | |||||
| // value: 'id', | |||||
| // }; | |||||
| /** 获取资源规格 */ | |||||
| export function useComputingResource() { | |||||
| const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]); | |||||
| // /** 获取资源规格 */ | |||||
| // export function useComputingResource() { | |||||
| // const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]); | |||||
| useEffect(() => { | |||||
| // 获取资源规格列表数据 | |||||
| const getComputingResource = async () => { | |||||
| const params = { | |||||
| page: 0, | |||||
| size: 1000, | |||||
| resource_type: '', | |||||
| }; | |||||
| const [res] = await to(getComputingResourceReq(params)); | |||||
| if (res && res.data && Array.isArray(res.data.content)) { | |||||
| setResourceStandardList(res.data.content); | |||||
| computingResource.splice(0, computingResource.length, ...res.data.content); | |||||
| } | |||||
| }; | |||||
| // useEffect(() => { | |||||
| // // 获取资源规格列表数据 | |||||
| // const getComputingResource = async () => { | |||||
| // const params = { | |||||
| // page: 0, | |||||
| // size: 1000, | |||||
| // resource_type: '', | |||||
| // }; | |||||
| // const [res] = await to(getComputingResourceReq(params)); | |||||
| // if (res && res.data && Array.isArray(res.data.content)) { | |||||
| // setResourceStandardList(res.data.content); | |||||
| // computingResource.splice(0, computingResource.length, ...res.data.content); | |||||
| // } | |||||
| // }; | |||||
| // if (computingResource.length > 0) { | |||||
| // setResourceStandardList(computingResource); | |||||
| // } else { | |||||
| // getComputingResource(); | |||||
| // } | |||||
| // }, []); | |||||
| if (computingResource.length > 0) { | |||||
| setResourceStandardList(computingResource); | |||||
| } else { | |||||
| getComputingResource(); | |||||
| } | |||||
| // // 根据 standard 获取 description | |||||
| // const getDescription = useCallback( | |||||
| // (id?: string | number) => { | |||||
| // if (!id) { | |||||
| // return undefined; | |||||
| // } | |||||
| // return resourceStandardList.find((item) => Number(item.id) === Number(id))?.description; | |||||
| // }, | |||||
| // [resourceStandardList], | |||||
| // ); | |||||
| // return [resourceStandardList, getDescription] as const; | |||||
| // } | |||||
| import state, { getSystemResources } from '@/state/systemResource'; | |||||
| import { useSnapshot } from '@umijs/max'; | |||||
| import { useCallback, useEffect } from 'react'; | |||||
| export const useSystemResource = () => { | |||||
| useEffect(() => { | |||||
| getSystemResources(); | |||||
| }, []); | }, []); | ||||
| // 根据 standard 获取 description | |||||
| const snap = useSnapshot(state); | |||||
| /* 根据 standard 获取 description */ | |||||
| const getDescription = useCallback( | const getDescription = useCallback( | ||||
| (id?: string | number) => { | (id?: string | number) => { | ||||
| if (!id) { | if (!id) { | ||||
| return undefined; | return undefined; | ||||
| } | } | ||||
| return resourceStandardList.find((item) => Number(item.id) === Number(id))?.description; | |||||
| return snap.resources.find((item) => Number(item.id) === Number(id))?.description; | |||||
| }, | }, | ||||
| [resourceStandardList], | |||||
| [snap.resources], | |||||
| ); | ); | ||||
| return [resourceStandardList, getDescription] as const; | |||||
| } | |||||
| return getDescription; | |||||
| }; | |||||
| @@ -1,6 +1,6 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | ||||
| import { AutoMLTaskType, autoMLTaskTypeOptions, ExperimentStatus } from '@/enums'; | import { AutoMLTaskType, autoMLTaskTypeOptions, ExperimentStatus } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { | import { | ||||
| classifierAlgorithms, | classifierAlgorithms, | ||||
| FrameworkType, | FrameworkType, | ||||
| @@ -39,7 +39,7 @@ function BasicInfo({ | |||||
| instanceStatus, | instanceStatus, | ||||
| isInstance = false, | isInstance = false, | ||||
| }: BasicInfoProps) { | }: BasicInfoProps) { | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | const basicDatas: BasicInfoData[] = useMemo(() => { | ||||
| if (!info) { | if (!info) { | ||||
| return []; | return []; | ||||
| @@ -6,7 +6,7 @@ import { | |||||
| autoMLEnsembleClassOptions, | autoMLEnsembleClassOptions, | ||||
| autoMLTaskTypeOptions, | autoMLTaskTypeOptions, | ||||
| } from '@/enums'; | } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { | import { | ||||
| classificationAlgorithms, | classificationAlgorithms, | ||||
| featureAlgorithms, | featureAlgorithms, | ||||
| @@ -76,7 +76,7 @@ function AutoMLBasic({ | |||||
| instanceStatus, | instanceStatus, | ||||
| isInstance = false, | isInstance = false, | ||||
| }: AutoMLBasicProps) { | }: AutoMLBasicProps) { | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | const basicDatas: BasicInfoData[] = useMemo(() => { | ||||
| if (!info) { | if (!info) { | ||||
| return []; | return []; | ||||
| @@ -1,30 +1,8 @@ | |||||
| import { getAccessToken } from '@/access'; | |||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import { CategoryData, DataSource, ResourceType, resourceConfig } from '@/pages/Dataset/config'; | |||||
| import { CategoryData, DataSource } from '@/pages/Dataset/config'; | |||||
| import { addDataset } from '@/services/dataset/index.js'; | import { addDataset } from '@/services/dataset/index.js'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { | |||||
| getFileListFromEvent, | |||||
| limitUploadFileType, | |||||
| removeUploadedFile, | |||||
| validateUploadFiles, | |||||
| } from '@/utils/ui'; | |||||
| import { | |||||
| Button, | |||||
| Form, | |||||
| Input, | |||||
| Radio, | |||||
| Select, | |||||
| Upload, | |||||
| UploadFile, | |||||
| message, | |||||
| type ModalProps, | |||||
| type UploadProps, | |||||
| } from 'antd'; | |||||
| import { omit } from 'lodash'; | |||||
| import { useState } from 'react'; | |||||
| import styles from './index.less'; | |||||
| import { Form, Input, Radio, Select, message, type ModalProps } from 'antd'; | |||||
| interface AddDatasetModalProps extends Omit<ModalProps, 'onOk'> { | interface AddDatasetModalProps extends Omit<ModalProps, 'onOk'> { | ||||
| typeList: CategoryData[]; | typeList: CategoryData[]; | ||||
| @@ -33,20 +11,6 @@ interface AddDatasetModalProps extends Omit<ModalProps, 'onOk'> { | |||||
| } | } | ||||
| function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) { | function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) { | ||||
| const [uuid] = useState(Date.now()); | |||||
| // 上传组件参数 | |||||
| const uploadProps: UploadProps = { | |||||
| action: resourceConfig[ResourceType.Dataset].uploadAction, | |||||
| headers: { | |||||
| Authorization: getAccessToken() || '', | |||||
| }, | |||||
| defaultFileList: [], | |||||
| accept: '.zip,.tgz', | |||||
| beforeUpload: limitUploadFileType('zip,tgz'), | |||||
| onRemove: removeUploadedFile, | |||||
| }; | |||||
| // 上传请求 | // 上传请求 | ||||
| const createDataset = async (params: any) => { | const createDataset = async (params: any) => { | ||||
| const [res] = await to(addDataset(params)); | const [res] = await to(addDataset(params)); | ||||
| @@ -58,22 +22,11 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr | |||||
| // 提交 | // 提交 | ||||
| const onFinish = (formData: any) => { | const onFinish = (formData: any) => { | ||||
| const fileList: UploadFile[] = formData['fileList'] ?? []; | |||||
| if (validateUploadFiles(fileList)) { | |||||
| const params = { | |||||
| ...omit(formData, ['fileList']), | |||||
| dataset_source: DataSource.Create, | |||||
| dataset_version_vos: fileList.map((item) => { | |||||
| const data = item.response?.data?.[0] ?? {}; | |||||
| return { | |||||
| file_name: data.fileName, | |||||
| file_size: data.fileSize, | |||||
| url: data.url, | |||||
| }; | |||||
| }), | |||||
| }; | |||||
| createDataset(params); | |||||
| } | |||||
| const params = { | |||||
| ...formData, | |||||
| dataset_source: DataSource.Create, | |||||
| }; | |||||
| createDataset(params); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| @@ -108,32 +61,6 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr | |||||
| > | > | ||||
| <Input placeholder="请输入数据名称" showCount allowClear maxLength={40} /> | <Input placeholder="请输入数据名称" showCount allowClear maxLength={40} /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="数据集版本" | |||||
| name="version" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入数据集版本', | |||||
| }, | |||||
| { | |||||
| pattern: /^[a-zA-Z0-9._-]+$/, | |||||
| message: '数据集版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', | |||||
| }, | |||||
| { | |||||
| validator: (_rule, value) => { | |||||
| if (value === 'master') { | |||||
| return Promise.reject(`数据集版本不能为 master`); | |||||
| } else if (value === 'origin') { | |||||
| return Promise.reject(`数据集版本不能为 origin`); | |||||
| } | |||||
| return Promise.resolve(); | |||||
| }, | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入数据集版本" showCount allowClear maxLength={64} /> | |||||
| </Form.Item> | |||||
| <Form.Item label="数据集分类" name="data_type"> | <Form.Item label="数据集分类" name="data_type"> | ||||
| <Select | <Select | ||||
| allowClear | allowClear | ||||
| @@ -172,24 +99,6 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr | |||||
| allowClear | allowClear | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="版本描述" | |||||
| name="version_desc" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入版本描述', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input.TextArea | |||||
| placeholder="请输入版本描述" | |||||
| autoSize={{ minRows: 2, maxRows: 6 }} | |||||
| maxLength={200} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item | <Form.Item | ||||
| label="可见性" | label="可见性" | ||||
| name="is_public" | name="is_public" | ||||
| @@ -200,29 +109,6 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr | |||||
| <Radio value={true}>公开</Radio> | <Radio value={true}>公开</Radio> | ||||
| </Radio.Group> | </Radio.Group> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="数据集文件" | |||||
| name="fileList" | |||||
| valuePropName="fileList" | |||||
| getValueFromEvent={getFileListFromEvent} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请上传数据集文件', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Upload {...uploadProps} data={{ uuid: uuid }}> | |||||
| <Button | |||||
| className={styles['upload-button']} | |||||
| type="default" | |||||
| icon={<KFIcon type="icon-shangchuan" />} | |||||
| > | |||||
| 上传文件 | |||||
| </Button> | |||||
| <div className={styles['upload-tip']}>只允许上传 .zip 和 .tgz 格式文件</div> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| </Form> | </Form> | ||||
| </KFModal> | </KFModal> | ||||
| ); | ); | ||||
| @@ -1,25 +1,8 @@ | |||||
| import { getAccessToken } from '@/access'; | |||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import { CategoryData, DataSource, ResourceType, resourceConfig } from '@/pages/Dataset/config'; | |||||
| import { CategoryData, DataSource } from '@/pages/Dataset/config'; | |||||
| import { addModel } from '@/services/dataset/index.js'; | import { addModel } from '@/services/dataset/index.js'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { getFileListFromEvent, removeUploadedFile, validateUploadFiles } from '@/utils/ui'; | |||||
| import { | |||||
| Button, | |||||
| Form, | |||||
| Input, | |||||
| Radio, | |||||
| Select, | |||||
| Upload, | |||||
| UploadFile, | |||||
| message, | |||||
| type ModalProps, | |||||
| type UploadProps, | |||||
| } from 'antd'; | |||||
| import { omit } from 'lodash'; | |||||
| import { useState } from 'react'; | |||||
| import styles from '../AddDatasetModal/index.less'; | |||||
| import { Form, Input, Radio, Select, message, type ModalProps } from 'antd'; | |||||
| interface AddModelModalProps extends Omit<ModalProps, 'onOk'> { | interface AddModelModalProps extends Omit<ModalProps, 'onOk'> { | ||||
| typeList: CategoryData[]; | typeList: CategoryData[]; | ||||
| @@ -28,18 +11,6 @@ interface AddModelModalProps extends Omit<ModalProps, 'onOk'> { | |||||
| } | } | ||||
| function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) { | function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) { | ||||
| const [uuid] = useState(Date.now()); | |||||
| // 上传组件参数 | |||||
| const uploadProps: UploadProps = { | |||||
| action: resourceConfig[ResourceType.Model].uploadAction, | |||||
| headers: { | |||||
| Authorization: getAccessToken() || '', | |||||
| }, | |||||
| defaultFileList: [], | |||||
| onRemove: removeUploadedFile, | |||||
| }; | |||||
| // 上传请求 | // 上传请求 | ||||
| const createModel = async (params: any) => { | const createModel = async (params: any) => { | ||||
| const [res] = await to(addModel(params)); | const [res] = await to(addModel(params)); | ||||
| @@ -51,22 +22,11 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) | |||||
| // 提交 | // 提交 | ||||
| const onFinish = (formData: any) => { | const onFinish = (formData: any) => { | ||||
| const fileList: UploadFile[] = formData['fileList'] ?? []; | |||||
| if (validateUploadFiles(fileList)) { | |||||
| const params = { | |||||
| ...omit(formData, ['fileList']), | |||||
| model_source: DataSource.Create, | |||||
| model_version_vos: fileList.map((item) => { | |||||
| const data = item.response?.data?.[0] ?? {}; | |||||
| return { | |||||
| file_name: data.fileName, | |||||
| file_size: data.fileSize, | |||||
| url: data.url, | |||||
| }; | |||||
| }), | |||||
| }; | |||||
| createModel(params); | |||||
| } | |||||
| const params = { | |||||
| ...formData, | |||||
| model_source: DataSource.Create, | |||||
| }; | |||||
| createModel(params); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| @@ -99,32 +59,6 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) | |||||
| > | > | ||||
| <Input placeholder="请输入模型名称" showCount allowClear maxLength={40} /> | <Input placeholder="请输入模型名称" showCount allowClear maxLength={40} /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="模型版本" | |||||
| name="version" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入模型版本', | |||||
| }, | |||||
| { | |||||
| pattern: /^[a-zA-Z0-9._-]+$/, | |||||
| message: '模型版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', | |||||
| }, | |||||
| { | |||||
| validator: (_rule, value) => { | |||||
| if (value === 'master') { | |||||
| return Promise.reject(`模型版本不能为 master`); | |||||
| } else if (value === 'origin') { | |||||
| return Promise.reject(`模型版本不能为 origin`); | |||||
| } | |||||
| return Promise.resolve(); | |||||
| }, | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入模型版本" showCount allowClear maxLength={64} /> | |||||
| </Form.Item> | |||||
| <Form.Item label="模型框架" name="model_type"> | <Form.Item label="模型框架" name="model_type"> | ||||
| <Select | <Select | ||||
| allowClear | allowClear | ||||
| @@ -163,24 +97,6 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) | |||||
| allowClear | allowClear | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="版本描述" | |||||
| name="version_desc" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入版本描述', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input.TextArea | |||||
| placeholder="请输入版本描述" | |||||
| autoSize={{ minRows: 2, maxRows: 6 }} | |||||
| maxLength={200} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item | <Form.Item | ||||
| label="可见性" | label="可见性" | ||||
| name="is_public" | name="is_public" | ||||
| @@ -191,28 +107,6 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) | |||||
| <Radio value={true}>公开</Radio> | <Radio value={true}>公开</Radio> | ||||
| </Radio.Group> | </Radio.Group> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="模型文件" | |||||
| name="fileList" | |||||
| valuePropName="fileList" | |||||
| getValueFromEvent={getFileListFromEvent} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请上传模型文件', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Upload {...uploadProps} data={{ uuid: uuid }}> | |||||
| <Button | |||||
| className={styles['upload-button']} | |||||
| type="default" | |||||
| icon={<KFIcon type="icon-shangchuan" />} | |||||
| > | |||||
| 上传文件 | |||||
| </Button> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| </Form> | </Form> | ||||
| </KFModal> | </KFModal> | ||||
| ); | ); | ||||
| @@ -15,7 +15,7 @@ import { | |||||
| type UploadProps, | type UploadProps, | ||||
| } from 'antd'; | } from 'antd'; | ||||
| import { omit } from 'lodash'; | import { omit } from 'lodash'; | ||||
| import { useState } from 'react'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import styles from '../AddDatasetModal/index.less'; | import styles from '../AddDatasetModal/index.less'; | ||||
| interface AddVersionModalProps extends Omit<ModalProps, 'onOk'> { | interface AddVersionModalProps extends Omit<ModalProps, 'onOk'> { | ||||
| @@ -40,6 +40,23 @@ function AddVersionModal({ | |||||
| }: AddVersionModalProps) { | }: AddVersionModalProps) { | ||||
| const [uuid] = useState(Date.now()); | const [uuid] = useState(Date.now()); | ||||
| const config = resourceConfig[resourceType]; | const config = resourceConfig[resourceType]; | ||||
| const [form] = Form.useForm(); | |||||
| useEffect(() => { | |||||
| const getNextVersion = async () => { | |||||
| const request = config.getNextVersion; | |||||
| const params = { | |||||
| identifier, | |||||
| owner, | |||||
| }; | |||||
| const [res] = await to(request(params)); | |||||
| if (res && res.data) { | |||||
| const nextVersion = res.data; | |||||
| form.setFieldValue('version', nextVersion); | |||||
| } | |||||
| }; | |||||
| getNextVersion(); | |||||
| }, [identifier, owner, config, form]); | |||||
| // 上传组件参数 | // 上传组件参数 | ||||
| const uploadProps: UploadProps = { | const uploadProps: UploadProps = { | ||||
| @@ -109,6 +126,7 @@ function AddVersionModal({ | |||||
| }} | }} | ||||
| onFinish={onFinish} | onFinish={onFinish} | ||||
| autoComplete="off" | autoComplete="off" | ||||
| form={form} | |||||
| > | > | ||||
| <Form.Item | <Form.Item | ||||
| label={`${name}名称`} | label={`${name}名称`} | ||||
| @@ -146,7 +164,7 @@ function AddVersionModal({ | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| <Input placeholder={`请输入${name}版本`} maxLength={64} showCount allowClear /> | |||||
| <Input placeholder={`请输入${name}版本`} maxLength={64} showCount allowClear disabled /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="版本描述" | label="版本描述" | ||||
| @@ -28,8 +28,15 @@ | |||||
| border-radius: 4px; | border-radius: 4px; | ||||
| } | } | ||||
| &__desc { | |||||
| margin-bottom: 0 !important; | |||||
| color: @text-color; | |||||
| font-size: @font-size; | |||||
| } | |||||
| &__praise { | &__praise { | ||||
| display: flex; | display: flex; | ||||
| flex: none; | |||||
| align-items: center; | align-items: center; | ||||
| justify-content: center; | justify-content: center; | ||||
| width: 70px; | width: 70px; | ||||
| @@ -4,6 +4,7 @@ | |||||
| * @Description: 数据集、模型详情 | * @Description: 数据集、模型详情 | ||||
| */ | */ | ||||
| import KFEmpty, { EmptyType } from '@/components/KFEmpty'; | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { | import { | ||||
| ResourceData, | ResourceData, | ||||
| @@ -19,7 +20,7 @@ import { openAntdModal } from '@/utils/modal'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { useParams, useSearchParams } from '@umijs/max'; | import { useParams, useSearchParams } from '@umijs/max'; | ||||
| import { App, Button, Flex, Select, Tabs } from 'antd'; | |||||
| import { App, Button, Flex, Select, Tabs, Typography } from 'antd'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useCallback, useEffect, useState } from 'react'; | import { useCallback, useEffect, useState } from 'react'; | ||||
| import AddVersionModal from '../AddVersionModal'; | import AddVersionModal from '../AddVersionModal'; | ||||
| @@ -62,21 +63,24 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| // 获取详情 | // 获取详情 | ||||
| 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 getResourceDetail = useCallback( | |||||
| async (version: string | undefined) => { | |||||
| 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, is_public], | |||||
| ); | |||||
| // 获取版本列表 | // 获取版本列表 | ||||
| const getVersionList = useCallback( | const getVersionList = useCallback( | ||||
| @@ -101,14 +105,15 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||||
| } | } | ||||
| } else { | } else { | ||||
| setVersion(undefined); | setVersion(undefined); | ||||
| getResourceDetail(undefined); | |||||
| } | } | ||||
| }, | }, | ||||
| [config, owner, identifier, versionParam], | |||||
| [config, owner, identifier, versionParam, getResourceDetail], | |||||
| ); | ); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (version) { | if (version) { | ||||
| getResourceDetail(); | |||||
| getResourceDetail(version); | |||||
| } | } | ||||
| }, [version, getResourceDetail]); | }, [version, getResourceDetail]); | ||||
| @@ -117,7 +122,7 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||||
| }, [getVersionList]); | }, [getVersionList]); | ||||
| // 新建版本 | // 新建版本 | ||||
| const showModal = () => { | |||||
| const showAddVersionModal = () => { | |||||
| const { close } = openAntdModal(AddVersionModal, { | const { close } = openAntdModal(AddVersionModal, { | ||||
| resourceType: resourceType, | resourceType: resourceType, | ||||
| resourceId: resourceId, | resourceId: resourceId, | ||||
| @@ -291,52 +296,70 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||||
| <span>{info.praises_count}</span> | <span>{info.praises_count}</span> | ||||
| </div> | </div> | ||||
| </Flex> | </Flex> | ||||
| <Flex align="center"> | |||||
| <span style={{ marginRight: '10px' }}>版本号:</span> | |||||
| <Select | |||||
| placeholder="请选择版本号" | |||||
| style={{ width: '160px', marginRight: '20px' }} | |||||
| value={version} | |||||
| onChange={handleVersionChange} | |||||
| fieldNames={{ label: 'name', value: 'name' }} | |||||
| options={versionList} | |||||
| /> | |||||
| <Button type="default" onClick={showModal} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 创建新版本 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| style={{ marginLeft: '20px' }} | |||||
| icon={<KFIcon type="icon-bianji" />} | |||||
| onClick={showEditVersionModal} | |||||
| > | |||||
| 版本编辑 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| style={{ marginLeft: '20px' }} | |||||
| icon={<KFIcon type="icon-banbenduibi" />} | |||||
| onClick={showVersionSelector} | |||||
| > | |||||
| 版本对比 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| style={{ marginLeft: '20px' }} | |||||
| onClick={handleDelete} | |||||
| icon={<KFIcon type="icon-shanchu" />} | |||||
| disabled={!version} | |||||
| danger | |||||
| {version ? ( | |||||
| <Flex align="center"> | |||||
| <span style={{ marginRight: '10px' }}>版本号:</span> | |||||
| <Select | |||||
| placeholder="请选择版本号" | |||||
| style={{ width: '160px', marginRight: '20px' }} | |||||
| value={version} | |||||
| onChange={handleVersionChange} | |||||
| fieldNames={{ label: 'name', value: 'name' }} | |||||
| options={versionList} | |||||
| /> | |||||
| <Button | |||||
| type="default" | |||||
| onClick={showAddVersionModal} | |||||
| icon={<KFIcon type="icon-xinjian2" />} | |||||
| > | |||||
| 创建新版本 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| style={{ marginLeft: '20px' }} | |||||
| icon={<KFIcon type="icon-banbenduibi" />} | |||||
| onClick={showVersionSelector} | |||||
| > | |||||
| 版本对比 | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| style={{ marginLeft: '20px' }} | |||||
| onClick={handleDelete} | |||||
| icon={<KFIcon type="icon-shanchu" />} | |||||
| danger | |||||
| > | |||||
| 删除版本 | |||||
| </Button> | |||||
| </Flex> | |||||
| ) : ( | |||||
| <Typography.Paragraph | |||||
| className={styles['resource-info__top__desc']} | |||||
| ellipsis={{ tooltip: info.description }} | |||||
| > | > | ||||
| 删除版本 | |||||
| </Button> | |||||
| </Flex> | |||||
| {info.description ?? '暂无描述'} | |||||
| </Typography.Paragraph> | |||||
| )} | |||||
| </div> | </div> | ||||
| <div className={styles['resource-info__bottom']}> | <div className={styles['resource-info__bottom']}> | ||||
| <Tabs activeKey={activeTab} items={items} onChange={(key) => setActiveTab(key)}></Tabs> | |||||
| <div className={styles['resource-info__bottom__legend']}> | |||||
| {activeTab === ResourceInfoTabKeys.Evolution && <GraphLegend />} | |||||
| </div> | |||||
| {version ? ( | |||||
| <> | |||||
| <Tabs activeKey={activeTab} items={items} onChange={(key) => setActiveTab(key)}></Tabs> | |||||
| <div className={styles['resource-info__bottom__legend']}> | |||||
| {activeTab === ResourceInfoTabKeys.Evolution && <GraphLegend />} | |||||
| </div> | |||||
| </> | |||||
| ) : ( | |||||
| <KFEmpty | |||||
| style={{ height: '100%' }} | |||||
| type={EmptyType.NoData} | |||||
| title="暂无版本" | |||||
| content={`请创建${config.name}版本`} | |||||
| hasFooter={true} | |||||
| buttonTitle="创建版本" | |||||
| onButtonClick={showAddVersionModal} | |||||
| /> | |||||
| )} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -13,9 +13,11 @@ import { | |||||
| editModelVersion, | editModelVersion, | ||||
| getDatasetInfo, | getDatasetInfo, | ||||
| getDatasetList, | getDatasetList, | ||||
| getDatasetNextVersionReq, | |||||
| getDatasetVersionList, | getDatasetVersionList, | ||||
| getModelInfo, | getModelInfo, | ||||
| getModelList, | getModelList, | ||||
| getModelNextVersionReq, | |||||
| getModelVersionList, | getModelVersionList, | ||||
| } from '@/services/dataset/index.js'; | } from '@/services/dataset/index.js'; | ||||
| import { limitUploadFileType } from '@/utils/ui'; | import { limitUploadFileType } from '@/utils/ui'; | ||||
| @@ -42,6 +44,7 @@ type ResourceTypeInfo = { | |||||
| deleteVersion: (params: any) => Promise<any>; // 删除版本 | deleteVersion: (params: any) => Promise<any>; // 删除版本 | ||||
| getInfo: (params: any) => Promise<any>; // 获取详情 | getInfo: (params: any) => Promise<any>; // 获取详情 | ||||
| compareVersion: (params: any) => Promise<any>; // 版本对比 | compareVersion: (params: any) => Promise<any>; // 版本对比 | ||||
| getNextVersion: (params: any) => Promise<any>; // 获取下一个版本 | |||||
| name: string; // 名称 | name: string; // 名称 | ||||
| typeParamKey: 'data_type' | 'model_type'; // 类型参数名称,获取资源列表接口使用 | typeParamKey: 'data_type' | 'model_type'; // 类型参数名称,获取资源列表接口使用 | ||||
| tagParamKey: 'data_tag' | 'model_tag'; // 标签参数名称,获取资源列表接口使用 | tagParamKey: 'data_tag' | 'model_tag'; // 标签参数名称,获取资源列表接口使用 | ||||
| @@ -72,6 +75,7 @@ export const resourceConfig: Record<ResourceType, ResourceTypeInfo> = { | |||||
| deleteVersion: deleteDatasetVersion, | deleteVersion: deleteDatasetVersion, | ||||
| getInfo: getDatasetInfo, | getInfo: getDatasetInfo, | ||||
| compareVersion: compareDatasetVersion, | compareVersion: compareDatasetVersion, | ||||
| getNextVersion: getDatasetNextVersionReq, | |||||
| name: '数据集', | name: '数据集', | ||||
| typeParamKey: 'data_type', | typeParamKey: 'data_type', | ||||
| tagParamKey: 'data_tag', | tagParamKey: 'data_tag', | ||||
| @@ -111,6 +115,7 @@ export const resourceConfig: Record<ResourceType, ResourceTypeInfo> = { | |||||
| deleteVersion: deleteModelVersion, | deleteVersion: deleteModelVersion, | ||||
| getInfo: getModelInfo, | getInfo: getModelInfo, | ||||
| compareVersion: compareModelVersion, | compareVersion: compareModelVersion, | ||||
| getNextVersion: getModelNextVersionReq, | |||||
| name: '模型', | name: '模型', | ||||
| typeParamKey: 'model_type', | typeParamKey: 'model_type', | ||||
| tagParamKey: 'model_tag', | tagParamKey: 'model_tag', | ||||
| @@ -8,7 +8,7 @@ import { CodeConfigData } from '@/components/CodeSelectorModal'; | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { DevEditorStatus } from '@/enums'; | import { DevEditorStatus } from '@/enums'; | ||||
| import { useCacheState } from '@/hooks/useCacheState'; | import { useCacheState } from '@/hooks/useCacheState'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { DatasetData, ModelData } from '@/pages/Dataset/config'; | import { DatasetData, ModelData } from '@/pages/Dataset/config'; | ||||
| import { | import { | ||||
| deleteEditorReq, | deleteEditorReq, | ||||
| @@ -66,7 +66,7 @@ function EditorList() { | |||||
| pageSize: 10, | pageSize: 10, | ||||
| }, | }, | ||||
| ); | ); | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| // 获取编辑器列表 | // 获取编辑器列表 | ||||
| const getEditorList = useCallback(async () => { | const getEditorList = useCallback(async () => { | ||||
| @@ -3,12 +3,10 @@ import KFModal from '@/components/KFModal'; | |||||
| import { | import { | ||||
| DataSource, | DataSource, | ||||
| ResourceType, | ResourceType, | ||||
| ResourceVersionData, | |||||
| resourceConfig, | resourceConfig, | ||||
| type ResourceData, | type ResourceData, | ||||
| } from '@/pages/Dataset/config'; | } from '@/pages/Dataset/config'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { InfoCircleOutlined } from '@ant-design/icons'; | |||||
| import { Form, Input, ModalProps, Select } from 'antd'; | import { Form, Input, ModalProps, Select } from 'antd'; | ||||
| import { pick } from 'lodash'; | import { pick } from 'lodash'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| @@ -44,7 +42,6 @@ function ExportModelModal({ | |||||
| }: ExportModelModalProps) { | }: ExportModelModalProps) { | ||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [resources, setResources] = useState<ResourceData[]>([]); | const [resources, setResources] = useState<ResourceData[]>([]); | ||||
| const [versions, setVersions] = useState<ResourceVersionData[]>([]); | |||||
| const config = resourceConfig[resourceType]; | const config = resourceConfig[resourceType]; | ||||
| const layout = { | const layout = { | ||||
| @@ -77,35 +74,24 @@ function ExportModelModal({ | |||||
| return undefined; | return undefined; | ||||
| }; | }; | ||||
| // 版本 tooltip | |||||
| const getTooltip = () => { | |||||
| const id = form.getFieldValue('id'); | |||||
| const resource = getSelectedResource(id); | |||||
| const name = resource?.name ?? ''; | |||||
| const versionNames = versions.map((item: ResourceVersionData) => item.name).join('、'); | |||||
| const tooltip = | |||||
| versions.length > 0 ? `${name}有以下版本:\n${versionNames}\n注意不能重复` : undefined; | |||||
| return tooltip; | |||||
| }; | |||||
| // 处理数据集、模型选择变化 | // 处理数据集、模型选择变化 | ||||
| const handleResourceChange = (id: number | undefined) => { | const handleResourceChange = (id: number | undefined) => { | ||||
| if (id) { | if (id) { | ||||
| getRecourceVersions(id); | |||||
| getRecourceNextVersion(id); | |||||
| } else { | } else { | ||||
| setVersions([]); | |||||
| form.setFieldValue('version', ''); | |||||
| } | } | ||||
| }; | }; | ||||
| // 获取数据集、模型版本列表 | |||||
| const getRecourceVersions = async (id: number) => { | |||||
| // 获取数据集、模型下一个版本 | |||||
| const getRecourceNextVersion = async (id: number) => { | |||||
| const resource = getSelectedResource(id); | const resource = getSelectedResource(id); | ||||
| if (!resource) { | if (!resource) { | ||||
| return; | return; | ||||
| } | } | ||||
| const [res] = await to(config.getVersions(pick(resource, ['identifier', 'owner']))); | |||||
| const [res] = await to(config.getNextVersion(pick(resource, ['identifier', 'owner']))); | |||||
| if (res && res.data) { | if (res && res.data) { | ||||
| setVersions(res.data); | |||||
| form.setFieldValue('version', res.data); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -184,15 +170,6 @@ function ExportModelModal({ | |||||
| <Form.Item | <Form.Item | ||||
| label={`${config.name}版本`} | label={`${config.name}版本`} | ||||
| name="version" | name="version" | ||||
| tooltip={ | |||||
| getTooltip() | |||||
| ? { | |||||
| overlayClassName: styles['export-model-modal__tooltip'], | |||||
| title: getTooltip(), | |||||
| icon: <InfoCircleOutlined />, | |||||
| } | |||||
| : undefined | |||||
| } | |||||
| rules={[ | rules={[ | ||||
| { required: true, message: `请输入${config.name}版本` }, | { required: true, message: `请输入${config.name}版本` }, | ||||
| { | { | ||||
| @@ -205,8 +182,6 @@ function ExportModelModal({ | |||||
| return Promise.reject(`${config.name}版本不能为 master`); | return Promise.reject(`${config.name}版本不能为 master`); | ||||
| } else if (value === 'origin') { | } else if (value === 'origin') { | ||||
| return Promise.reject(`${config.name}版本不能为 origin`); | return Promise.reject(`${config.name}版本不能为 origin`); | ||||
| } else if (value && versions.map((item) => item.name).includes(value)) { | |||||
| return Promise.reject(`${config.name}版本已存在`); | |||||
| } else { | } else { | ||||
| return Promise.resolve(); | return Promise.resolve(); | ||||
| } | } | ||||
| @@ -214,7 +189,13 @@ function ExportModelModal({ | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| <Input placeholder={`请输入${config.name}版本`} maxLength={64} showCount allowClear /> | |||||
| <Input | |||||
| placeholder={`请输入${config.name}版本`} | |||||
| maxLength={64} | |||||
| showCount | |||||
| allowClear | |||||
| disabled | |||||
| /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="版本描述" | label="版本描述" | ||||
| @@ -1,6 +1,6 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | ||||
| import { ExperimentStatus, hyperParameterOptimizedMode } from '@/enums'; | import { ExperimentStatus, hyperParameterOptimizedMode } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import ExperimentRunBasic from '@/pages/AutoML/components/ExperimentRunBasic'; | import ExperimentRunBasic from '@/pages/AutoML/components/ExperimentRunBasic'; | ||||
| import { | import { | ||||
| schedulerAlgorithms, | schedulerAlgorithms, | ||||
| @@ -41,7 +41,7 @@ function HyperParameterBasic({ | |||||
| instanceStatus, | instanceStatus, | ||||
| isInstance = false, | isInstance = false, | ||||
| }: HyperParameterBasicProps) { | }: HyperParameterBasicProps) { | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | const basicDatas: BasicInfoData[] = useMemo(() => { | ||||
| if (!info) { | if (!info) { | ||||
| @@ -9,7 +9,7 @@ import PageTitle from '@/components/PageTitle'; | |||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | import SubAreaTitle from '@/components/SubAreaTitle'; | ||||
| import { ServiceRunStatus, serviceStatusOptions } from '@/enums'; | import { ServiceRunStatus, serviceStatusOptions } from '@/enums'; | ||||
| import { useCacheState } from '@/hooks/useCacheState'; | import { useCacheState } from '@/hooks/useCacheState'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { ModelData } from '@/pages/Dataset/config'; | import { ModelData } from '@/pages/Dataset/config'; | ||||
| import { | import { | ||||
| deleteServiceVersionReq, | deleteServiceVersionReq, | ||||
| @@ -89,7 +89,7 @@ function ServiceInfo() { | |||||
| format: formatDate, | format: formatDate, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| // 获取服务详情 | // 获取服务详情 | ||||
| const getServiceInfo = useCallback(async () => { | const getServiceInfo = useCallback(async () => { | ||||
| @@ -1,6 +1,6 @@ | |||||
| import BasicInfo, { type BasicInfoData } from '@/components/BasicInfo'; | import BasicInfo, { type BasicInfoData } from '@/components/BasicInfo'; | ||||
| import { ServiceRunStatus } from '@/enums'; | import { ServiceRunStatus } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { ServiceVersionData } from '@/pages/ModelDeployment/types'; | import { ServiceVersionData } from '@/pages/ModelDeployment/types'; | ||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import { formatMirror, formatModel } from '@/utils/format'; | import { formatMirror, formatModel } from '@/utils/format'; | ||||
| @@ -36,7 +36,7 @@ const formatEnvText = (env?: Record<string, string>) => { | |||||
| }; | }; | ||||
| function VersionBasicInfo({ info }: BasicInfoProps) { | function VersionBasicInfo({ info }: BasicInfoProps) { | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| const datas: BasicInfoData[] = [ | const datas: BasicInfoData[] = [ | ||||
| { | { | ||||
| @@ -1,6 +1,6 @@ | |||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import { ServiceRunStatus } from '@/enums'; | import { ServiceRunStatus } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { useSystemResource } from '@/hooks/useComputingResource'; | |||||
| import { type ServiceVersionData } from '@/pages/ModelDeployment/types'; | import { type ServiceVersionData } from '@/pages/ModelDeployment/types'; | ||||
| import { getServiceVersionCompareReq } from '@/services/modelDeployment'; | import { getServiceVersionCompareReq } from '@/services/modelDeployment'; | ||||
| import { isEmpty } from '@/utils'; | import { isEmpty } from '@/utils'; | ||||
| @@ -42,7 +42,7 @@ const formatEnvText = (env: Record<string, string>) => { | |||||
| function VersionCompareModal({ version1, version2, ...rest }: VersionCompareModalProps) { | function VersionCompareModal({ version1, version2, ...rest }: VersionCompareModalProps) { | ||||
| const [compareData, setCompareData] = useState<CompareData | undefined>(undefined); | const [compareData, setCompareData] = useState<CompareData | undefined>(undefined); | ||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const getResourceDescription = useSystemResource(); | |||||
| const fields: FiledType[] = useMemo( | const fields: FiledType[] = useMemo( | ||||
| () => [ | () => [ | ||||
| @@ -70,15 +70,6 @@ export function createMenuItems( | |||||
| } | } | ||||
| } | } | ||||
| export function getInParameterComponent( | |||||
| parameter: PipelineNodeModelParameter, | |||||
| ): React.ReactNode | null { | |||||
| if (parameter.value) { | |||||
| } | |||||
| return null; | |||||
| } | |||||
| // 判断是否允许输入 | // 判断是否允许输入 | ||||
| export function canInput(parameter: PipelineNodeModelParameter) { | export function canInput(parameter: PipelineNodeModelParameter) { | ||||
| const { type, item_type } = parameter; | const { type, item_type } = parameter; | ||||
| @@ -87,6 +78,9 @@ export function canInput(parameter: PipelineNodeModelParameter) { | |||||
| (item_type === 'dataset' || | (item_type === 'dataset' || | ||||
| item_type === 'model' || | item_type === 'model' || | ||||
| item_type === 'image' || | item_type === 'image' || | ||||
| item_type === 'code') | |||||
| item_type === 'code' || | |||||
| item_type === 'remote-dataset' || | |||||
| item_type === 'remote-model' || | |||||
| item_type === 'remote-code') | |||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,7 +1,10 @@ | |||||
| import CodeSelectorModal, { CodeConfigData } from '@/components/CodeSelectorModal'; | import CodeSelectorModal, { CodeConfigData } from '@/components/CodeSelectorModal'; | ||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import ParameterInput, { requiredValidator } from '@/components/ParameterInput'; | import ParameterInput, { requiredValidator } from '@/components/ParameterInput'; | ||||
| import ParameterSelect, { type ParameterSelectDataType } from '@/components/ParameterSelect'; | |||||
| import ParameterSelect, { | |||||
| type ParameterSelectDataType, | |||||
| type ParameterSelectObject, | |||||
| } from '@/components/ParameterSelect'; | |||||
| import ResourceSelectorModal, { | import ResourceSelectorModal, { | ||||
| ResourceSelectorType, | ResourceSelectorType, | ||||
| selectorTypeConfig, | selectorTypeConfig, | ||||
| @@ -9,6 +12,7 @@ import ResourceSelectorModal, { | |||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | import SubAreaTitle from '@/components/SubAreaTitle'; | ||||
| import { CommonTabKeys, ComponentType } from '@/enums'; | import { CommonTabKeys, ComponentType } from '@/enums'; | ||||
| import { canInput, createMenuItems } from '@/pages/Pipeline/Info/utils'; | import { canInput, createMenuItems } from '@/pages/Pipeline/Info/utils'; | ||||
| import state from '@/state/jcdResource'; | |||||
| import { | import { | ||||
| PipelineGlobalParam, | PipelineGlobalParam, | ||||
| PipelineNodeModel, | PipelineNodeModel, | ||||
| @@ -20,6 +24,7 @@ import { to } from '@/utils/promise'; | |||||
| import { removeFormListItem } from '@/utils/ui'; | import { removeFormListItem } from '@/utils/ui'; | ||||
| import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | ||||
| import { INode } from '@antv/g6'; | import { INode } from '@antv/g6'; | ||||
| import { useSnapshot } from '@umijs/max'; | |||||
| import { Button, Drawer, Flex, Form, Input, MenuProps } from 'antd'; | import { Button, Drawer, Flex, Form, Input, MenuProps } from 'antd'; | ||||
| import { RuleObject } from 'antd/es/form'; | import { RuleObject } from 'antd/es/form'; | ||||
| import { NamePath } from 'antd/es/form/interface'; | import { NamePath } from 'antd/es/form/interface'; | ||||
| @@ -38,6 +43,17 @@ type PipelineNodeParameterProps = { | |||||
| onFormChange: (data: PipelineNodeModelSerialize) => void; | onFormChange: (data: PipelineNodeModelSerialize) => void; | ||||
| }; | }; | ||||
| // 自定义的下拉组件类型 | |||||
| const parameterSelectList = [ | |||||
| 'dataset', | |||||
| 'model', | |||||
| 'service', | |||||
| 'resource', | |||||
| 'remote-resource-type', | |||||
| 'remote-image', | |||||
| 'remote-resource', | |||||
| ]; | |||||
| const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParameterProps, ref) => { | const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParameterProps, ref) => { | ||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [stagingItem, setStagingItem] = useState<PipelineNodeModelSerialize>( | const [stagingItem, setStagingItem] = useState<PipelineNodeModelSerialize>( | ||||
| @@ -45,6 +61,8 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| ); | ); | ||||
| const [open, setOpen] = useState(false); | const [open, setOpen] = useState(false); | ||||
| const [menuItems, setMenuItems] = useState<MenuProps['items']>([]); | const [menuItems, setMenuItems] = useState<MenuProps['items']>([]); | ||||
| const snap = useSnapshot(state); | |||||
| const { setCurrentType } = snap; | |||||
| const afterOpenChange = async () => { | const afterOpenChange = async () => { | ||||
| if (!open) { | if (!open) { | ||||
| @@ -119,6 +137,12 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| // 参数下拉菜单 | // 参数下拉菜单 | ||||
| setMenuItems(createMenuItems(params, parentNodes)); | setMenuItems(createMenuItems(params, parentNodes)); | ||||
| // 云际组件,设置 store 当前资源类型 | |||||
| if (model.id.startsWith('remote-task')) { | |||||
| const resourceType = model.in_parameters['--resource_type'].value; | |||||
| setCurrentType(resourceType); | |||||
| } | |||||
| }, | }, | ||||
| close: () => { | close: () => { | ||||
| onClose(); | onClose(); | ||||
| @@ -136,7 +160,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| } | } | ||||
| }, | }, | ||||
| }), | }), | ||||
| [form, open], | |||||
| [form, open, setCurrentType], | |||||
| ); | ); | ||||
| // ref 类型选择 | // ref 类型选择 | ||||
| @@ -144,7 +168,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| formItemName: NamePath, | formItemName: NamePath, | ||||
| item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>, | item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>, | ||||
| ) => { | ) => { | ||||
| if (item.item_type === 'code') { | |||||
| if (item.item_type === 'code' || item.item_type === 'remote-code') { | |||||
| selectCodeConfig(formItemName, item); | selectCodeConfig(formItemName, item); | ||||
| } else { | } else { | ||||
| selectResource(formItemName, item); | selectResource(formItemName, item); | ||||
| @@ -183,9 +207,11 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| let type: ResourceSelectorType; | let type: ResourceSelectorType; | ||||
| switch (item.item_type) { | switch (item.item_type) { | ||||
| case 'dataset': | case 'dataset': | ||||
| case 'remote-dataset': | |||||
| type = ResourceSelectorType.Dataset; | type = ResourceSelectorType.Dataset; | ||||
| break; | break; | ||||
| case 'model': | case 'model': | ||||
| case 'remote-model': | |||||
| type = ResourceSelectorType.Model; | type = ResourceSelectorType.Model; | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -249,14 +275,14 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| // 获取选择数据集、模型后面按钮 icon | // 获取选择数据集、模型后面按钮 icon | ||||
| const getSelectBtnIcon = (item: { item_type: string }) => { | const getSelectBtnIcon = (item: { item_type: string }) => { | ||||
| const type = item.item_type; | const type = item.item_type; | ||||
| if (type === 'code') { | |||||
| if (type === 'code' || type === 'remote-code') { | |||||
| return <KFIcon type="icon-xuanzedaimapeizhi" />; | return <KFIcon type="icon-xuanzedaimapeizhi" />; | ||||
| } | } | ||||
| let selectorType: ResourceSelectorType; | let selectorType: ResourceSelectorType; | ||||
| if (type === 'dataset') { | |||||
| if (type === 'dataset' || type === 'remote-dataset') { | |||||
| selectorType = ResourceSelectorType.Dataset; | selectorType = ResourceSelectorType.Dataset; | ||||
| } else if (type === 'model') { | |||||
| } else if (type === 'model' || type === 'remote-model') { | |||||
| selectorType = ResourceSelectorType.Model; | selectorType = ResourceSelectorType.Model; | ||||
| } else { | } else { | ||||
| selectorType = ResourceSelectorType.Mirror; | selectorType = ResourceSelectorType.Mirror; | ||||
| @@ -331,6 +357,21 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| return rules; | return rules; | ||||
| }; | }; | ||||
| // 云际组件,选择类型后,重置镜像和资源,获取镜像、资源列表 | |||||
| const handleParameterSelect = ( | |||||
| value: ParameterSelectObject, | |||||
| itemType: string, | |||||
| parentName: string, | |||||
| ) => { | |||||
| if (itemType === 'remote-resource-type') { | |||||
| snap.setCurrentType(value.value); | |||||
| const remoteImage = form.getFieldValue([parentName, '--image']); | |||||
| form.setFieldValue([parentName, '--image'], { ...remoteImage, value: undefined }); | |||||
| const remoteResource = form.getFieldValue([parentName, '--resource']); | |||||
| form.setFieldValue([parentName, '--resource'], { ...remoteResource, value: undefined }); | |||||
| } | |||||
| }; | |||||
| // 表单组件 | // 表单组件 | ||||
| const getFormComponent = ( | const getFormComponent = ( | ||||
| item: { key: string; value: PipelineNodeModelParameter }, | item: { key: string; value: PipelineNodeModelParameter }, | ||||
| @@ -361,12 +402,18 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete | |||||
| </Flex> | </Flex> | ||||
| )} | )} | ||||
| {item.value.type === ComponentType.Select && | {item.value.type === ComponentType.Select && | ||||
| (['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? ( | |||||
| (parameterSelectList.includes(item.value.item_type) ? ( | |||||
| <Form.Item name={[parentName, item.key]} rules={getFormRules(item)} noStyle> | <Form.Item name={[parentName, item.key]} rules={getFormRules(item)} noStyle> | ||||
| <ParameterSelect | <ParameterSelect | ||||
| isPipeline | |||||
| dataType={item.value.item_type as ParameterSelectDataType} | dataType={item.value.item_type as ParameterSelectDataType} | ||||
| placeholder={item.value.placeholder} | placeholder={item.value.placeholder} | ||||
| onChange={(value) => | |||||
| handleParameterSelect( | |||||
| value as ParameterSelectObject, | |||||
| item.value.item_type, | |||||
| parentName, | |||||
| ) | |||||
| } | |||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| ) : null)} | ) : null)} | ||||
| @@ -90,6 +90,15 @@ export function compareDatasetVersion(data) { | |||||
| }); | }); | ||||
| } | } | ||||
| // 获取数据集下个版本号 | |||||
| export function getDatasetNextVersionReq(data) { | |||||
| return request(`/api/mmp/newdataset/queryNextVersion`, { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // ----------------------------模型--------------------------------- | // ----------------------------模型--------------------------------- | ||||
| // 分页查询模型列表 | // 分页查询模型列表 | ||||
| @@ -157,6 +166,14 @@ export function deleteModelVersion(params) { | |||||
| }); | }); | ||||
| } | } | ||||
| // 获取模型下个版本号 | |||||
| export function getModelNextVersionReq(data) { | |||||
| return request(`/api/mmp/newmodel/queryNextVersion`, { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // 获取模型依赖 | // 获取模型依赖 | ||||
| export function getModelAtlasReq(params) { | export function getModelAtlasReq(params) { | ||||
| return request(`/api/mmp/newmodel/getModelDependencyTree`, { | return request(`/api/mmp/newmodel/getModelDependencyTree`, { | ||||
| @@ -218,4 +235,5 @@ export function unpraiseResourceReq(id) { | |||||
| return request(`/api/mmp/newmodel/unpraise/${id}`, { | return request(`/api/mmp/newmodel/unpraise/${id}`, { | ||||
| method: 'DELETE', | method: 'DELETE', | ||||
| }); | }); | ||||
| } | |||||
| } | |||||
| @@ -0,0 +1,87 @@ | |||||
| // 外部系统 | |||||
| import { request } from '@umijs/max'; | |||||
| // 云际系统登录 | |||||
| export function jccLoginReq() { | |||||
| return request(`http://119.45.255.234:30180/jcc-admin/admin/login`, { | |||||
| method: 'POST', | |||||
| data: { | |||||
| username: 'iflytek', | |||||
| password: 'iflytek@123', | |||||
| }, | |||||
| headers: { | |||||
| isToken: false, | |||||
| }, | |||||
| skipLoading: true, | |||||
| skipValidating: true, | |||||
| }); | |||||
| } | |||||
| // 云际系统获取资源类型 | |||||
| export function jccGetResourceTypesReq(token: string, userId: number) { | |||||
| return request(`http://119.45.255.234:30180/jsm/jobSet/resourceRange`, { | |||||
| method: 'POST', | |||||
| data: { | |||||
| userID: userId, | |||||
| }, | |||||
| headers: { | |||||
| authorization: `${token}`, | |||||
| isToken: false, | |||||
| }, | |||||
| skipLoading: true, | |||||
| skipValidating: true, | |||||
| }); | |||||
| } | |||||
| // 云际系统获取资源镜像 | |||||
| export function jccGetImagesReq(token: string, cardTypes: string[]) { | |||||
| return request(`http://119.45.255.234:30180/jsm/jobSet/queryImages`, { | |||||
| method: 'POST', | |||||
| data: { | |||||
| cardTypes: cardTypes, | |||||
| }, | |||||
| headers: { | |||||
| authorization: `${token}`, | |||||
| isToken: false, | |||||
| }, | |||||
| skipLoading: true, | |||||
| skipValidating: true, | |||||
| }); | |||||
| } | |||||
| // 云际系统获取资源列表 | |||||
| export function jccGetResourcesReq(token: string, cardType: string) { | |||||
| return request(`http://119.45.255.234:30180/jsm/jobSet/queryResource`, { | |||||
| method: 'POST', | |||||
| data: { | |||||
| queryResource: { | |||||
| cpu: { | |||||
| min: 0, | |||||
| max: 0, | |||||
| }, | |||||
| memory: { | |||||
| min: 0, | |||||
| max: 0, | |||||
| }, | |||||
| gpu: { | |||||
| min: 0, | |||||
| max: 0, | |||||
| }, | |||||
| storage: { | |||||
| min: 0, | |||||
| max: 0, | |||||
| }, | |||||
| type: cardType, | |||||
| }, | |||||
| resourceType: 'Train', | |||||
| clusterIDs: ['1865927992266461184', ''], | |||||
| }, | |||||
| headers: { | |||||
| authorization: `${token}`, | |||||
| isToken: false, | |||||
| }, | |||||
| skipLoading: true, | |||||
| skipValidating: true, | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,140 @@ | |||||
| import { | |||||
| jccGetImagesReq, | |||||
| jccGetResourcesReq, | |||||
| jccGetResourceTypesReq, | |||||
| jccLoginReq, | |||||
| } from '@/services/external'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { proxy } from '@umijs/max'; | |||||
| export type JCCResourceRange = { | |||||
| type: string; | |||||
| }; | |||||
| export type JCCResourceType = { | |||||
| label: string; | |||||
| value: string; | |||||
| }; | |||||
| export interface JCCResourceImage { | |||||
| imageID: number; | |||||
| name: string; | |||||
| createTime: Date; | |||||
| clusterImages: JCCClusterImage[]; | |||||
| } | |||||
| export interface JCCClusterImage { | |||||
| imageID: number; | |||||
| clusterID: string; | |||||
| originImageType: string; | |||||
| originImageID: string; | |||||
| originImageName: string; | |||||
| cards: JCCCard[]; | |||||
| } | |||||
| export interface JCCCard { | |||||
| originImageID: string; | |||||
| card: string; | |||||
| } | |||||
| export interface JCCResourceStandard { | |||||
| id: number; | |||||
| sourceKey: string; | |||||
| type: string; | |||||
| name: string; | |||||
| totalCount: number; | |||||
| availableCount: number; | |||||
| changeType: number; | |||||
| status: number; | |||||
| region: string; | |||||
| clusterId: string; | |||||
| costPerUnit: number; | |||||
| costType: string; | |||||
| tag: string; | |||||
| userId: number; | |||||
| createTime: Date; | |||||
| updateTime: Date; | |||||
| baseResourceSpecs: JCCBaseResourceSpec[]; | |||||
| } | |||||
| export interface JCCBaseResourceSpec { | |||||
| id: number; | |||||
| resourceSpecId: number; | |||||
| type: string; | |||||
| name: string; | |||||
| totalValue: number; | |||||
| totalUnit: string; | |||||
| availableValue: number; | |||||
| availableUnit: string; | |||||
| userId: number; | |||||
| createTime: Date; | |||||
| updateTime: Date; | |||||
| } | |||||
| type JCCResourceTypeStore = { | |||||
| token: string; | |||||
| types: JCCResourceType[]; | |||||
| images: JCCResourceImage[]; | |||||
| resources: JCCResourceStandard[]; | |||||
| currentType: string | undefined | null; | |||||
| jccLogin: () => void; | |||||
| getResourceTypes: () => void; | |||||
| getImages: (cardTypes: string[]) => void; | |||||
| getResources: (cardType: string) => void; | |||||
| setCurrentType: (cardType: string) => void; | |||||
| }; | |||||
| const state = proxy<JCCResourceTypeStore>({ | |||||
| token: '', | |||||
| types: [], | |||||
| images: [], | |||||
| resources: [], | |||||
| currentType: undefined, | |||||
| jccLogin: async () => { | |||||
| const [res] = await to(jccLoginReq()); | |||||
| if (res && res.code === 200 && res.data) { | |||||
| const { tokenHead, token } = res.data; | |||||
| state.token = tokenHead + token; | |||||
| } | |||||
| }, | |||||
| getResourceTypes: async () => { | |||||
| const [loginRes] = await to(jccLoginReq()); | |||||
| if (loginRes && loginRes.code === 200 && loginRes.data) { | |||||
| const { tokenHead, token, jsmUserInfo } = loginRes.data; | |||||
| state.token = tokenHead + token; | |||||
| const userID = jsmUserInfo?.data?.userID; | |||||
| const [res] = await to(jccGetResourceTypesReq(tokenHead + token, userID)); | |||||
| if (res && res.code === 'OK' && res.data) { | |||||
| state.types = res.data.resourceRanges?.map((v: JCCResourceRange) => ({ | |||||
| label: v.type, | |||||
| value: v.type, | |||||
| })); | |||||
| } | |||||
| } | |||||
| }, | |||||
| getImages: async (cardTypes: string[]) => { | |||||
| const [res] = await to(jccGetImagesReq(state.token, cardTypes)); | |||||
| if (res && res.code === 'OK' && res.data) { | |||||
| state.images = res.data.images; | |||||
| } | |||||
| }, | |||||
| getResources: async (cardType: string) => { | |||||
| const [res] = await to(jccGetResourcesReq(state.token, cardType)); | |||||
| if (res && res.code === 'OK' && res.data) { | |||||
| state.resources = res.data.resource; | |||||
| } | |||||
| }, | |||||
| setCurrentType: (cardType: string | undefined | null) => { | |||||
| if (state.currentType !== cardType) { | |||||
| state.currentType = cardType; | |||||
| state.images = []; | |||||
| state.resources = []; | |||||
| if (cardType) { | |||||
| state.getImages([cardType]); | |||||
| state.getResources(cardType); | |||||
| } | |||||
| } | |||||
| }, | |||||
| }); | |||||
| export default state; | |||||
| @@ -0,0 +1,53 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-10-10 08:51:41 | |||||
| * @Description: 资源规格 | |||||
| */ | |||||
| import { getComputingResourceReq } from '@/services/pipeline'; | |||||
| import { ComputingResource } from '@/types'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { proxy } from '@umijs/max'; | |||||
| import { type SelectProps } from 'antd'; | |||||
| /** 过滤资源规格 */ | |||||
| export const filterResourceStandard: SelectProps<string, ComputingResource>['filterOption'] = ( | |||||
| input: string, | |||||
| option?: ComputingResource, | |||||
| ) => { | |||||
| return ( | |||||
| option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false | |||||
| ); | |||||
| }; | |||||
| /** 资源规格字段 */ | |||||
| export const resourceFieldNames = { | |||||
| label: 'description', | |||||
| value: 'id', | |||||
| }; | |||||
| export interface SystemResourceStore { | |||||
| resources: ComputingResource[]; | |||||
| } | |||||
| const state = proxy<SystemResourceStore>({ | |||||
| resources: [], | |||||
| }); | |||||
| /** 获取资源列表 */ | |||||
| export const getSystemResources = async () => { | |||||
| if (state.resources.length > 0) { | |||||
| return; | |||||
| } | |||||
| const params = { | |||||
| page: 0, | |||||
| size: 1000, | |||||
| resource_type: '', | |||||
| }; | |||||
| const [res] = await to(getComputingResourceReq(params)); | |||||
| if (res && res.data && Array.isArray(res.data.content)) { | |||||
| state.resources = res.data.content; | |||||
| } | |||||
| }; | |||||
| export default state; | |||||
| @@ -13,6 +13,8 @@ export default class SessionStorage { | |||||
| static readonly aimUrlKey = 'aim-url'; | static readonly aimUrlKey = 'aim-url'; | ||||
| /** tensorBoard url */ | /** tensorBoard url */ | ||||
| static readonly tensorBoardUrlKey = 'tensor-board-url'; | static readonly tensorBoardUrlKey = 'tensor-board-url'; | ||||
| // /** 云际系统 Token */ | |||||
| // static readonly jccTokenKey = 'jcc-token'; | |||||
| /** | /** | ||||
| * 获取 SessionStorage 值 | * 获取 SessionStorage 值 | ||||