| @@ -16,6 +16,7 @@ const config: StorybookConfig = { | |||
| name: '@storybook/react-webpack5', | |||
| options: {}, | |||
| }, | |||
| staticDirs: ['../public'], | |||
| webpackFinal: async (config) => { | |||
| if (config.resolve) { | |||
| config.resolve.alias = { | |||
| @@ -5,5 +5,12 @@ export const Link = ({ to, children, ...props }: any) => ( | |||
| ); | |||
| export const request = (url: string, options: any) => { | |||
| return fetch(url, options).then((res) => res.json()); | |||
| return fetch(url, options) | |||
| .then((res) => { | |||
| if (!res.ok) { | |||
| throw new Error(res.statusText); | |||
| } | |||
| return res; | |||
| }) | |||
| .then((res) => res.json()); | |||
| }; | |||
| @@ -4,8 +4,16 @@ import themes from '@/styles/theme.less'; | |||
| import type { Preview } from '@storybook/react'; | |||
| import { App, ConfigProvider } from 'antd'; | |||
| import zhCN from 'antd/locale/zh_CN'; | |||
| import { initialize, mswLoader } from 'msw-storybook-addon'; | |||
| import './storybook.css'; | |||
| /* | |||
| * Initializes MSW | |||
| * See https://github.com/mswjs/msw-storybook-addon#configuring-msw | |||
| * to learn how to customize it | |||
| */ | |||
| initialize(); | |||
| const preview: Preview = { | |||
| parameters: { | |||
| controls: { | |||
| @@ -77,6 +85,7 @@ const preview: Preview = { | |||
| </ConfigProvider> | |||
| ), | |||
| ], | |||
| loaders: [mswLoader], // 👈 Add the MSW loader to all stories | |||
| }; | |||
| export default preview; | |||
| @@ -6,7 +6,14 @@ body, | |||
| margin: 0; | |||
| padding: 0; | |||
| overflow-y: visible; | |||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, | |||
| 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', | |||
| 'Noto Color Emoji'; | |||
| } | |||
| .ant-input-search-large .ant-input-affix-wrapper, .ant-input-search-large .ant-input-search-button { | |||
| height: 46px; | |||
| } | |||
| *, | |||
| *::before, | |||
| *::after { | |||
| box-sizing: border-box; | |||
| } | |||
| @@ -119,6 +119,8 @@ | |||
| "less-loader": "~12.2.0", | |||
| "lint-staged": "^13.2.0", | |||
| "mockjs": "^1.1.0", | |||
| "msw": "~2.7.0", | |||
| "msw-storybook-addon": "~2.0.4", | |||
| "prettier": "^2.8.1", | |||
| "storybook": "~8.5.3", | |||
| "swagger-ui-dist": "^4.18.2", | |||
| @@ -158,5 +160,10 @@ | |||
| "CNAME", | |||
| "create-umi" | |||
| ] | |||
| }, | |||
| "msw": { | |||
| "workerDirectory": [ | |||
| "public" | |||
| ] | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,307 @@ | |||
| /* eslint-disable */ | |||
| /* tslint:disable */ | |||
| /** | |||
| * Mock Service Worker. | |||
| * @see https://github.com/mswjs/msw | |||
| * - Please do NOT modify this file. | |||
| * - Please do NOT serve this file on production. | |||
| */ | |||
| const PACKAGE_VERSION = '2.7.0' | |||
| const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f' | |||
| const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') | |||
| const activeClientIds = new Set() | |||
| self.addEventListener('install', function () { | |||
| self.skipWaiting() | |||
| }) | |||
| self.addEventListener('activate', function (event) { | |||
| event.waitUntil(self.clients.claim()) | |||
| }) | |||
| self.addEventListener('message', async function (event) { | |||
| const clientId = event.source.id | |||
| if (!clientId || !self.clients) { | |||
| return | |||
| } | |||
| const client = await self.clients.get(clientId) | |||
| if (!client) { | |||
| return | |||
| } | |||
| const allClients = await self.clients.matchAll({ | |||
| type: 'window', | |||
| }) | |||
| switch (event.data) { | |||
| case 'KEEPALIVE_REQUEST': { | |||
| sendToClient(client, { | |||
| type: 'KEEPALIVE_RESPONSE', | |||
| }) | |||
| break | |||
| } | |||
| case 'INTEGRITY_CHECK_REQUEST': { | |||
| sendToClient(client, { | |||
| type: 'INTEGRITY_CHECK_RESPONSE', | |||
| payload: { | |||
| packageVersion: PACKAGE_VERSION, | |||
| checksum: INTEGRITY_CHECKSUM, | |||
| }, | |||
| }) | |||
| break | |||
| } | |||
| case 'MOCK_ACTIVATE': { | |||
| activeClientIds.add(clientId) | |||
| sendToClient(client, { | |||
| type: 'MOCKING_ENABLED', | |||
| payload: { | |||
| client: { | |||
| id: client.id, | |||
| frameType: client.frameType, | |||
| }, | |||
| }, | |||
| }) | |||
| break | |||
| } | |||
| case 'MOCK_DEACTIVATE': { | |||
| activeClientIds.delete(clientId) | |||
| break | |||
| } | |||
| case 'CLIENT_CLOSED': { | |||
| activeClientIds.delete(clientId) | |||
| const remainingClients = allClients.filter((client) => { | |||
| return client.id !== clientId | |||
| }) | |||
| // Unregister itself when there are no more clients | |||
| if (remainingClients.length === 0) { | |||
| self.registration.unregister() | |||
| } | |||
| break | |||
| } | |||
| } | |||
| }) | |||
| self.addEventListener('fetch', function (event) { | |||
| const { request } = event | |||
| // Bypass navigation requests. | |||
| if (request.mode === 'navigate') { | |||
| return | |||
| } | |||
| // Opening the DevTools triggers the "only-if-cached" request | |||
| // that cannot be handled by the worker. Bypass such requests. | |||
| if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { | |||
| return | |||
| } | |||
| // Bypass all requests when there are no active clients. | |||
| // Prevents the self-unregistered worked from handling requests | |||
| // after it's been deleted (still remains active until the next reload). | |||
| if (activeClientIds.size === 0) { | |||
| return | |||
| } | |||
| // Generate unique request ID. | |||
| const requestId = crypto.randomUUID() | |||
| event.respondWith(handleRequest(event, requestId)) | |||
| }) | |||
| async function handleRequest(event, requestId) { | |||
| const client = await resolveMainClient(event) | |||
| const response = await getResponse(event, client, requestId) | |||
| // Send back the response clone for the "response:*" life-cycle events. | |||
| // Ensure MSW is active and ready to handle the message, otherwise | |||
| // this message will pend indefinitely. | |||
| if (client && activeClientIds.has(client.id)) { | |||
| ;(async function () { | |||
| const responseClone = response.clone() | |||
| sendToClient( | |||
| client, | |||
| { | |||
| type: 'RESPONSE', | |||
| payload: { | |||
| requestId, | |||
| isMockedResponse: IS_MOCKED_RESPONSE in response, | |||
| type: responseClone.type, | |||
| status: responseClone.status, | |||
| statusText: responseClone.statusText, | |||
| body: responseClone.body, | |||
| headers: Object.fromEntries(responseClone.headers.entries()), | |||
| }, | |||
| }, | |||
| [responseClone.body], | |||
| ) | |||
| })() | |||
| } | |||
| return response | |||
| } | |||
| // Resolve the main client for the given event. | |||
| // Client that issues a request doesn't necessarily equal the client | |||
| // that registered the worker. It's with the latter the worker should | |||
| // communicate with during the response resolving phase. | |||
| async function resolveMainClient(event) { | |||
| const client = await self.clients.get(event.clientId) | |||
| if (activeClientIds.has(event.clientId)) { | |||
| return client | |||
| } | |||
| if (client?.frameType === 'top-level') { | |||
| return client | |||
| } | |||
| const allClients = await self.clients.matchAll({ | |||
| type: 'window', | |||
| }) | |||
| return allClients | |||
| .filter((client) => { | |||
| // Get only those clients that are currently visible. | |||
| return client.visibilityState === 'visible' | |||
| }) | |||
| .find((client) => { | |||
| // Find the client ID that's recorded in the | |||
| // set of clients that have registered the worker. | |||
| return activeClientIds.has(client.id) | |||
| }) | |||
| } | |||
| async function getResponse(event, client, requestId) { | |||
| const { request } = event | |||
| // Clone the request because it might've been already used | |||
| // (i.e. its body has been read and sent to the client). | |||
| const requestClone = request.clone() | |||
| function passthrough() { | |||
| // Cast the request headers to a new Headers instance | |||
| // so the headers can be manipulated with. | |||
| const headers = new Headers(requestClone.headers) | |||
| // Remove the "accept" header value that marked this request as passthrough. | |||
| // This prevents request alteration and also keeps it compliant with the | |||
| // user-defined CORS policies. | |||
| const acceptHeader = headers.get('accept') | |||
| if (acceptHeader) { | |||
| const values = acceptHeader.split(',').map((value) => value.trim()) | |||
| const filteredValues = values.filter( | |||
| (value) => value !== 'msw/passthrough', | |||
| ) | |||
| if (filteredValues.length > 0) { | |||
| headers.set('accept', filteredValues.join(', ')) | |||
| } else { | |||
| headers.delete('accept') | |||
| } | |||
| } | |||
| return fetch(requestClone, { headers }) | |||
| } | |||
| // Bypass mocking when the client is not active. | |||
| if (!client) { | |||
| return passthrough() | |||
| } | |||
| // Bypass initial page load requests (i.e. static assets). | |||
| // The absence of the immediate/parent client in the map of the active clients | |||
| // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet | |||
| // and is not ready to handle requests. | |||
| if (!activeClientIds.has(client.id)) { | |||
| return passthrough() | |||
| } | |||
| // Notify the client that a request has been intercepted. | |||
| const requestBuffer = await request.arrayBuffer() | |||
| const clientMessage = await sendToClient( | |||
| client, | |||
| { | |||
| type: 'REQUEST', | |||
| payload: { | |||
| id: requestId, | |||
| url: request.url, | |||
| mode: request.mode, | |||
| method: request.method, | |||
| headers: Object.fromEntries(request.headers.entries()), | |||
| cache: request.cache, | |||
| credentials: request.credentials, | |||
| destination: request.destination, | |||
| integrity: request.integrity, | |||
| redirect: request.redirect, | |||
| referrer: request.referrer, | |||
| referrerPolicy: request.referrerPolicy, | |||
| body: requestBuffer, | |||
| keepalive: request.keepalive, | |||
| }, | |||
| }, | |||
| [requestBuffer], | |||
| ) | |||
| switch (clientMessage.type) { | |||
| case 'MOCK_RESPONSE': { | |||
| return respondWithMock(clientMessage.data) | |||
| } | |||
| case 'PASSTHROUGH': { | |||
| return passthrough() | |||
| } | |||
| } | |||
| return passthrough() | |||
| } | |||
| function sendToClient(client, message, transferrables = []) { | |||
| return new Promise((resolve, reject) => { | |||
| const channel = new MessageChannel() | |||
| channel.port1.onmessage = (event) => { | |||
| if (event.data && event.data.error) { | |||
| return reject(event.data.error) | |||
| } | |||
| resolve(event.data) | |||
| } | |||
| client.postMessage( | |||
| message, | |||
| [channel.port2].concat(transferrables.filter(Boolean)), | |||
| ) | |||
| }) | |||
| } | |||
| async function respondWithMock(response) { | |||
| // Setting response status code to 0 is a no-op. | |||
| // However, when responding with a "Response.error()", the produced Response | |||
| // instance will have status code set to 0. Since it's not possible to create | |||
| // a Response instance with status code 0, handle that use-case separately. | |||
| if (response.status === 0) { | |||
| return Response.error() | |||
| } | |||
| const mockedResponse = new Response(response.body, response) | |||
| Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { | |||
| value: true, | |||
| enumerable: true, | |||
| }) | |||
| return mockedResponse | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| .code-selector { | |||
| .kf-code-selector-modal { | |||
| width: 100%; | |||
| height: 100%; | |||
| @@ -6,31 +6,6 @@ | |||
| width: 100%; | |||
| } | |||
| :global { | |||
| .ant-input-affix-wrapper { | |||
| border-radius: 23px !important; | |||
| .ant-input-prefix { | |||
| margin-inline-end: 12px; | |||
| } | |||
| .ant-input-suffix { | |||
| margin-inline-end: 12px; | |||
| } | |||
| .ant-input-clear-icon { | |||
| font-size: 16px; | |||
| } | |||
| } | |||
| .ant-input-group-addon { | |||
| display: none; | |||
| } | |||
| .ant-pagination { | |||
| .ant-select-single { | |||
| height: 32px !important; | |||
| } | |||
| } | |||
| } | |||
| &__content { | |||
| display: flex; | |||
| flex-direction: row; | |||
| @@ -47,4 +22,28 @@ | |||
| &__empty { | |||
| padding-top: 40px; | |||
| } | |||
| // 覆盖 antd 样式 | |||
| .ant-input-affix-wrapper { | |||
| border-radius: 23px !important; | |||
| .ant-input-prefix { | |||
| margin-inline-end: 12px; | |||
| } | |||
| .ant-input-suffix { | |||
| margin-inline-end: 12px; | |||
| } | |||
| .ant-input-clear-icon { | |||
| font-size: 16px; | |||
| } | |||
| } | |||
| .ant-input-group-addon { | |||
| display: none; | |||
| } | |||
| .ant-pagination { | |||
| .ant-select-single { | |||
| height: 32px !important; | |||
| } | |||
| } | |||
| } | |||
| @@ -13,7 +13,7 @@ import type { ModalProps, PaginationProps } from 'antd'; | |||
| import { Empty, Input, Pagination } from 'antd'; | |||
| import { useEffect, useState } from 'react'; | |||
| import CodeConfigItem from '../CodeConfigItem'; | |||
| import styles from './index.less'; | |||
| import './index.less'; | |||
| export { type CodeConfigData }; | |||
| @@ -80,9 +80,9 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { | |||
| footer={null} | |||
| destroyOnClose | |||
| > | |||
| <div className={styles['code-selector']}> | |||
| <div className="kf-code-selector-modal"> | |||
| <Input.Search | |||
| className={styles['code-selector__search']} | |||
| className="kf-code-selector-modal__search" | |||
| placeholder="按代码仓库名称筛选" | |||
| allowClear | |||
| onSearch={handleSearch} | |||
| @@ -99,7 +99,7 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { | |||
| /> | |||
| {dataList?.length !== 0 ? ( | |||
| <> | |||
| <div className={styles['code-selector__content']}> | |||
| <div className="kf-code-selector-modal__content"> | |||
| {dataList?.map((item) => ( | |||
| <CodeConfigItem item={item} key={item.id} onClick={handleClick} /> | |||
| ))} | |||
| @@ -116,7 +116,7 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) { | |||
| /> | |||
| </> | |||
| ) : ( | |||
| <div className={styles['code-selector__empty']}> | |||
| <div className="kf-code-selector-modal__empty"> | |||
| <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty> | |||
| </div> | |||
| )} | |||
| @@ -1,5 +1,4 @@ | |||
| .kf-info-group-title { | |||
| box-sizing: border-box; | |||
| width: 100%; | |||
| height: 56px; | |||
| padding: 0 @content-padding; | |||
| @@ -9,7 +9,7 @@ import './index.less'; | |||
| type PageTitleProps = { | |||
| /** 标题 */ | |||
| title: string; | |||
| title: React.ReactNode; | |||
| /** 自定义类名 */ | |||
| className?: string; | |||
| /** 自定义样式 */ | |||
| @@ -26,18 +26,34 @@ export type ParameterInputObject = { | |||
| export type ParameterInputValue = ParameterInputObject | string; | |||
| export interface ParameterInputProps { | |||
| /** 值,可以是字符串,也可以是 ParameterInputObject 对象 */ | |||
| value?: ParameterInputValue; | |||
| /** | |||
| * 值变化时的回调 | |||
| * @param value 值,可以是字符串,也可以是 ParameterInputObject 对象 | |||
| */ | |||
| onChange?: (value?: ParameterInputValue) => void; | |||
| /** 点击时的回调 */ | |||
| onClick?: () => void; | |||
| /** 删除时的回调 */ | |||
| onRemove?: () => void; | |||
| /** 是否可以手动输入 */ | |||
| canInput?: boolean; | |||
| /** 是否是文本框 */ | |||
| textArea?: boolean; | |||
| /** 占位符 */ | |||
| placeholder?: string; | |||
| /** 是否允许清除 */ | |||
| allowClear?: boolean; | |||
| /** 自定义类名 */ | |||
| className?: string; | |||
| /** 自定义样式 */ | |||
| style?: React.CSSProperties; | |||
| /** 大小 */ | |||
| size?: 'middle' | 'small' | 'large'; | |||
| /** 是否禁用 */ | |||
| disabled?: boolean; | |||
| /** 元素 id */ | |||
| id?: string; | |||
| } | |||
| @@ -21,14 +21,16 @@ export { requiredValidator, type ParameterInputObject } from '../ParameterInput' | |||
| export { ResourceSelectorType, selectorTypeConfig, type ResourceSelectorResponse }; | |||
| type ResourceSelectProps = { | |||
| /** 类型,数据集、模型、镜像 */ | |||
| type: ResourceSelectorType; | |||
| } & ParameterInputProps; | |||
| // 获取选择数据集、模型后面按钮 icon | |||
| // 获取选择数据集、模型、镜像后面按钮 icon | |||
| const getSelectBtnIcon = (type: ResourceSelectorType) => { | |||
| return <KFIcon type={selectorTypeConfig[type].buttonIcon} font={16} />; | |||
| }; | |||
| /** 数据集、模型、镜像选择表单组件 */ | |||
| function ResourceSelect({ type, value, onChange, disabled, ...rest }: ResourceSelectProps) { | |||
| const [selectedResource, setSelectedResource] = useState<ResourceSelectorResponse | undefined>( | |||
| undefined, | |||
| @@ -16,7 +16,7 @@ import { ResourceSelectorType, selectorTypeConfig } from './config'; | |||
| import styles from './index.less'; | |||
| export { ResourceSelectorType, selectorTypeConfig }; | |||
| // 选择数据集\模型\镜像的返回类型 | |||
| // 选择数据集、模型、镜像的返回类型 | |||
| export type ResourceSelectorResponse = { | |||
| activeTab: CommonTabKeys; // 是我的还是公开的 | |||
| id: string; // 数据集\模型\镜像 id | |||
| @@ -28,10 +28,18 @@ export type ResourceSelectorResponse = { | |||
| }; | |||
| export interface ResourceSelectorModalProps extends Omit<ModalProps, 'onOk'> { | |||
| type: ResourceSelectorType; // 数据集\模型\镜像 | |||
| /** 类型,数据集、模型、镜像 */ | |||
| type: ResourceSelectorType; | |||
| /** 默认展开的节点 */ | |||
| defaultExpandedKeys?: React.Key[]; | |||
| /** 默认展开的节点 */ | |||
| defaultCheckedKeys?: React.Key[]; | |||
| /** 默认激活的 Tab */ | |||
| defaultActiveTab?: CommonTabKeys; | |||
| /** | |||
| * 确认回调 | |||
| * @param params 选择的数据 | |||
| */ | |||
| onOk?: (params: ResourceSelectorResponse | undefined) => void; | |||
| } | |||
| @@ -61,6 +69,7 @@ const getIdAndVersion = (versionKey: string) => { | |||
| }; | |||
| }; | |||
| /** 选择 数据集、模型、镜像 弹框 */ | |||
| function ResourceSelectorModal({ | |||
| type, | |||
| defaultExpandedKeys = [], | |||
| @@ -5,7 +5,7 @@ body, | |||
| height: 100%; | |||
| margin: 0; | |||
| padding: 0; | |||
| overflow-y: hidden; | |||
| overflow-y: visible; | |||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, | |||
| 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', | |||
| 'Noto Color Emoji'; | |||
| @@ -1,20 +1,9 @@ | |||
| import BasicInfo from '@/components/BasicInfo'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { formatList } from '@/utils/format'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { Button } from 'antd'; | |||
| const formatList = (value: string[] | null | undefined): string => { | |||
| if ( | |||
| value === undefined || | |||
| value === null || | |||
| Array.isArray(value) === false || | |||
| value.length === 0 | |||
| ) { | |||
| return '--'; | |||
| } | |||
| return value.join(','); | |||
| }; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/BasicInfo', | |||
| @@ -1,5 +1,9 @@ | |||
| import CodeSelect from '@/components/CodeSelect'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { fn } from '@storybook/test'; | |||
| import { Col, Form, Row } from 'antd'; | |||
| import { http, HttpResponse } from 'msw'; | |||
| import { codeListData } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| @@ -8,6 +12,13 @@ const meta = { | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| // layout: 'centered', | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/codeConfig', () => { | |||
| return HttpResponse.json(codeListData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| @@ -16,7 +27,7 @@ const meta = { | |||
| // backgroundColor: { control: 'color' }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| // args: { onClick: fn() }, | |||
| args: { onChange: fn() }, | |||
| } satisfies Meta<typeof CodeSelect>; | |||
| export default meta; | |||
| @@ -24,5 +35,22 @@ type Story = StoryObj<typeof meta>; | |||
| // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args | |||
| export const Primary: Story = { | |||
| args: {}, | |||
| render: ({ onChange }) => { | |||
| return ( | |||
| <Form name="code-select-form" size="large"> | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item label="代码配置" name="code_config"> | |||
| <CodeSelect | |||
| placeholder="请选择代码配置" | |||
| canInput={false} | |||
| size="large" | |||
| onChange={onChange} | |||
| /> | |||
| </Form.Item> | |||
| </Col> | |||
| </Row> | |||
| </Form> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -4,6 +4,8 @@ import { useArgs } from '@storybook/preview-api'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { fn } from '@storybook/test'; | |||
| import { Button } from 'antd'; | |||
| import { http, HttpResponse } from 'msw'; | |||
| import { codeListData } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| @@ -12,15 +14,19 @@ const meta = { | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| layout: 'centered', | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/codeConfig', () => { | |||
| return HttpResponse.json(codeListData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| title: { | |||
| description: '标题', | |||
| }, | |||
| open: { | |||
| description: '对话框是否可见', | |||
| }, | |||
| @@ -37,17 +43,19 @@ export const Primary: Story = { | |||
| args: { | |||
| open: false, | |||
| }, | |||
| render: function Render(args) { | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onOk() { | |||
| function onModalOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function onCancel() { | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| @@ -55,27 +63,27 @@ export const Primary: Story = { | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择代码配置 | |||
| </Button> | |||
| <CodeSelectorModal {...args} open={open} onOk={onOk} onCancel={onCancel} /> | |||
| <CodeSelectorModal {...args} open={open} onOk={onModalOk} onCancel={onModalCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| const OpenModalByFunction = () => { | |||
| const handleOnChange = () => { | |||
| const { close } = openAntdModal(CodeSelectorModal, { | |||
| onOk: () => { | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleOnChange}> | |||
| 以函数的方式打开 | |||
| </Button> | |||
| ); | |||
| }; | |||
| export const OpenInFunction: Story = { | |||
| render: () => <OpenModalByFunction />, | |||
| render: function Render(args) { | |||
| const handleOnChange = () => { | |||
| const { close } = openAntdModal(CodeSelectorModal, { | |||
| onOk: (res) => { | |||
| const { onOk } = args; | |||
| onOk?.(res); | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleOnChange}> | |||
| 以函数的方式打开 | |||
| </Button> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -25,6 +25,10 @@ const meta = { | |||
| open: { | |||
| description: '对话框是否可见', | |||
| }, | |||
| children: { | |||
| description: '子元素', | |||
| type: 'string', | |||
| }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| args: { onCancel: fn(), onOk: fn() }, | |||
| @@ -41,17 +45,19 @@ export const Primary: Story = { | |||
| open: false, | |||
| children: '这是一个模态框', | |||
| }, | |||
| render: function Render(args) { | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onOk() { | |||
| function onModalOk() { | |||
| updateArgs({ open: false }); | |||
| onOk?.(); | |||
| } | |||
| function onCancel() { | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| @@ -59,30 +65,28 @@ export const Primary: Story = { | |||
| <Button type="primary" onClick={onClick}> | |||
| 打开 KFModal | |||
| </Button> | |||
| <KFModal {...args} open={open} onOk={onOk} onCancel={onCancel} /> | |||
| <KFModal {...args} open={open} onOk={onModalOk} onCancel={onModalCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| const OpenModalByFunction = () => { | |||
| const handleOnChange = () => { | |||
| const { close } = openAntdModal(KFModal, { | |||
| title: '创建实验', | |||
| image: CreateExperiment, | |||
| children: '这是一个模态框', | |||
| onOk: () => { | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleOnChange}> | |||
| 以函数的方式打开 | |||
| </Button> | |||
| ); | |||
| }; | |||
| export const OpenInFunction: Story = { | |||
| render: () => <OpenModalByFunction />, | |||
| render: function Render() { | |||
| const handleOnChange = () => { | |||
| const { close } = openAntdModal(KFModal, { | |||
| title: '创建实验', | |||
| image: CreateExperiment, | |||
| children: '这是一个模态框', | |||
| onOk: () => { | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleOnChange}> | |||
| 以函数的方式打开 | |||
| </Button> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -34,17 +34,19 @@ export const Primary: Story = { | |||
| selectedIcon: 'manual-icon', | |||
| open: false, | |||
| }, | |||
| render: function Render(args) { | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open, selectedIcon }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onOk(value: string) { | |||
| function onModalOk(value: string) { | |||
| updateArgs({ selectedIcon: value, open: false }); | |||
| onOk?.(value); | |||
| } | |||
| function onCancel() { | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| @@ -56,8 +58,8 @@ export const Primary: Story = { | |||
| {...args} | |||
| open={open} | |||
| selectedIcon={selectedIcon} | |||
| onOk={onOk} | |||
| onCancel={onCancel} | |||
| onOk={onModalOk} | |||
| onCancel={onModalCancel} | |||
| /> | |||
| </> | |||
| ); | |||
| @@ -0,0 +1,108 @@ | |||
| import ParameterInput, { ParameterInputValue } from '@/components/ParameterInput'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { Button } from 'antd'; | |||
| import { useState } from 'react'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ParameterInput', | |||
| component: ParameterInput, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| // layout: 'centered', | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| // args: { onClick: fn() }, | |||
| } satisfies Meta<typeof ParameterInput>; | |||
| export default meta; | |||
| type Story = StoryObj<typeof meta>; | |||
| // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args | |||
| export const Input: Story = { | |||
| args: { | |||
| placeholder: '请输入工作目录', | |||
| style: { width: 300 }, | |||
| canInput: true, | |||
| textArea: false, | |||
| allowClear: true, | |||
| size: 'large', | |||
| }, | |||
| }; | |||
| export const Select: Story = { | |||
| args: { | |||
| placeholder: '请输入工作目录', | |||
| style: { width: 300 }, | |||
| value: 'storybook', | |||
| canInput: false, | |||
| size: 'large', | |||
| }, | |||
| }; | |||
| export const SelectWithObjctValue: Story = { | |||
| args: { | |||
| placeholder: '请输入工作目录', | |||
| style: { width: 300 }, | |||
| value: { | |||
| value: 'storybook', | |||
| showValue: 'storybook', | |||
| fromSelect: true, | |||
| }, | |||
| canInput: true, | |||
| size: 'large', | |||
| }, | |||
| }; | |||
| export const Disabled: Story = { | |||
| args: { | |||
| placeholder: '请输入工作目录', | |||
| style: { width: 300 }, | |||
| value: { | |||
| value: 'storybook', | |||
| showValue: 'storybook', | |||
| fromSelect: true, | |||
| }, | |||
| canInput: true, | |||
| size: 'large', | |||
| disabled: true, | |||
| }, | |||
| }; | |||
| export const Application: Story = { | |||
| args: { | |||
| placeholder: '请输入工作目录', | |||
| style: { width: 300 }, | |||
| canInput: true, | |||
| size: 'large', | |||
| }, | |||
| render: function Render(args) { | |||
| const [value, setValue] = useState<ParameterInputValue | undefined>(''); | |||
| const onClick = () => { | |||
| setValue({ | |||
| value: 'storybook', | |||
| showValue: 'storybook', | |||
| fromSelect: true, | |||
| }); | |||
| }; | |||
| return ( | |||
| <> | |||
| <ParameterInput | |||
| {...args} | |||
| value={value} | |||
| onChange={(value) => setValue(value)} | |||
| ></ParameterInput> | |||
| <Button type="primary" style={{ display: 'block', marginTop: 10 }} onClick={onClick}> | |||
| 模拟从全局参数选择 | |||
| </Button> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -1,32 +0,0 @@ | |||
| import MirrorBasic from '@/assets/img/mirror-basic.png'; | |||
| import ParameterSelect from '@/components/ParameterSelect'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ParameterSelect', | |||
| component: ParameterSelect, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| // layout: 'centered', | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| // args: { onClick: fn() }, | |||
| } satisfies Meta<typeof ParameterSelect>; | |||
| export default meta; | |||
| type Story = StoryObj<typeof meta>; | |||
| // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args | |||
| export const Primary: Story = { | |||
| args: { | |||
| title: '基本信息', | |||
| image: MirrorBasic, | |||
| }, | |||
| }; | |||
| @@ -0,0 +1,135 @@ | |||
| import ResourceSelect, { | |||
| requiredValidator, | |||
| ResourceSelectorType, | |||
| } from '@/components/ResourceSelect'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { fn } from '@storybook/test'; | |||
| import { Col, Form, Row } from 'antd'; | |||
| import { http, HttpResponse } from 'msw'; | |||
| import { | |||
| datasetDetailData, | |||
| datasetListData, | |||
| datasetVersionData, | |||
| mirrorListData, | |||
| mirrorVerionData, | |||
| modelDetailData, | |||
| modelListData, | |||
| modelVersionData, | |||
| } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ResourceSelect', | |||
| component: ResourceSelect, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| // layout: 'centered', | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/newdataset/queryDatasets', () => { | |||
| return HttpResponse.json(datasetListData); | |||
| }), | |||
| http.get('/api/mmp/newdataset/getVersionList', () => { | |||
| return HttpResponse.json(datasetVersionData); | |||
| }), | |||
| http.get('/api/mmp/newdataset/getDatasetDetail', () => { | |||
| return HttpResponse.json(datasetDetailData); | |||
| }), | |||
| http.get('/api/mmp/newmodel/queryModels', () => { | |||
| return HttpResponse.json(modelListData); | |||
| }), | |||
| http.get('/api/mmp/newmodel/getVersionList', () => { | |||
| return HttpResponse.json(modelVersionData); | |||
| }), | |||
| http.get('/api/mmp/newmodel/getModelDetail', () => { | |||
| return HttpResponse.json(modelDetailData); | |||
| }), | |||
| http.get('/api/mmp/image', () => { | |||
| return HttpResponse.json(mirrorListData); | |||
| }), | |||
| http.get('/api/mmp/imageVersion', () => { | |||
| return HttpResponse.json(mirrorVerionData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| args: { onChange: fn() }, | |||
| } satisfies Meta<typeof ResourceSelect>; | |||
| export default meta; | |||
| type Story = StoryObj<typeof meta>; | |||
| // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args | |||
| export const Primary: Story = { | |||
| args: { | |||
| type: ResourceSelectorType.Dataset, | |||
| }, | |||
| render: ({ onChange }) => { | |||
| return ( | |||
| <Form | |||
| name="resource-select-form" | |||
| labelCol={{ flex: '80px' }} | |||
| labelAlign="left" | |||
| size="large" | |||
| autoComplete="off" | |||
| > | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item label="数据集" name="dataset"> | |||
| <ResourceSelect | |||
| type={ResourceSelectorType.Dataset} | |||
| placeholder="请选择" | |||
| canInput={false} | |||
| size="large" | |||
| onChange={onChange} | |||
| /> | |||
| </Form.Item> | |||
| </Col> | |||
| </Row> | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="模型" | |||
| name="model" | |||
| rules={[ | |||
| { | |||
| validator: requiredValidator, | |||
| message: '请选择镜像', | |||
| }, | |||
| ]} | |||
| required | |||
| > | |||
| <ResourceSelect | |||
| type={ResourceSelectorType.Model} | |||
| placeholder="请选择" | |||
| canInput={false} | |||
| size="large" | |||
| onChange={onChange} | |||
| /> | |||
| </Form.Item> | |||
| </Col> | |||
| </Row> | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item label="镜像" name="image"> | |||
| <ResourceSelect | |||
| type={ResourceSelectorType.Mirror} | |||
| placeholder="请选择" | |||
| canInput={false} | |||
| size="large" | |||
| onChange={onChange} | |||
| /> | |||
| </Form.Item> | |||
| </Col> | |||
| </Row> | |||
| </Form> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -0,0 +1,216 @@ | |||
| import ResourceSelectorModal, { ResourceSelectorType } from '@/components/ResourceSelectorModal'; | |||
| import { openAntdModal } from '@/utils/modal'; | |||
| import { useArgs } from '@storybook/preview-api'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { fn } from '@storybook/test'; | |||
| import { Button } from 'antd'; | |||
| import { http, HttpResponse } from 'msw'; | |||
| import { | |||
| datasetDetailData, | |||
| datasetListData, | |||
| datasetVersionData, | |||
| mirrorListData, | |||
| mirrorVerionData, | |||
| modelDetailData, | |||
| modelListData, | |||
| modelVersionData, | |||
| } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ResourceSelectorModal', | |||
| component: ResourceSelectorModal, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| layout: 'centered', | |||
| }, | |||
| // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs | |||
| tags: ['autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| open: { | |||
| description: '对话框是否可见', | |||
| }, | |||
| type: { | |||
| control: 'select', | |||
| options: Object.values(ResourceSelectorType), | |||
| }, | |||
| }, | |||
| // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args | |||
| args: { onCancel: fn(), onOk: fn() }, | |||
| } satisfies Meta<typeof ResourceSelectorModal>; | |||
| export default meta; | |||
| type Story = StoryObj<typeof meta>; | |||
| // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args | |||
| export const Dataset: Story = { | |||
| args: { | |||
| type: ResourceSelectorType.Dataset, | |||
| open: false, | |||
| }, | |||
| parameters: { | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/newdataset/queryDatasets', () => { | |||
| return HttpResponse.json(datasetListData); | |||
| }), | |||
| http.get('/api/mmp/newdataset/getVersionList', () => { | |||
| return HttpResponse.json(datasetVersionData); | |||
| }), | |||
| http.get('/api/mmp/newdataset/getDatasetDetail', () => { | |||
| return HttpResponse.json(datasetDetailData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onModalOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择数据集 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={onModalOk} onCancel={onModalCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| export const Model: Story = { | |||
| args: { | |||
| type: ResourceSelectorType.Model, | |||
| open: false, | |||
| }, | |||
| parameters: { | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/newmodel/queryModels', () => { | |||
| return HttpResponse.json(modelListData); | |||
| }), | |||
| http.get('/api/mmp/newmodel/getVersionList', () => { | |||
| return HttpResponse.json(modelVersionData); | |||
| }), | |||
| http.get('/api/mmp/newmodel/getModelDetail', () => { | |||
| return HttpResponse.json(modelDetailData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onModalOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择模型 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={onModalOk} onCancel={onModalCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| export const Mirror: Story = { | |||
| args: { | |||
| type: ResourceSelectorType.Mirror, | |||
| open: false, | |||
| }, | |||
| parameters: { | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/image', () => { | |||
| return HttpResponse.json(mirrorListData); | |||
| }), | |||
| http.get('/api/mmp/imageVersion', () => { | |||
| return HttpResponse.json(mirrorVerionData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function onModalOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function onModalCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择镜像 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={onModalOk} onCancel={onModalCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| export const OpenInFunction: Story = { | |||
| args: { | |||
| type: ResourceSelectorType.Mirror, | |||
| }, | |||
| parameters: { | |||
| msw: { | |||
| handlers: [ | |||
| http.get('/api/mmp/image', () => { | |||
| return HttpResponse.json(mirrorListData); | |||
| }), | |||
| http.get('/api/mmp/imageVersion', () => { | |||
| return HttpResponse.json(mirrorVerionData); | |||
| }), | |||
| ], | |||
| }, | |||
| }, | |||
| render: function Render(args) { | |||
| const handleOnChange = () => { | |||
| const { close } = openAntdModal(ResourceSelectorModal, { | |||
| type: args.type, | |||
| onOk: (res) => { | |||
| const { onOk } = args; | |||
| onOk?.(res); | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleOnChange}> | |||
| 以函数的方式打开 | |||
| </Button> | |||
| ); | |||
| }, | |||
| }; | |||
| @@ -0,0 +1,548 @@ | |||
| export const datasetListData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: { | |||
| content: [ | |||
| { | |||
| name: '手写体识别训练测试数据集', | |||
| identifier: 'admin_dataset_20241213140429', | |||
| description: '手写体识别数据集', | |||
| is_public: false, | |||
| time_ago: '2个月前', | |||
| id: 1454047, | |||
| visits: 0, | |||
| create_by: '陈志航', | |||
| owner: 'chenzhihang', | |||
| }, | |||
| { | |||
| name: '手写体识别', | |||
| identifier: 'admin_dataset_20241213140020', | |||
| description: '手写体识别数据集', | |||
| is_public: false, | |||
| time_ago: '2个月前', | |||
| id: 1454046, | |||
| visits: 0, | |||
| create_by: '陈志航', | |||
| owner: 'chenzhihang', | |||
| }, | |||
| { | |||
| name: '生物活性分子数据集', | |||
| identifier: 'admin_dataset_20241211151411', | |||
| description: '生物活性分子数据集', | |||
| is_public: false, | |||
| time_ago: '2个月前', | |||
| id: 1454004, | |||
| visits: 0, | |||
| create_by: '陈志航', | |||
| owner: 'chenzhihang', | |||
| }, | |||
| { | |||
| name: '介电材料数据集', | |||
| identifier: 'admin_dataset_20241211151330', | |||
| description: '介电材料数据集', | |||
| is_public: false, | |||
| time_ago: '2个月前', | |||
| id: 1454003, | |||
| visits: 0, | |||
| create_by: '陈志航', | |||
| owner: 'chenzhihang', | |||
| }, | |||
| ], | |||
| pageable: { | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| pageSize: 2000, | |||
| pageNumber: 0, | |||
| offset: 0, | |||
| unpaged: false, | |||
| paged: true, | |||
| }, | |||
| last: true, | |||
| totalElements: 4, | |||
| totalPages: 1, | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| first: true, | |||
| number: 0, | |||
| numberOfElements: 4, | |||
| size: 2000, | |||
| empty: false, | |||
| }, | |||
| }; | |||
| export const datasetVersionData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: [ | |||
| { | |||
| name: 'v2', | |||
| http_url: 'https://cdn09022024.gitlink.org.cn/chenzhihang/admin_dataset_20241213140429.git', | |||
| zip_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v2.zip', | |||
| tar_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v2.tar.gz', | |||
| }, | |||
| { | |||
| name: 'v3', | |||
| http_url: 'https://cdn09022024.gitlink.org.cn/chenzhihang/admin_dataset_20241213140429.git', | |||
| zip_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v3.zip', | |||
| tar_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v3.tar.gz', | |||
| }, | |||
| { | |||
| name: 'v1', | |||
| http_url: 'https://cdn09022024.gitlink.org.cn/chenzhihang/admin_dataset_20241213140429.git', | |||
| zip_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v1.zip', | |||
| tar_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_dataset_20241213140429/archive/v1.tar.gz', | |||
| }, | |||
| ], | |||
| }; | |||
| export const datasetDetailData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: { | |||
| name: '生物活性分子材料数据集', | |||
| identifier: 'admin_dataset_20250217105241', | |||
| description: '生物活性分子材料数据集', | |||
| is_public: false, | |||
| data_type: '自然语言处理', | |||
| data_tag: '机器翻译', | |||
| version: 'v1', | |||
| dataset_version_vos: [ | |||
| { | |||
| url: '/home/resource/admin/datasets/1454953/admin_dataset_20250217105241/v1/dataset/BBBP.zip', | |||
| file_name: 'BBBP.zip', | |||
| file_size: '42.14 KB', | |||
| }, | |||
| ], | |||
| id: 1454953, | |||
| create_by: '樊帅', | |||
| version_desc: '生物活性分子材料数据集', | |||
| usage: | |||
| '<pre><code># 克隆数据集配置文件与存储参数到本地\ngit clone -b v1 https://gitlink.org.cn/fanshuai/admin_dataset_20250217105241.git\n# 远程拉取配置文件\ndvc pull\n</code></pre>', | |||
| update_time: '2025-02-17 10:52:43', | |||
| owner: 'fanshuai', | |||
| dataset_source: 'add', | |||
| relative_paths: 'admin/datasets/1454953/admin_dataset_20250217105241/v1/dataset', | |||
| }, | |||
| }; | |||
| export const modelListData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: { | |||
| content: [ | |||
| { | |||
| id: 1454208, | |||
| name: '介电材料模型1', | |||
| create_by: '陈志航', | |||
| description: '介电材料模型1', | |||
| time_ago: '2个月前', | |||
| owner: 'chenzhihang', | |||
| identifier: 'admin_model_20241224095928', | |||
| is_public: false, | |||
| }, | |||
| { | |||
| id: 1454007, | |||
| name: '手写体识别部署模型', | |||
| create_by: '陈志航', | |||
| description: '手写体识别部署模型', | |||
| time_ago: '2个月前', | |||
| owner: 'chenzhihang', | |||
| identifier: 'admin_model_20241211151713', | |||
| is_public: false, | |||
| }, | |||
| { | |||
| id: 1454006, | |||
| name: '生物活性分子材料', | |||
| create_by: '陈志航', | |||
| description: '生物活性分子材料', | |||
| time_ago: '2个月前', | |||
| owner: 'chenzhihang', | |||
| identifier: 'admin_model_20241211151645', | |||
| is_public: false, | |||
| }, | |||
| { | |||
| id: 1454005, | |||
| name: '介电材料模型', | |||
| create_by: '陈志航', | |||
| description: '介电材料模型', | |||
| time_ago: '2个月前', | |||
| owner: 'chenzhihang', | |||
| identifier: 'admin_model_20241211151601', | |||
| is_public: false, | |||
| }, | |||
| ], | |||
| pageable: { | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| pageSize: 2000, | |||
| pageNumber: 0, | |||
| offset: 0, | |||
| unpaged: false, | |||
| paged: true, | |||
| }, | |||
| last: true, | |||
| totalElements: 4, | |||
| totalPages: 1, | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| first: true, | |||
| number: 0, | |||
| numberOfElements: 4, | |||
| size: 2000, | |||
| empty: false, | |||
| }, | |||
| }; | |||
| export const modelVersionData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: [ | |||
| { | |||
| name: 'v1', | |||
| http_url: 'https://cdn09022024.gitlink.org.cn/chenzhihang/admin_model_20241224095928.git', | |||
| zip_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_model_20241224095928/archive/v1.zip', | |||
| tar_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_model_20241224095928/archive/v1.tar.gz', | |||
| }, | |||
| { | |||
| name: 'v2', | |||
| http_url: 'https://cdn09022024.gitlink.org.cn/chenzhihang/admin_model_20241224095928.git', | |||
| zip_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_model_20241224095928/archive/v1.zip', | |||
| tar_url: | |||
| 'https://www.gitlink.org.cn/api/chenzhihang/admin_model_20241224095928/archive/v1.tar.gz', | |||
| }, | |||
| ], | |||
| }; | |||
| export const modelDetailData = { | |||
| msg: '操作成功', | |||
| code: 200, | |||
| data: { | |||
| id: 1454208, | |||
| name: '介电材料模型1', | |||
| version: 'v1', | |||
| version_desc: '介电材料模型1', | |||
| create_by: '陈志航', | |||
| create_time: '2024-12-24 09:59:31', | |||
| update_time: '2024-12-24 09:59:31', | |||
| model_size: '101.90 KB', | |||
| model_source: 'add', | |||
| model_tag: '图像分类', | |||
| model_type: 'PyTorch', | |||
| description: '介电材料模型1', | |||
| usage: | |||
| '<pre><code># 克隆模型配置文件与存储参数到本地\ngit clone -b v1 https://gitlink.org.cn/chenzhihang/admin_model_20241224095928.git\n# 远程拉取配置文件\ndvc pull\n</code></pre>', | |||
| owner: 'chenzhihang', | |||
| identifier: 'admin_model_20241224095928', | |||
| is_public: false, | |||
| relative_paths: 'admin/model/1454208/admin_model_20241224095928/v1/model', | |||
| model_version_vos: [ | |||
| { | |||
| url: '/home/resource/admin/model/1454208/admin_model_20241224095928/v1/model/sklearn_svr_good.pkl', | |||
| file_name: 'sklearn_svr_good.pkl', | |||
| file_size: '101.90 KB', | |||
| }, | |||
| ], | |||
| }, | |||
| }; | |||
| export const mirrorListData = { | |||
| code: 200, | |||
| msg: '操作成功', | |||
| data: { | |||
| content: [ | |||
| { | |||
| id: 42, | |||
| name: 'ccr.ccs.tencentyun.com/somunslotus/httpserver', | |||
| description: 'htttp服务器镜像', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-04-30T14:44:37.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-04-30T14:44:37.000+08:00', | |||
| state: 1, | |||
| version_count: 1, | |||
| }, | |||
| { | |||
| id: 44, | |||
| name: 'minio-test', | |||
| description: 'minio镜像', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-05-08T15:19:00.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-05-08T15:19:00.000+08:00', | |||
| state: 1, | |||
| version_count: 1, | |||
| }, | |||
| { | |||
| id: 46, | |||
| name: 'machine-learning/mnist-model-deploy', | |||
| description: 'mnist手写体识别部署镜像', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-05-28T10:18:30.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-05-28T10:18:30.000+08:00', | |||
| state: 1, | |||
| version_count: 2, | |||
| }, | |||
| { | |||
| id: 49, | |||
| name: 'go_httpsever', | |||
| description: 'golang httpserver镜像', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-06-25T11:11:41.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-06-25T11:11:41.000+08:00', | |||
| state: 1, | |||
| version_count: 1, | |||
| }, | |||
| { | |||
| id: 51, | |||
| name: 'pytorch2_python3_cuda_12', | |||
| description: 'pytorch2.1.2_python3.11_cuda_12', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-14T16:16:35.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-14T16:16:35.000+08:00', | |||
| state: 1, | |||
| version_count: 2, | |||
| }, | |||
| { | |||
| id: 53, | |||
| name: 'jupyterlab', | |||
| description: 'v1', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-15T16:19:29.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-15T16:19:29.000+08:00', | |||
| state: 1, | |||
| version_count: 1, | |||
| }, | |||
| { | |||
| id: 55, | |||
| name: 'machine-learning/ax-pytorch', | |||
| description: '自动机器学习Ax镜像,带pytorch', | |||
| image_type: 0, | |||
| create_by: 'admin', | |||
| create_time: '2024-12-13T11:25:37.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-12-13T11:25:37.000+08:00', | |||
| state: 1, | |||
| version_count: 1, | |||
| }, | |||
| ], | |||
| pageable: { | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| pageSize: 2000, | |||
| pageNumber: 0, | |||
| offset: 0, | |||
| unpaged: false, | |||
| paged: true, | |||
| }, | |||
| last: true, | |||
| totalElements: 7, | |||
| totalPages: 1, | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| first: true, | |||
| number: 0, | |||
| numberOfElements: 7, | |||
| size: 2000, | |||
| empty: false, | |||
| }, | |||
| }; | |||
| export const mirrorVerionData = { | |||
| code: 200, | |||
| msg: '操作成功', | |||
| data: { | |||
| content: [ | |||
| { | |||
| id: 54, | |||
| image_id: 42, | |||
| version: null, | |||
| url: '172.20.32.187/testlib/admin/ccr.ccs.tencentyun.com/somunslotus/httpserver:v1', | |||
| tag_name: 'v1', | |||
| file_size: '6.98 MB', | |||
| status: 'available', | |||
| create_by: 'admin', | |||
| create_time: '2024-04-30T14:44:37.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-04-30T14:44:51.000+08:00', | |||
| state: 1, | |||
| host_ip: null, | |||
| }, | |||
| ], | |||
| pageable: { | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| pageSize: 2000, | |||
| pageNumber: 0, | |||
| offset: 0, | |||
| unpaged: false, | |||
| paged: true, | |||
| }, | |||
| last: true, | |||
| totalElements: 1, | |||
| totalPages: 1, | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| first: true, | |||
| number: 0, | |||
| numberOfElements: 1, | |||
| size: 2000, | |||
| empty: false, | |||
| }, | |||
| }; | |||
| export const codeListData = { | |||
| code: 200, | |||
| msg: '操作成功', | |||
| data: { | |||
| content: [ | |||
| { | |||
| id: 2, | |||
| code_repo_name: '介电材料代码', | |||
| code_repo_vis: 1, | |||
| git_url: 'https://gitlink.org.cn/fuli/ML_for_Materials.git', | |||
| git_branch: 'master', | |||
| verify_mode: null, | |||
| git_user_name: null, | |||
| git_password: null, | |||
| ssh_key: null, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-14T16:10:45.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-14T16:10:45.000+08:00', | |||
| state: 1, | |||
| }, | |||
| { | |||
| id: 3, | |||
| code_repo_name: '生物活性材料代码', | |||
| code_repo_vis: 1, | |||
| git_url: 'https://gitlink.org.cn/zhaoyihan/test_mole_pre.git', | |||
| git_branch: 'parse_dataset', | |||
| verify_mode: null, | |||
| git_user_name: null, | |||
| git_password: null, | |||
| ssh_key: null, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-16T08:41:39.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-16T08:41:39.000+08:00', | |||
| state: 1, | |||
| }, | |||
| { | |||
| id: 4, | |||
| code_repo_name: '数据处理', | |||
| code_repo_vis: 1, | |||
| git_url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||
| git_branch: 'train_ci_test', | |||
| verify_mode: null, | |||
| git_user_name: null, | |||
| git_password: null, | |||
| ssh_key: null, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-16T14:51:18.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-16T14:51:18.000+08:00', | |||
| state: 1, | |||
| }, | |||
| { | |||
| id: 5, | |||
| code_repo_name: '手写体识别部署', | |||
| code_repo_vis: 1, | |||
| git_url: 'https://gitlink.org.cn/somunslotus/mnist-inference.git', | |||
| git_branch: 'master', | |||
| verify_mode: null, | |||
| git_user_name: null, | |||
| git_password: null, | |||
| ssh_key: null, | |||
| create_by: 'admin', | |||
| create_time: '2024-10-16T16:36:43.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-10-16T16:36:43.000+08:00', | |||
| state: 1, | |||
| }, | |||
| { | |||
| id: 7, | |||
| code_repo_name: '手写体识别训练', | |||
| code_repo_vis: 1, | |||
| git_url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||
| git_branch: 'train_ci_test', | |||
| verify_mode: null, | |||
| git_user_name: null, | |||
| git_password: null, | |||
| ssh_key: null, | |||
| create_by: 'admin', | |||
| create_time: '2024-12-13T13:58:50.000+08:00', | |||
| update_by: 'admin', | |||
| update_time: '2024-12-13T13:58:50.000+08:00', | |||
| state: 1, | |||
| }, | |||
| ], | |||
| pageable: { | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| pageSize: 20, | |||
| pageNumber: 0, | |||
| offset: 0, | |||
| unpaged: false, | |||
| paged: true, | |||
| }, | |||
| last: true, | |||
| totalElements: 5, | |||
| totalPages: 1, | |||
| sort: { | |||
| unsorted: true, | |||
| sorted: false, | |||
| empty: true, | |||
| }, | |||
| first: true, | |||
| number: 0, | |||
| numberOfElements: 5, | |||
| size: 20, | |||
| empty: false, | |||
| }, | |||
| }; | |||