| @@ -0,0 +1,7 @@ | |||||
| .kf-confirm-modal { | |||||
| &__content { | |||||
| width: 100%; | |||||
| font-size: 18px; | |||||
| text-align: center; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-10-10 10:54:25 | |||||
| * @Description: 自定义 Confirm Modal | |||||
| */ | |||||
| import classNames from 'classnames'; | |||||
| import KFModal, { KFModalProps } from '../KFModal'; | |||||
| import './index.less'; | |||||
| export interface KFConfirmModalProps extends KFModalProps { | |||||
| content: string; | |||||
| } | |||||
| function KFConfirmModal({ | |||||
| title, | |||||
| image, | |||||
| className = '', | |||||
| centered, | |||||
| maskClosable, | |||||
| content, | |||||
| ...rest | |||||
| }: KFConfirmModalProps) { | |||||
| return ( | |||||
| <KFModal | |||||
| className={classNames(['kf-confirm-modal', className])} | |||||
| {...rest} | |||||
| centered={centered ?? true} | |||||
| maskClosable={maskClosable ?? false} | |||||
| title={title} | |||||
| image={image ?? require('@/assets/img/edit-experiment.png')} | |||||
| > | |||||
| <div className="kf-confirm-modal__content">{content}</div> | |||||
| </KFModal> | |||||
| ); | |||||
| } | |||||
| export default KFConfirmModal; | |||||
| @@ -80,7 +80,7 @@ export enum ServiceType { | |||||
| export const serviceTypeOptions = [ | export const serviceTypeOptions = [ | ||||
| { label: '视频', value: ServiceType.Video }, | { label: '视频', value: ServiceType.Video }, | ||||
| { label: '图像', value: ServiceType.Image }, | |||||
| { label: '图片', value: ServiceType.Image }, | |||||
| { label: '音频', value: ServiceType.Audio }, | { label: '音频', value: ServiceType.Audio }, | ||||
| { label: '文本', value: ServiceType.Text }, | { label: '文本', value: ServiceType.Text }, | ||||
| ]; | ]; | ||||
| @@ -1,6 +1,7 @@ | |||||
| import KFEmpty, { EmptyType } from '@/components/KFEmpty'; | import KFEmpty, { EmptyType } from '@/components/KFEmpty'; | ||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig'; | import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig'; | ||||
| import { getGitUrl } from '@/utils'; | |||||
| import { openAntdModal } from '@/utils/modal'; | 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'; | ||||
| @@ -99,6 +100,13 @@ function CodeConfigList() { | |||||
| }); | }); | ||||
| }; | }; | ||||
| // 查看 | |||||
| const handleClick = (record: CodeConfigData) => { | |||||
| const { git_url, git_branch } = record; | |||||
| const url = getGitUrl(git_url, git_branch); | |||||
| window.open(url, '_blank'); | |||||
| }; | |||||
| // 新建 | // 新建 | ||||
| const createCodeConfig = () => { | const createCodeConfig = () => { | ||||
| const { close } = openAntdModal(AddCodeConfigModal, { | const { close } = openAntdModal(AddCodeConfigModal, { | ||||
| @@ -152,6 +160,7 @@ function CodeConfigList() { | |||||
| key={item.id} | key={item.id} | ||||
| onRemove={handleRemove} | onRemove={handleRemove} | ||||
| onEdit={handleEdit} | onEdit={handleEdit} | ||||
| onClick={handleClick} | |||||
| /> | /> | ||||
| ))} | ))} | ||||
| </div> | </div> | ||||
| @@ -123,7 +123,7 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^[a-zA-Z0-9._-]+$/, | pattern: /^[a-zA-Z0-9._-]+$/, | ||||
| message: '版本只支持字母、数字、下划线、点、横杠', | |||||
| message: '版本只支持字母、数字、点、下划线、中横线', | |||||
| }, | }, | ||||
| { | { | ||||
| validator: (_rule, value) => { | validator: (_rule, value) => { | ||||
| @@ -108,7 +108,7 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^[a-zA-Z0-9._-]+$/, | pattern: /^[a-zA-Z0-9._-]+$/, | ||||
| message: '版本只支持字母、数字、下划线、点、横杠', | |||||
| message: '版本只支持字母、数字、点、下划线、中横线', | |||||
| }, | }, | ||||
| { | { | ||||
| validator: (_rule, value) => { | validator: (_rule, value) => { | ||||
| @@ -123,7 +123,7 @@ function AddVersionModal({ | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^[a-zA-Z0-9._-]+$/, | pattern: /^[a-zA-Z0-9._-]+$/, | ||||
| message: '版本只支持字母、数字、下划线、点、横杠', | |||||
| message: '版本只支持字母、数字、点、下划线、中横线', | |||||
| }, | }, | ||||
| { | { | ||||
| validator: (_rule, value) => { | validator: (_rule, value) => { | ||||
| @@ -9,6 +9,7 @@ import { | |||||
| ResourceType, | ResourceType, | ||||
| TrainTask, | TrainTask, | ||||
| } from '@/pages/Dataset/config'; | } from '@/pages/Dataset/config'; | ||||
| import { getGitUrl } from '@/utils'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ResourceIntroProps = { | type ResourceIntroProps = { | ||||
| @@ -54,9 +55,7 @@ const getProjectUrl = (project?: ProjectDependency) => { | |||||
| return undefined; | return undefined; | ||||
| } | } | ||||
| const { url, branch } = project; | const { url, branch } = project; | ||||
| if (url.endsWith('.git')) { | |||||
| return `${url.substring(0, url.length - 4)}/tree/${branch}`; | |||||
| } | |||||
| return getGitUrl(url, branch); | |||||
| }; | }; | ||||
| const formatProject = (project?: ProjectDependency) => { | const formatProject = (project?: ProjectDependency) => { | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; | import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; | ||||
| import { getGitUrl } from '@/utils'; | |||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import { useNavigate } from '@umijs/max'; | import { useNavigate } from '@umijs/max'; | ||||
| import { ModelDepsData, NodeType, ProjectDependency, TrainDataset } from '../ModelEvolution/utils'; | import { ModelDepsData, NodeType, ProjectDependency, TrainDataset } from '../ModelEvolution/utils'; | ||||
| @@ -127,10 +128,7 @@ function DatasetInfo({ data }: { data: TrainDataset }) { | |||||
| function ProjectInfo({ data }: { data: ProjectDependency }) { | function ProjectInfo({ data }: { data: ProjectDependency }) { | ||||
| const gotoProjectPage = () => { | const gotoProjectPage = () => { | ||||
| const { url, branch } = data; | const { url, branch } = data; | ||||
| let projectUrl = url; | |||||
| if (url.endsWith('.git')) { | |||||
| projectUrl = `${url.substring(0, url.length - 4)}/tree/${branch}`; | |||||
| } | |||||
| const projectUrl = getGitUrl(url, branch); | |||||
| window.open(projectUrl, '_blank'); | window.open(projectUrl, '_blank'); | ||||
| }; | }; | ||||
| @@ -18,7 +18,7 @@ import { useNavigate } from '@umijs/max'; | |||||
| import { App, Button, Col, Form, Input, Row, Select } from 'antd'; | import { App, Button, Col, Form, Input, Row, Select } from 'antd'; | ||||
| import { pick } from 'lodash'; | import { pick } from 'lodash'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType } from '../types'; | |||||
| import { ServiceData, ServiceOperationType, createServiceVersionMessage } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| // 表单数据 | // 表单数据 | ||||
| @@ -59,9 +59,12 @@ function CreateService() { | |||||
| ...formData, | ...formData, | ||||
| }; | }; | ||||
| const [res] = await to(request(params)); | const [res] = await to(request(params)); | ||||
| if (res) { | |||||
| if (res && res.data) { | |||||
| message.success('操作成功'); | message.success('操作成功'); | ||||
| navigate(-1); | navigate(-1); | ||||
| setTimeout(() => { | |||||
| window.postMessage({ type: createServiceVersionMessage, payload: res.data.id }); | |||||
| }, 500); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -31,7 +31,12 @@ import { useNavigate, useParams } from '@umijs/max'; | |||||
| import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd'; | import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd'; | ||||
| import { omit, pick } from 'lodash'; | import { omit, pick } from 'lodash'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| ServiceVersionData, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| // 表单数据 | // 表单数据 | ||||
| @@ -53,6 +58,7 @@ function CreateServiceVersion() { | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [resourceStandardList, filterResourceStandard] = useComputingResource(); | const [resourceStandardList, filterResourceStandard] = useComputingResource(); | ||||
| const [operationType, setOperationType] = useState(ServiceOperationType.Create); | const [operationType, setOperationType] = useState(ServiceOperationType.Create); | ||||
| const [lastPage, setLastPage] = useState(CreateServiceVersionFrom.ServiceInfo); | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined); | const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined); | ||||
| const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined); | const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined); | ||||
| @@ -60,10 +66,15 @@ function CreateServiceVersion() { | |||||
| const id = params.id; | const id = params.id; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| const res: (ServiceVersionData & { operationType: ServiceOperationType }) | undefined = | |||||
| getSessionStorageItem(serviceVersionInfoKey, true); | |||||
| const res: | |||||
| | (ServiceVersionData & { | |||||
| operationType: ServiceOperationType; | |||||
| lastPage: CreateServiceVersionFrom; | |||||
| }) | |||||
| | undefined = getSessionStorageItem(serviceVersionInfoKey, true); | |||||
| if (res) { | if (res) { | ||||
| setOperationType(res.operationType); | setOperationType(res.operationType); | ||||
| setLastPage(res.lastPage); | |||||
| setVersionInfo(res); | setVersionInfo(res); | ||||
| let model, codeConfig, envVariables; | let model, codeConfig, envVariables; | ||||
| if (res.model && typeof res.model === 'object') { | if (res.model && typeof res.model === 'object') { | ||||
| @@ -156,7 +167,11 @@ function CreateServiceVersion() { | |||||
| const [res] = await to(request(params)); | const [res] = await to(request(params)); | ||||
| if (res) { | if (res) { | ||||
| message.success('操作成功'); | message.success('操作成功'); | ||||
| navigate(-1); | |||||
| if (lastPage === CreateServiceVersionFrom.ServiceInfo) { | |||||
| navigate(-1); | |||||
| } else { | |||||
| navigate(`/modelDeployment/serviceInfo/${serviceInfo?.id}`, { replace: true }); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -234,7 +249,7 @@ function CreateServiceVersion() { | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^[a-zA-Z0-9._-]+$/, | pattern: /^[a-zA-Z0-9._-]+$/, | ||||
| message: '版本只支持字母、数字、下划线、点、横杠', | |||||
| message: '版本只支持字母、数字、点、下划线、中横线', | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| @@ -401,7 +416,8 @@ function CreateServiceVersion() { | |||||
| }, | }, | ||||
| { | { | ||||
| pattern: /^\/[a-zA-Z0-9._/-]+$/, | pattern: /^\/[a-zA-Z0-9._/-]+$/, | ||||
| message: '请输入正确的挂载绝对路径', | |||||
| message: | |||||
| '请输入正确的挂载路径,以 / 开头,只支持字母、数字、点、下划线、中横线、斜杠', | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| > | > | ||||
| @@ -12,7 +12,11 @@ import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment'; | import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { serviceInfoKey, setSessionStorageItem } from '@/utils/sessionStorage'; | |||||
| import { | |||||
| serviceInfoKey, | |||||
| serviceVersionInfoKey, | |||||
| setSessionStorageItem, | |||||
| } from '@/utils/sessionStorage'; | |||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { useNavigate } from '@umijs/max'; | import { useNavigate } from '@umijs/max'; | ||||
| import { | import { | ||||
| @@ -28,7 +32,12 @@ import { | |||||
| import { type SearchProps } from 'antd/es/input'; | import { type SearchProps } from 'antd/es/input'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import { ServiceData, ServiceOperationType } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| createServiceVersionMessage, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const allServiceTypeOptions = [{ label: '全部', value: '' }, ...serviceTypeOptions]; | const allServiceTypeOptions = [{ label: '全部', value: '' }, ...serviceTypeOptions]; | ||||
| @@ -49,6 +58,13 @@ function ModelDeployment() { | |||||
| }, | }, | ||||
| ); | ); | ||||
| useEffect(() => { | |||||
| window.addEventListener('message', handleMessage); | |||||
| return () => { | |||||
| window.removeEventListener('message', handleMessage); | |||||
| }; | |||||
| }, []); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getServiceList(); | getServiceList(); | ||||
| }, [pagination, searchText, serviceType]); | }, [pagination, searchText, serviceType]); | ||||
| @@ -137,6 +153,35 @@ function ModelDeployment() { | |||||
| navigate(`/modelDeployment/serviceInfo/${record.id}`); | navigate(`/modelDeployment/serviceInfo/${record.id}`); | ||||
| }; | }; | ||||
| const handleMessage = (e: MessageEvent) => { | |||||
| const { type, payload } = e.data; | |||||
| if (type === createServiceVersionMessage) { | |||||
| modalConfirm({ | |||||
| title: '创建服务成功', | |||||
| content: '是否创建服务版本?', | |||||
| isDelete: false, | |||||
| cancelText: '稍后创建', | |||||
| onOk: () => { | |||||
| gotoCreateServiceVersion(payload); | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }; | |||||
| // 去创建服务版本 | |||||
| const gotoCreateServiceVersion = (serviceId: number) => { | |||||
| setSessionStorageItem( | |||||
| serviceVersionInfoKey, | |||||
| { | |||||
| operationType: ServiceOperationType.Create, | |||||
| lastPage: CreateServiceVersionFrom.CreateService, | |||||
| }, | |||||
| true, | |||||
| ); | |||||
| navigate(`/modelDeployment/addVersion/${serviceId}`); | |||||
| }; | |||||
| // 分页切换 | // 分页切换 | ||||
| const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => { | const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => { | ||||
| if (action === 'paginate') { | if (action === 'paginate') { | ||||
| @@ -38,7 +38,12 @@ import { type SearchProps } from 'antd/es/input'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||
| import ServiceRunStatusCell from '../components/ModelDeployStatusCell'; | import ServiceRunStatusCell from '../components/ModelDeployStatusCell'; | ||||
| import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types'; | |||||
| import { | |||||
| CreateServiceVersionFrom, | |||||
| ServiceData, | |||||
| ServiceOperationType, | |||||
| ServiceVersionData, | |||||
| } from '../types'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const allServiceStatusOptions = [{ label: '全部', value: '' }, ...serviceStatusOptions]; | const allServiceStatusOptions = [{ label: '全部', value: '' }, ...serviceStatusOptions]; | ||||
| @@ -171,13 +176,14 @@ function ServiceInfo() { | |||||
| }); | }); | ||||
| }; | }; | ||||
| // 创建、更新、重启模型部署 | |||||
| // 创建、更新、重启服务版本 | |||||
| const createServiceVersion = (type: ServiceOperationType, record?: ServiceVersionData) => { | const createServiceVersion = (type: ServiceOperationType, record?: ServiceVersionData) => { | ||||
| setSessionStorageItem( | setSessionStorageItem( | ||||
| serviceVersionInfoKey, | serviceVersionInfoKey, | ||||
| { | { | ||||
| ...record, | ...record, | ||||
| operationType: type, | operationType: type, | ||||
| lastPage: CreateServiceVersionFrom.ServiceInfo, | |||||
| }, | }, | ||||
| true, | true, | ||||
| ); | ); | ||||
| @@ -0,0 +1,6 @@ | |||||
| .basic-info { | |||||
| a:hover { | |||||
| text-decoration: underline @underline-color; | |||||
| text-underline-offset: 3px; | |||||
| } | |||||
| } | |||||
| @@ -1,10 +1,12 @@ | |||||
| import LabelValue from '@/components/LabelValue'; | import LabelValue from '@/components/LabelValue'; | ||||
| import { useComputingResource } from '@/hooks/resource'; | import { useComputingResource } from '@/hooks/resource'; | ||||
| import { ServiceVersionData } from '@/pages/ModelDeployment/types'; | import { ServiceVersionData } from '@/pages/ModelDeployment/types'; | ||||
| import { getGitUrl } from '@/utils'; | |||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import { Link } from '@umijs/max'; | import { Link } from '@umijs/max'; | ||||
| import { Col, Row } from 'antd'; | import { Col, Row } from 'antd'; | ||||
| import ServiceRunStatusCell from '../ModelDeployStatusCell'; | import ServiceRunStatusCell from '../ModelDeployStatusCell'; | ||||
| import styles from './index.less'; | |||||
| type BasicInfoProps = { | type BasicInfoProps = { | ||||
| info?: ServiceVersionData; | info?: ServiceVersionData; | ||||
| @@ -15,7 +17,7 @@ function BasicInfo({ info }: BasicInfoProps) { | |||||
| // 格式化环境变量 | // 格式化环境变量 | ||||
| const formatEnvText = () => { | const formatEnvText = () => { | ||||
| if (!info?.env_variables) { | |||||
| if (!info?.env_variables || Object.keys(info.env_variables).length === 0) { | |||||
| return '--'; | return '--'; | ||||
| } | } | ||||
| const env = info.env_variables; | const env = info.env_variables; | ||||
| @@ -26,7 +28,8 @@ function BasicInfo({ info }: BasicInfoProps) { | |||||
| const formatCodeConfig = () => { | const formatCodeConfig = () => { | ||||
| if (info && info.code_config) { | if (info && info.code_config) { | ||||
| const url = `${info.code_config.code_path}/tree/${info.code_config.branch}`; | |||||
| const { code_path, branch } = info.code_config; | |||||
| const url = getGitUrl(code_path, branch); | |||||
| return ( | return ( | ||||
| <a href={url} target="_blank" rel="noreferrer"> | <a href={url} target="_blank" rel="noreferrer"> | ||||
| {info?.code_config?.show_value} | {info?.code_config?.show_value} | ||||
| @@ -53,7 +56,7 @@ function BasicInfo({ info }: BasicInfoProps) { | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <div> | |||||
| <div className={styles['basic-info']}> | |||||
| <Row gutter={40} style={{ marginBottom: '20px' }}> | <Row gutter={40} style={{ marginBottom: '20px' }}> | ||||
| <Col span={10}> | <Col span={10}> | ||||
| <LabelValue label="服务名称:" value={info?.service_name}></LabelValue> | <LabelValue label="服务名称:" value={info?.service_name}></LabelValue> | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * @Author: 赵伟 | * @Author: 赵伟 | ||||
| * @Date: 2024-04-18 18:35:41 | * @Date: 2024-04-18 18:35:41 | ||||
| * @Description: 模型部署状态 | |||||
| * @Description: 服务运行状态 | |||||
| */ | */ | ||||
| import { ServiceRunStatus } from '@/enums'; | import { ServiceRunStatus } from '@/enums'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| @@ -57,7 +57,7 @@ function ServerLog({ info }: ServerLogProps) { | |||||
| getModelDeploymentLog(); | getModelDeploymentLog(); | ||||
| }, [info, logTime]); | }, [info, logTime]); | ||||
| // 获取模型部署日志 | |||||
| // 获取服务日志 | |||||
| const getModelDeploymentLog = async () => { | const getModelDeploymentLog = async () => { | ||||
| if (info && logTime && logTime.length === 2) { | if (info && logTime && logTime.length === 2) { | ||||
| const params = { | const params = { | ||||
| @@ -14,7 +14,7 @@ function UserGuide({ info }: UserGuideProps) { | |||||
| getModelDeploymentDocs(); | getModelDeploymentDocs(); | ||||
| }, [info]); | }, [info]); | ||||
| // 获取模型部署文档 | |||||
| // 获取服务文档 | |||||
| const getModelDeploymentDocs = async () => { | const getModelDeploymentDocs = async () => { | ||||
| if (info) { | if (info) { | ||||
| const [res] = await to(getServiceVersionDocsReq(info.id)); | const [res] = await to(getServiceVersionDocsReq(info.id)); | ||||
| @@ -57,3 +57,12 @@ export enum ServiceOperationType { | |||||
| Update = 'Update', // 更新 | Update = 'Update', // 更新 | ||||
| Restart = 'Restart', // 重启 | Restart = 'Restart', // 重启 | ||||
| } | } | ||||
| // 操作类型 | |||||
| export enum CreateServiceVersionFrom { | |||||
| CreateService = 'CreateService', // 来自创建服务 | |||||
| ServiceInfo = 'ServiceInfo', // 来自服务详情 | |||||
| } | |||||
| // 去创建服务版本消息 | |||||
| export const createServiceVersionMessage = 'createServiceVersion'; | |||||
| @@ -31,7 +31,7 @@ export function parseJsonText(text?: string | null): any | null { | |||||
| } | } | ||||
| } | } | ||||
| // 判断是否为对象 | |||||
| // 判断是否为一般对象 | |||||
| function isPlainObject(value: any) { | function isPlainObject(value: any) { | ||||
| if (value === null || typeof value !== 'object') return false; | if (value === null || typeof value !== 'object') return false; | ||||
| let proto = Object.getPrototypeOf(value); | let proto = Object.getPrototypeOf(value); | ||||
| @@ -160,13 +160,13 @@ export function changePropertyName(obj: Record<string, any>, mapping: Record<str | |||||
| } | } | ||||
| /** | /** | ||||
| * 计算显示的字符串 | |||||
| * @param tr 要裁剪的字符串 | |||||
| * @param maxWidth 最大宽度 | |||||
| * @param fontSize 字体大小 | |||||
| * @return 处理后的字符串 | |||||
| * 计算能显示的字符串 | |||||
| * @param {string} str 要裁剪的字符串 | |||||
| * @param {number} maxWidth 最大宽度 | |||||
| * @param {number} fontSize 字体大小 | |||||
| * @return {string} 处理后的字符串 | |||||
| */ | */ | ||||
| export const fittingString = (str: string, maxWidth: number, fontSize: number) => { | |||||
| export const fittingString = (str: string, maxWidth: number, fontSize: number): string => { | |||||
| if (!str) { | if (!str) { | ||||
| return ''; | return ''; | ||||
| } | } | ||||
| @@ -200,3 +200,24 @@ export const fittingString = (str: string, maxWidth: number, fontSize: number) = | |||||
| export const isEmptyString = (str: any): boolean => { | export const isEmptyString = (str: any): boolean => { | ||||
| return str === '' || str === undefined || str === null; | return str === '' || str === undefined || str === null; | ||||
| }; | }; | ||||
| /** | |||||
| * 获取 git 仓库的 url | |||||
| * | |||||
| * @param {string} url - the url of the git repository | |||||
| * @param {string} branch - the branch of the repository | |||||
| * @return {string} the url of the repository | |||||
| * | |||||
| * If `branch` is given, the url will be in the format of 'http://gitlab.com/user/repo/tree/branch'. | |||||
| * Otherwise, the url will be in the format of 'http://gitlab.com/user/repo'. | |||||
| */ | |||||
| export const getGitUrl = (url: string, branch: string): string => { | |||||
| if (!url) { | |||||
| return ''; | |||||
| } | |||||
| const gitUrl = url.replace(/\.git$/, ''); | |||||
| if (branch) { | |||||
| return `${gitUrl}/tree/${branch}`; | |||||
| } | |||||
| return gitUrl; | |||||
| }; | |||||
| @@ -10,8 +10,20 @@ import { history } from '@umijs/max'; | |||||
| import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd'; | import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd'; | ||||
| import { closeAllModals } from './modal'; | import { closeAllModals } from './modal'; | ||||
| // 自定义 Confirm 弹框 | |||||
| export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) { | |||||
| type ModalConfirmProps = ModalFuncProps & { | |||||
| isDelete?: boolean; | |||||
| }; | |||||
| // 自定义删除 Confirm 弹框 | |||||
| export function modalConfirm({ | |||||
| title, | |||||
| content, | |||||
| okText = '确认', | |||||
| cancelText = '取消', | |||||
| isDelete = true, | |||||
| onOk, | |||||
| ...rest | |||||
| }: ModalConfirmProps) { | |||||
| Modal.confirm({ | Modal.confirm({ | ||||
| ...rest, | ...rest, | ||||
| width: 600, | width: 600, | ||||
| @@ -19,7 +31,11 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) | |||||
| title: ( | title: ( | ||||
| <div> | <div> | ||||
| <img | <img | ||||
| src={require('@/assets/img/delete-icon.png')} | |||||
| src={ | |||||
| isDelete | |||||
| ? require('@/assets/img/delete-icon.png') | |||||
| : require('@/assets/img/comfirm-icon.png') | |||||
| } | |||||
| style={{ width: '120px', marginBottom: '24px' }} | style={{ width: '120px', marginBottom: '24px' }} | ||||
| draggable={false} | draggable={false} | ||||
| alt="" | alt="" | ||||
| @@ -28,8 +44,8 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) | |||||
| </div> | </div> | ||||
| ), | ), | ||||
| content: content && <div style={{ color: themes.textColor, fontSize: '15px' }}>{content}</div>, | content: content && <div style={{ color: themes.textColor, fontSize: '15px' }}>{content}</div>, | ||||
| okText: '确认', | |||||
| cancelText: '取消', | |||||
| okText: okText, | |||||
| cancelText: cancelText, | |||||
| onOk: onOk, | onOk: onOk, | ||||
| }); | }); | ||||
| } | } | ||||