| @@ -1,4 +1,3 @@ | |||
| import { AvailableRange } from '@/enums'; | |||
| import { type CodeConfigData } from '@/pages/CodeConfig/List'; | |||
| import { Flex, Typography } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| @@ -24,12 +23,12 @@ function CodeConfigItem({ item, onClick }: CodeConfigItemProps) { | |||
| <div | |||
| className={classNames( | |||
| styles['code-config-item__tag'], | |||
| item.code_repo_vis === AvailableRange.Public | |||
| item.is_public | |||
| ? styles['code-config-item__tag--public'] | |||
| : styles['code-config-item__tag--private'], | |||
| )} | |||
| > | |||
| {item.code_repo_vis === AvailableRange.Public ? '公开' : '私有'} | |||
| {item.is_public ? '公开' : '私有'} | |||
| </div> | |||
| </Flex> | |||
| <Typography.Paragraph | |||
| @@ -39,9 +39,9 @@ export enum TensorBoardStatus { | |||
| // 镜像版本状态 | |||
| export enum MirrorVersionStatus { | |||
| Available = 'available', // 可用 | |||
| Building = 'building', // 构建中 | |||
| Failed = 'failed', // 构建中 | |||
| Available = 'Available', // 可用 | |||
| Building = 'Building', // 构建中 | |||
| Failed = 'Failed', // 失败 | |||
| } | |||
| // 服务运行状态 | |||
| @@ -334,7 +334,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||
| dataIndex: 'update_time', | |||
| key: 'update_time', | |||
| width: '20%', | |||
| render: tableCellRender(false, TableCellValueType.Date), | |||
| render: tableCellRender(true, TableCellValueType.Date), | |||
| }, | |||
| { | |||
| title: '最近五次运行状态', | |||
| @@ -22,7 +22,7 @@ import styles from './index.less'; | |||
| export type CodeConfigData = { | |||
| id: number; | |||
| code_repo_name: string; | |||
| code_repo_vis: number; | |||
| is_public: boolean; | |||
| git_url: string; | |||
| git_branch: string; | |||
| git_user_name: string; | |||
| @@ -1,5 +1,4 @@ | |||
| import KFModal from '@/components/KFModal'; | |||
| import { AvailableRange } from '@/enums'; | |||
| import { type CodeConfigData } from '@/pages/CodeConfig/List'; | |||
| import { addCodeConfigReq, updateCodeConfigReq } from '@/services/codeConfig'; | |||
| import { to } from '@/utils/promise'; | |||
| @@ -27,7 +26,7 @@ interface AddCodeConfigModalProps extends Omit<ModalProps, 'onOk'> { | |||
| function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeConfigModalProps) { | |||
| const [form] = Form.useForm(); | |||
| const isPublic = Form.useWatch('code_repo_vis', form) === AvailableRange.Public; | |||
| const isPublic = Form.useWatch('is_public', form) as boolean; | |||
| const urlExample = useMemo( | |||
| () => | |||
| @@ -57,7 +56,7 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo | |||
| ...formData, | |||
| }; | |||
| // 清除多余的信息 | |||
| if (formData.code_repo_vis === AvailableRange.Public) { | |||
| if (formData.is_public) { | |||
| omit(params, ['verify_mode', 'git_user_name', 'git_password', 'ssh_key']); | |||
| } | |||
| if (formData.verify_mode === VerifyMode.Password) { | |||
| @@ -83,7 +82,7 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo | |||
| // 设置初始值 | |||
| const initialValues: FormData = codeConfigData ?? { | |||
| code_repo_vis: AvailableRange.Public, | |||
| is_public: true, | |||
| verify_mode: VerifyMode.Password, | |||
| }; | |||
| if (initialValues.verify_mode === undefined || initialValues.verify_mode === null) { | |||
| @@ -125,7 +124,7 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo | |||
| </Form.Item> | |||
| <Form.Item | |||
| label="代码仓库可见性" | |||
| name="code_repo_vis" | |||
| name="is_public" | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| @@ -134,8 +133,8 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo | |||
| ]} | |||
| > | |||
| <Radio.Group> | |||
| <Radio value={AvailableRange.Public}>公开</Radio> | |||
| <Radio value={AvailableRange.Private}>私有</Radio> | |||
| <Radio value={true}>公开</Radio> | |||
| <Radio value={false}>私有</Radio> | |||
| </Radio.Group> | |||
| </Form.Item> | |||
| <Form.Item | |||
| @@ -171,11 +170,11 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo | |||
| <Form.Item | |||
| noStyle | |||
| shouldUpdate={(prevValues, currentValues) => | |||
| prevValues?.code_repo_vis !== currentValues?.code_repo_vis | |||
| prevValues?.is_public !== currentValues?.is_public | |||
| } | |||
| > | |||
| {({ getFieldValue }) => { | |||
| return getFieldValue('code_repo_vis') === AvailableRange.Private ? ( | |||
| return getFieldValue('is_public') === false ? ( | |||
| <> | |||
| <Form.Item | |||
| label="验证方式" | |||
| @@ -1,7 +1,6 @@ | |||
| import clock from '@/assets/img/clock.png'; | |||
| import creatByImg from '@/assets/img/creatBy.png'; | |||
| import KFIcon from '@/components/KFIcon'; | |||
| import { AvailableRange } from '@/enums'; | |||
| import { type CodeConfigData } from '@/pages/CodeConfig/List'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { Button, Flex, Typography } from 'antd'; | |||
| @@ -33,12 +32,12 @@ function CodeConfigItem({ item, onClick, onEdit, onRemove }: CodeConfigItemProps | |||
| <div | |||
| className={classNames( | |||
| styles['code-config-item__tag'], | |||
| item.code_repo_vis === AvailableRange.Public | |||
| item.is_public | |||
| ? styles['code-config-item__tag--public'] | |||
| : styles['code-config-item__tag--private'], | |||
| )} | |||
| > | |||
| {item.code_repo_vis === AvailableRange.Public ? '公开' : '私有'} | |||
| {item.is_public ? '公开' : '私有'} | |||
| </div> | |||
| <Button | |||
| type="text" | |||
| @@ -28,9 +28,29 @@ | |||
| border-radius: 4px; | |||
| } | |||
| &__praise { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| width: 70px; | |||
| height: 28px; | |||
| margin-left: auto; | |||
| color: @text-color-tertiary; | |||
| font-size: 13px; | |||
| background: #ffffff; | |||
| border: 1px solid rgba(22, 100, 255, 0.11); | |||
| border-radius: 4px; | |||
| cursor: pointer; | |||
| &--praised { | |||
| color: @primary-color; | |||
| } | |||
| } | |||
| :global { | |||
| .ant-btn-dangerous { | |||
| background-color: transparent !important; | |||
| background-color: .addAlpha(@error-color, 0.06) [] !important; | |||
| border-color: .addAlpha(@error-color, 0.11) [] !important; | |||
| } | |||
| } | |||
| } | |||
| @@ -13,12 +13,14 @@ import { | |||
| } from '@/pages/Dataset/config'; | |||
| import GraphLegend from '@/pages/Model/components/GraphLegend'; | |||
| import ModelEvolution from '@/pages/Model/components/ModelEvolution'; | |||
| import { praiseResourceReq, unpraiseResourceReq } from '@/services/dataset'; | |||
| import { VersionChangedMessage } from '@/utils/constant'; | |||
| import { openAntdModal } from '@/utils/modal'; | |||
| 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 classNames from 'classnames'; | |||
| import { useCallback, useEffect, useState } from 'react'; | |||
| import AddVersionModal from '../AddVersionModal'; | |||
| import ResourceIntro from '../ResourceIntro'; | |||
| @@ -189,6 +191,20 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||
| }); | |||
| }; | |||
| // 处理点赞 | |||
| const handlePraise = async () => { | |||
| const request = info.praised === true ? unpraiseResourceReq : praiseResourceReq; | |||
| const [res] = await to(request(info.id)); | |||
| if (res) { | |||
| message.success('操作成功'); | |||
| setInfo({ | |||
| ...info, | |||
| praised: !info.praised, | |||
| praises_count: info.praised ? info.praises_count - 1 : info.praises_count + 1, | |||
| }); | |||
| } | |||
| }; | |||
| const items = [ | |||
| { | |||
| key: ResourceInfoTabKeys.Introduction, | |||
| @@ -248,6 +264,19 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||
| {(info[tagPropertyName] as string) || '--'} | |||
| </div> | |||
| )} | |||
| <div | |||
| className={classNames(styles['resource-info__top__praise'], { | |||
| [styles['resource-info__top__praise--praised']]: info.praised, | |||
| })} | |||
| onClick={handlePraise} | |||
| > | |||
| <KFIcon | |||
| type={info.praised ? 'icon-dianzanhou' : 'icon-dianzan'} | |||
| font={16} | |||
| style={{ marginRight: '3px' }} | |||
| /> | |||
| <span>{info.praises_count}</span> | |||
| </div> | |||
| </Flex> | |||
| <Flex align="center"> | |||
| <span style={{ marginRight: '10px' }}>版本号:</span> | |||
| @@ -262,12 +291,17 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { | |||
| <Button type="default" onClick={showModal} icon={<KFIcon type="icon-xinjian2" />}> | |||
| 创建新版本 | |||
| </Button> | |||
| <Button type="default" style={{ marginLeft: '20px' }} onClick={showVersionSelector}> | |||
| <Button | |||
| type="default" | |||
| style={{ marginLeft: '20px' }} | |||
| icon={<KFIcon type="icon-banbenduibi" />} | |||
| onClick={showVersionSelector} | |||
| > | |||
| 版本对比 | |||
| </Button> | |||
| <Button | |||
| type="default" | |||
| style={{ marginLeft: 'auto', marginRight: 0 }} | |||
| style={{ marginLeft: '20px' }} | |||
| onClick={handleDelete} | |||
| icon={<KFIcon type="icon-shanchu" />} | |||
| disabled={!version} | |||
| @@ -7,12 +7,18 @@ | |||
| border-radius: 4px; | |||
| cursor: pointer; | |||
| @media screen and (max-width: 1860px) { | |||
| @media screen and (max-width: 1860px) and (min-width: 1601px) { | |||
| & { | |||
| width: calc(33.33% - 13.33px); | |||
| } | |||
| } | |||
| @media screen and (max-width: 1600px) { | |||
| & { | |||
| width: calc(50% - 10px); | |||
| } | |||
| } | |||
| &:hover { | |||
| border-color: @primary-color; | |||
| box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1); | |||
| @@ -56,8 +62,19 @@ | |||
| &__time { | |||
| display: flex; | |||
| align-items: center; | |||
| color: #808080; | |||
| font-size: 13px; | |||
| min-width: 0; | |||
| color: @text-color-tertiary; | |||
| font-size: 13px; | |||
| &__separator { | |||
| width: 1px; | |||
| height: 9px; | |||
| margin: 0 8px; | |||
| background-color: rgba(205, 206, 209, 0.5); | |||
| } | |||
| &__praise { | |||
| margin-left: 4px; | |||
| } | |||
| } | |||
| } | |||
| @@ -14,9 +14,9 @@ type ResourceItemProps = { | |||
| }; | |||
| function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) { | |||
| const timeAgo = | |||
| '最近更新: ' + | |||
| (item.update_time ? formatDate(item.update_time, 'YYYY-MM-DD') : item.time_ago ?? ''); | |||
| const timeAgo = `更新于${ | |||
| item.update_time ? formatDate(item.update_time, 'YYYY-MM-DD') : item.time_ago ?? '' | |||
| }`; | |||
| const create_by = item.create_by ?? ''; | |||
| return ( | |||
| <div className={styles['resource-item']} onClick={() => onClick(item)}> | |||
| @@ -54,6 +54,9 @@ function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) | |||
| <div className={styles['resource-item__time']}> | |||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} draggable={false} alt="" /> | |||
| <Typography.Text ellipsis={{ tooltip: timeAgo }}>{timeAgo}</Typography.Text> | |||
| <div className={styles['resource-item__time__separator']}></div> | |||
| <KFIcon type="icon-dianzan" font={16} /> | |||
| <div className={styles['resource-item__time__praise']}>{item.praises_count}</div> | |||
| </div> | |||
| </Flex> | |||
| </div> | |||
| @@ -162,6 +162,8 @@ export interface ResourceData { | |||
| usage?: string; | |||
| relative_paths?: string; | |||
| train_task?: TrainTask; // 训练任务 | |||
| praises_count: number; // 点赞数 | |||
| praised: boolean; // 是否点赞 | |||
| } | |||
| // 数据集数据 | |||
| @@ -185,7 +185,7 @@ function EditorList() { | |||
| title: '编辑器名称', | |||
| dataIndex: 'name', | |||
| key: 'name', | |||
| width: '20%', | |||
| width: '16%', | |||
| render: (text, record, index) => | |||
| record.url && record.status === DevEditorStatus.Running | |||
| ? tableCellRender<EditorData>(true, TableCellValueType.Link, { | |||
| @@ -197,14 +197,14 @@ function EditorList() { | |||
| title: '计算资源', | |||
| dataIndex: 'computing_resource', | |||
| key: 'computing_resource', | |||
| width: 100, | |||
| width: '12%', | |||
| render: tableCellRender(), | |||
| }, | |||
| { | |||
| title: '资源规格', | |||
| dataIndex: 'computing_resource_id', | |||
| key: 'computing_resource_id', | |||
| width: '20%', | |||
| width: '12%', | |||
| render: tableCellRender(true, TableCellValueType.Custom, { | |||
| format: getResourceDescription, | |||
| }), | |||
| @@ -213,36 +213,36 @@ function EditorList() { | |||
| title: '数据集', | |||
| dataIndex: ['dataset', 'showValue'], | |||
| key: 'dataset', | |||
| width: '15%', | |||
| width: '12%', | |||
| render: tableCellRender(true), | |||
| }, | |||
| { | |||
| title: '模型', | |||
| dataIndex: ['model', 'showValue'], | |||
| key: 'model', | |||
| width: '15%', | |||
| width: '12%', | |||
| render: tableCellRender(true), | |||
| }, | |||
| { | |||
| title: '镜像', | |||
| dataIndex: ['image', 'showValue'], | |||
| key: 'image', | |||
| width: '15%', | |||
| width: '12%', | |||
| render: tableCellRender(true), | |||
| }, | |||
| { | |||
| title: '创建者', | |||
| dataIndex: 'update_by', | |||
| key: 'update_by', | |||
| width: '15%', | |||
| width: '12%', | |||
| render: tableCellRender(true), | |||
| }, | |||
| { | |||
| title: '创建时间', | |||
| dataIndex: 'create_time', | |||
| key: 'create_time', | |||
| width: 180, | |||
| render: tableCellRender(false, TableCellValueType.Date), | |||
| width: '12%', | |||
| render: tableCellRender(true, TableCellValueType.Date), | |||
| }, | |||
| { | |||
| title: '状态', | |||
| @@ -254,7 +254,7 @@ function EditorList() { | |||
| { | |||
| title: '操作', | |||
| dataIndex: 'operation', | |||
| width: 300, | |||
| width: 270, | |||
| key: 'operation', | |||
| render: (_: any, record: EditorData) => ( | |||
| <div> | |||
| @@ -280,7 +280,7 @@ function EditorList() { | |||
| 启动 | |||
| </Button> | |||
| )} | |||
| {record.status === DevEditorStatus.Running ? ( | |||
| {record.status !== DevEditorStatus.Running ? ( | |||
| <Button | |||
| type="link" | |||
| size="small" | |||
| @@ -187,3 +187,18 @@ export function deleteUploadFileReq(params) { | |||
| params, | |||
| }); | |||
| } | |||
| // 点赞 | |||
| export function praiseResourceReq(id) { | |||
| return request(`/api/mmp/newmodel/praise/${id}`, { | |||
| method: 'POST', | |||
| }); | |||
| } | |||
| // 取消点赞 | |||
| export function unpraiseResourceReq(id) { | |||
| return request(`/api/mmp/newmodel/unpraise/${id}`, { | |||
| method: 'DELETE', | |||
| }); | |||
| } | |||
| @@ -165,12 +165,12 @@ function CodeConfigItem({ item, onClick }: CodeConfigItemProps) { | |||
| <div | |||
| className={classNames( | |||
| styles['code-config-item__tag'], | |||
| item.code_repo_vis === AvailableRange.Public | |||
| item.is_public | |||
| ? styles['code-config-item__tag--public'] | |||
| : styles['code-config-item__tag--private'], | |||
| )} | |||
| > | |||
| {item.code_repo_vis === AvailableRange.Public ? '公开' : '私有'} | |||
| {item.is_public ? '公开' : '私有'} | |||
| </div> | |||
| </Flex> | |||
| <Typography.Paragraph | |||
| @@ -450,7 +450,7 @@ export const codeListData = { | |||
| { | |||
| id: 2, | |||
| code_repo_name: '介电材料代码', | |||
| code_repo_vis: 1, | |||
| is_public: true, | |||
| git_url: 'https://gitlink.org.cn/fuli/ML_for_Materials.git', | |||
| git_branch: 'master', | |||
| verify_mode: null, | |||
| @@ -466,7 +466,7 @@ export const codeListData = { | |||
| { | |||
| id: 3, | |||
| code_repo_name: '生物活性材料代码', | |||
| code_repo_vis: 1, | |||
| is_public: true, | |||
| git_url: 'https://gitlink.org.cn/zhaoyihan/test_mole_pre.git', | |||
| git_branch: 'parse_dataset', | |||
| verify_mode: null, | |||
| @@ -482,7 +482,7 @@ export const codeListData = { | |||
| { | |||
| id: 4, | |||
| code_repo_name: '数据处理', | |||
| code_repo_vis: 1, | |||
| is_public: true, | |||
| git_url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||
| git_branch: 'train_ci_test', | |||
| verify_mode: null, | |||
| @@ -498,7 +498,7 @@ export const codeListData = { | |||
| { | |||
| id: 5, | |||
| code_repo_name: '手写体识别部署', | |||
| code_repo_vis: 1, | |||
| is_public: true, | |||
| git_url: 'https://gitlink.org.cn/somunslotus/mnist-inference.git', | |||
| git_branch: 'master', | |||
| verify_mode: null, | |||
| @@ -514,7 +514,7 @@ export const codeListData = { | |||
| { | |||
| id: 7, | |||
| code_repo_name: '手写体识别训练', | |||
| code_repo_vis: 1, | |||
| is_public: true, | |||
| git_url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||
| git_branch: 'train_ci_test', | |||
| verify_mode: null, | |||