| @@ -0,0 +1,19 @@ | |||
| import { Of, useOf } from '@storybook/blocks'; | |||
| /** | |||
| * A block that displays the story name or title from the of prop | |||
| * - if a story reference is passed, it renders the story name | |||
| * - if a meta reference is passed, it renders the stories' title | |||
| * - if nothing is passed, it defaults to the primary story | |||
| */ | |||
| export const StoryName = ({ of }: { of?: Of }) => { | |||
| const resolvedOf = useOf(of || 'story', ['story', 'meta']); | |||
| switch (resolvedOf.type) { | |||
| case 'story': { | |||
| return <h3 className="css-wzniqs">{resolvedOf.story.name}</h3>; | |||
| } | |||
| case 'meta': { | |||
| return <h3 className="css-wzniqs">{resolvedOf.preparedMeta.title}</h3>; | |||
| } | |||
| } | |||
| }; | |||
| @@ -16,7 +16,7 @@ const config: StorybookConfig = { | |||
| name: '@storybook/react-webpack5', | |||
| options: {}, | |||
| }, | |||
| staticDirs: ['../static'], | |||
| staticDirs: ['../public'], | |||
| docs: { | |||
| defaultName: 'Documentation', | |||
| }, | |||
| @@ -0,0 +1,6 @@ | |||
| import { addons } from '@storybook/manager-api'; | |||
| import theme from './theme'; | |||
| addons.setConfig({ | |||
| theme: theme, | |||
| }); | |||
| @@ -0,0 +1,7 @@ | |||
| import { create } from '@storybook/theming'; | |||
| export default create({ | |||
| base: 'light', | |||
| brandTitle: '组件库文档', | |||
| brandUrl: 'https://storybook.js.org/docs', | |||
| brandTarget: '_blank', | |||
| }); | |||
| @@ -8,7 +8,7 @@ | |||
| "build": "max build", | |||
| "deploy": "npm run build && npm run gh-pages", | |||
| "dev": "npm run start:dev", | |||
| "dev-no-sso": "NO_SSO=true npm run start:dev", | |||
| "dev-no-sso": "cross-env NO_SSO=true npm run start:dev", | |||
| "docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./", | |||
| "docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build", | |||
| "docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up", | |||
| @@ -96,9 +96,11 @@ | |||
| "@storybook/addon-webpack5-compiler-babel": "~3.0.5", | |||
| "@storybook/addon-webpack5-compiler-swc": "~2.0.0", | |||
| "@storybook/blocks": "~8.5.3", | |||
| "@storybook/manager-api": "~8.6.0", | |||
| "@storybook/react": "~8.5.3", | |||
| "@storybook/react-webpack5": "~8.5.3", | |||
| "@storybook/test": "~8.5.3", | |||
| "@storybook/theming": "~8.6.0", | |||
| "@testing-library/react": "^14.0.0", | |||
| "@types/antd": "^1.0.0", | |||
| "@types/express": "^4.17.14", | |||
| @@ -166,7 +168,7 @@ | |||
| }, | |||
| "msw": { | |||
| "workerDirectory": [ | |||
| "static" | |||
| "public" | |||
| ] | |||
| } | |||
| } | |||
| @@ -24,6 +24,12 @@ export type BasicInfoProps = { | |||
| /** | |||
| * 基础信息展示组件,用于展示基础信息,支持一行两列或一行三列,支持数据格式化 | |||
| * | |||
| * ### usage | |||
| * ```tsx | |||
| * import { BasicInfo } from '@/components/BasicInfo'; | |||
| * <BasicInfo datas={datas} labelWidth={80} /> | |||
| * ``` | |||
| */ | |||
| export default function BasicInfo({ | |||
| datas, | |||
| @@ -1,3 +1,4 @@ | |||
| import { formatEnum } from '@/utils/format'; | |||
| import { Typography } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| import './index.less'; | |||
| @@ -7,8 +8,12 @@ type FormInfoProps = { | |||
| value?: any; | |||
| /** 如果 `value` 是对象时,取对象的哪个属性作为值 */ | |||
| valuePropName?: string; | |||
| /** 是否是多行 */ | |||
| multiline?: boolean; | |||
| /** 是否是多行文本 */ | |||
| textArea?: boolean; | |||
| /** 是否是下拉框 */ | |||
| select?: boolean; | |||
| /** 下拉框数据 */ | |||
| options?: { label: string; value: any }[]; | |||
| /** 自定义类名 */ | |||
| className?: string; | |||
| /** 自定义样式 */ | |||
| @@ -18,20 +23,34 @@ type FormInfoProps = { | |||
| /** | |||
| * 模拟禁用的输入框,但是内容超长时,hover 时显示所有内容 | |||
| */ | |||
| function FormInfo({ value, valuePropName, className, style, multiline = false }: FormInfoProps) { | |||
| const data = value && typeof value === 'object' && valuePropName ? value[valuePropName] : value; | |||
| function FormInfo({ | |||
| value, | |||
| valuePropName, | |||
| className, | |||
| select, | |||
| options, | |||
| style, | |||
| textArea = false, | |||
| }: FormInfoProps) { | |||
| let data = value; | |||
| if (value && typeof value === 'object' && valuePropName) { | |||
| data = value[valuePropName]; | |||
| } else if (select === true && options) { | |||
| data = formatEnum(options)(value); | |||
| } | |||
| return ( | |||
| <div | |||
| className={classNames( | |||
| 'form-info', | |||
| { | |||
| 'form-info--multiline': multiline, | |||
| 'form-info--multiline': textArea, | |||
| }, | |||
| className, | |||
| )} | |||
| style={style} | |||
| > | |||
| <Typography.Paragraph ellipsis={multiline ? false : { tooltip: data }}> | |||
| <Typography.Paragraph ellipsis={textArea ? false : { tooltip: data }}> | |||
| {data} | |||
| </Typography.Paragraph> | |||
| </div> | |||
| @@ -15,11 +15,11 @@ import { useSnapshot } from 'umi'; | |||
| // 获取资源规格 | |||
| export function useComputingResource() { | |||
| const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]); | |||
| const computingResourceSnap = useSnapshot(computingResourceState); | |||
| const snap = useSnapshot(computingResourceState); | |||
| useEffect(() => { | |||
| if (computingResourceSnap.computingResource.length > 0) { | |||
| setResourceStandardList(computingResourceSnap.computingResource as ComputingResource[]); | |||
| if (snap.computingResource.length > 0) { | |||
| setResourceStandardList(snap.computingResource as ComputingResource[]); | |||
| } else { | |||
| getComputingResource(); | |||
| } | |||
| @@ -83,7 +83,7 @@ function AutoMLInstance() { | |||
| const setupSSE = (name: string, namespace: string) => { | |||
| let { origin } = location; | |||
| if (process.env.NODE_ENV === 'development') { | |||
| origin = 'http://172.20.32.181:31213'; | |||
| origin = 'http://172.20.32.197:31213'; | |||
| } | |||
| const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); | |||
| const evtSource = new EventSource( | |||
| @@ -67,8 +67,8 @@ function CreateMirrorModal({ envId, onOk, ...rest }: CreateMirrorModalProps) { | |||
| message: '请输入镜像Tag', | |||
| }, | |||
| { | |||
| pattern: /^[a-zA-Z0-9_-]*$/, | |||
| message: '只支持字母、数字、下划线(_)、中横线(-)', | |||
| pattern: /^[a-zA-Z0-9._-]+$/, | |||
| message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', | |||
| }, | |||
| ]} | |||
| > | |||
| @@ -135,7 +135,7 @@ function LogGroup({ | |||
| const setupSockect = () => { | |||
| let { host } = location; | |||
| if (process.env.NODE_ENV === 'development') { | |||
| host = '172.20.32.181:31213'; | |||
| host = '172.20.32.197:31213'; | |||
| } | |||
| const socket = new WebSocket( | |||
| `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, | |||
| @@ -1,7 +1,7 @@ | |||
| import KFIcon from '@/components/KFIcon'; | |||
| import { AutoMLTaskType, ExperimentStatus } from '@/enums'; | |||
| import LogList from '@/pages/Experiment/components/LogList'; | |||
| import { getExperimentInsReq } from '@/services/autoML'; | |||
| import { getRayInsReq } from '@/services/hyperParameter'; | |||
| import { NodeStatus } from '@/types'; | |||
| import { parseJsonText } from '@/utils'; | |||
| import { safeInvoke } from '@/utils/functional'; | |||
| @@ -22,12 +22,11 @@ enum TabKeys { | |||
| History = 'history', | |||
| } | |||
| function AutoMLInstance() { | |||
| function HyperParameterInstance() { | |||
| const [activeTab, setActiveTab] = useState<string>(TabKeys.Params); | |||
| const [autoMLInfo, setAutoMLInfo] = useState<HyperParameterData | undefined>(undefined); | |||
| const [experimentInfo, setExperimentInfo] = useState<HyperParameterData | undefined>(undefined); | |||
| const [instanceInfo, setInstanceInfo] = useState<AutoMLInstanceData | undefined>(undefined); | |||
| const params = useParams(); | |||
| // const autoMLId = safeInvoke(Number)(params.autoMLId); | |||
| const instanceId = safeInvoke(Number)(params.id); | |||
| const evtSourceRef = useRef<EventSource | null>(null); | |||
| @@ -42,14 +41,14 @@ function AutoMLInstance() { | |||
| // 获取实验实例详情 | |||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | |||
| const [res] = await to(getExperimentInsReq(instanceId)); | |||
| const [res] = await to(getRayInsReq(instanceId)); | |||
| if (res && res.data) { | |||
| const info = res.data as AutoMLInstanceData; | |||
| const { param, node_status, argo_ins_name, argo_ins_ns, status } = info; | |||
| // 解析配置参数 | |||
| const paramJson = parseJsonText(param); | |||
| if (paramJson) { | |||
| setAutoMLInfo(paramJson); | |||
| setExperimentInfo(paramJson); | |||
| } | |||
| // 这个接口返回的状态有延时,SSE 返回的状态是最新的 | |||
| @@ -83,7 +82,7 @@ function AutoMLInstance() { | |||
| const setupSSE = (name: string, namespace: string) => { | |||
| let { origin } = location; | |||
| if (process.env.NODE_ENV === 'development') { | |||
| origin = 'http://172.20.32.181:31213'; | |||
| origin = 'http://172.20.32.197:31213'; | |||
| } | |||
| const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); | |||
| const evtSource = new EventSource( | |||
| @@ -142,7 +141,7 @@ function AutoMLInstance() { | |||
| children: ( | |||
| <HyperParameterBasic | |||
| className={styles['auto-ml-instance__basic']} | |||
| info={autoMLInfo} | |||
| info={experimentInfo} | |||
| runStatus={instanceInfo?.nodeStatus} | |||
| isInstance | |||
| /> | |||
| @@ -189,7 +188,7 @@ function AutoMLInstance() { | |||
| children: ( | |||
| <ExperimentHistory | |||
| fileUrl={instanceInfo?.run_history_path} | |||
| isClassification={autoMLInfo?.task_type === AutoMLTaskType.Classification} | |||
| isClassification={experimentInfo?.task_type === AutoMLTaskType.Classification} | |||
| /> | |||
| ), | |||
| }, | |||
| @@ -212,4 +211,4 @@ function AutoMLInstance() { | |||
| ); | |||
| } | |||
| export default AutoMLInstance; | |||
| export default HyperParameterInstance; | |||
| @@ -109,7 +109,7 @@ function ExecuteConfig() { | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="代码配置" | |||
| name="code" | |||
| name="code_config" | |||
| rules={[ | |||
| { | |||
| validator: requiredValidator, | |||
| @@ -12,7 +12,7 @@ export enum OperationType { | |||
| export type FormData = { | |||
| name: string; // 实验名称 | |||
| description: string; // 实验描述 | |||
| code: ParameterInputObject; // 代码 | |||
| code_config: ParameterInputObject; // 代码 | |||
| dataset: ParameterInputObject; // 数据集 | |||
| model: ParameterInputObject; // 模型 | |||
| image: ParameterInputObject; // 镜像 | |||
| @@ -177,8 +177,8 @@ function MirrorCreate() { | |||
| message: '请输入镜像Tag', | |||
| }, | |||
| { | |||
| pattern: /^[a-zA-Z0-9_-]*$/, | |||
| message: '只支持字母、数字、下划线(_)、中横线(-)', | |||
| pattern: /^[a-zA-Z0-9._-]+$/, | |||
| message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', | |||
| }, | |||
| ]} | |||
| > | |||
| @@ -247,7 +247,7 @@ function CreateServiceVersion() { | |||
| }, | |||
| { | |||
| pattern: /^[a-zA-Z0-9._-]+$/, | |||
| message: '版本只支持字母、数字、点、下划线、中横线', | |||
| message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', | |||
| }, | |||
| ]} | |||
| > | |||
| @@ -6,7 +6,7 @@ import { Button } from 'antd'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/BasicInfo', | |||
| title: 'Components/BasicInfo 基本信息', | |||
| component: BasicInfo, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -4,7 +4,7 @@ import * as BasicInfoStories from './BasicInfo.stories'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/BasicTableInfo', | |||
| title: 'Components/BasicTableInfo 表格基本信息', | |||
| component: BasicTableInfo, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -8,7 +8,7 @@ import { codeListData } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/CodeSelect', | |||
| title: 'Components/CodeSelect 代码配置选择器', | |||
| component: CodeSelect, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -1,6 +1,5 @@ | |||
| import CodeSelectorModal from '@/components/CodeSelectorModal'; | |||
| 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'; | |||
| @@ -9,7 +8,7 @@ import { codeListData } from './mockData'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/CodeSelectorModal', | |||
| title: 'Components/CodeSelectorModal 代码选择对话框', | |||
| component: CodeSelectorModal, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -39,39 +38,8 @@ 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: { | |||
| open: false, | |||
| }, | |||
| render: function Render({ onOk, onCancel, ...args }) { | |||
| const [{ open }, updateArgs] = useArgs(); | |||
| function onClick() { | |||
| updateArgs({ open: true }); | |||
| } | |||
| function handleOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function handleCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择代码配置 | |||
| </Button> | |||
| <CodeSelectorModal {...args} open={open} onOk={handleOk} onCancel={handleCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| /** 通过 `openAntdModal` 函数打开 */ | |||
| export const OpenByFunction: Story = { | |||
| name: '通过函数的方式打开', | |||
| export const Primary: Story = { | |||
| render: function Render(args) { | |||
| const handleClick = () => { | |||
| const { close } = openAntdModal(CodeSelectorModal, { | |||
| @@ -84,7 +52,7 @@ export const OpenByFunction: Story = { | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleClick}> | |||
| 以函数的方式打开 | |||
| 选择代码配置 | |||
| </Button> | |||
| ); | |||
| }, | |||
| @@ -4,7 +4,7 @@ import * as BasicInfoStories from './BasicInfo.stories'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ConfigInfo', | |||
| title: 'Components/ConfigInfo 配置信息', | |||
| component: ConfigInfo, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -1,10 +1,10 @@ | |||
| import FormInfo from '@/components/FormInfo'; | |||
| import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { Form, Input, Select, Typography } from 'antd'; | |||
| import { Form, Input, Select } from 'antd'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/FormInfo', | |||
| title: 'Components/FormInfo 表单信息', | |||
| component: FormInfo, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -24,6 +24,14 @@ 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: { | |||
| style: { width: '200px' }, | |||
| value: | |||
| '超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本', | |||
| }, | |||
| }; | |||
| export const InForm: Story = { | |||
| render: () => { | |||
| return ( | |||
| @@ -40,11 +48,10 @@ export const InForm: Story = { | |||
| value: 1, | |||
| showValue: '对象文本', | |||
| }, | |||
| input_text: | |||
| '超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本', | |||
| antd_select: 1, | |||
| select_text: 1, | |||
| select_large_text: 1, | |||
| ant_input_text: | |||
| '超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本', | |||
| ant_select_text: 1, | |||
| }} | |||
| > | |||
| <Form.Item label="文本" name="text"> | |||
| @@ -54,7 +61,7 @@ export const InForm: Story = { | |||
| <FormInfo /> | |||
| </Form.Item> | |||
| <Form.Item label="多行文本" name="multiline_text"> | |||
| <FormInfo multiline /> | |||
| <FormInfo textArea /> | |||
| </Form.Item> | |||
| <Form.Item label="对象" name="object_text"> | |||
| <FormInfo valuePropName="showValue" /> | |||
| @@ -62,12 +69,9 @@ export const InForm: Story = { | |||
| <Form.Item label="无内容" name="empty_text"> | |||
| <FormInfo /> | |||
| </Form.Item> | |||
| <Form.Item label="Input" name="input_text"> | |||
| <Input disabled /> | |||
| </Form.Item> | |||
| <Form.Item label="Select" name="antd_select"> | |||
| <Select | |||
| disabled | |||
| <Form.Item label="Select" name="select_text"> | |||
| <FormInfo | |||
| select | |||
| options={[ | |||
| { | |||
| label: | |||
| @@ -77,37 +81,11 @@ export const InForm: Story = { | |||
| ]} | |||
| /> | |||
| </Form.Item> | |||
| <Form.Item label="Select" name="select_text"> | |||
| <Select | |||
| labelRender={(props) => { | |||
| return ( | |||
| <div style={{ width: '100%', lineHeight: 'normal' }}> | |||
| <Typography.Text ellipsis={{ tooltip: props.label }} style={{ margin: 0 }}> | |||
| {props.label} | |||
| </Typography.Text> | |||
| </div> | |||
| ); | |||
| }} | |||
| disabled | |||
| options={[ | |||
| { | |||
| label: '选择文本', | |||
| value: 1, | |||
| }, | |||
| ]} | |||
| /> | |||
| <Form.Item label="Input" name="ant_input_text"> | |||
| <Input disabled /> | |||
| </Form.Item> | |||
| <Form.Item label="Long Select" name="select_large_text"> | |||
| <Form.Item label="Select" name="ant_select_text"> | |||
| <Select | |||
| labelRender={(props) => { | |||
| return ( | |||
| <div style={{ width: '100%', lineHeight: 'normal' }}> | |||
| <Typography.Text ellipsis={{ tooltip: props.label }} style={{ margin: 0 }}> | |||
| {props.label} | |||
| </Typography.Text> | |||
| </div> | |||
| ); | |||
| }} | |||
| disabled | |||
| options={[ | |||
| { | |||
| @@ -4,7 +4,7 @@ import { fn } from '@storybook/test'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/FullScreenFrame', | |||
| title: 'Components/FullScreenFrame 全屏iframe', | |||
| component: FullScreenFrame, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ 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/IFramePage', | |||
| title: 'Components/IFramePage iframe页面', | |||
| component: IFramePage, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ 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/InfoGroup', | |||
| title: 'Components/InfoGroup 信息分组', | |||
| component: InfoGroup, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { fn } from '@storybook/test'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/KFEmpty', | |||
| title: 'Components/KFEmpty 空状态', | |||
| component: KFEmpty, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'; | |||
| import { Button } from 'antd'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/KFIcon', | |||
| title: 'Components/KFIcon 图标', | |||
| component: KFIcon, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -8,7 +8,7 @@ import { Button } from 'antd'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/KFModal', | |||
| title: 'Components/KFModal 对话框', | |||
| component: KFModal, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -5,7 +5,7 @@ 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/KFRadio', | |||
| title: 'Components/KFRadio 单选框', | |||
| component: KFRadio, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ 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/KFSpin', | |||
| title: 'Components/KFSpin 加载器', | |||
| component: KFSpin, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -6,7 +6,7 @@ import { Button } from 'antd'; | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/MenuIconSelector', | |||
| title: 'Components/MenuIconSelector 菜单图标选择器', | |||
| component: MenuIconSelector, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -3,7 +3,7 @@ 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/PageTitle', | |||
| title: 'Components/PageTitle 页面标题', | |||
| component: PageTitle, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -5,7 +5,7 @@ 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', | |||
| 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 | |||
| @@ -21,7 +21,7 @@ import { | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ResourceSelect', | |||
| 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 | |||
| @@ -1,13 +1,22 @@ | |||
| import { Meta, Canvas } from '@storybook/blocks'; | |||
| import { Meta, Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks'; | |||
| import * as ResourceSelectorModalStories from "./ResourceSelectorModal.stories" | |||
| import { StoryName } from "../../.storybook/blocks/StoryName" | |||
| <Meta of={ResourceSelectorModalStories} /> | |||
| <Title /> | |||
| <Subtitle /> | |||
| <Description /> | |||
| <Meta of={ResourceSelectorModalStories} name="Usage" /> | |||
| # Usage | |||
| ### Usage | |||
| 推荐通过 `openAntdModal` 函数打开 `ResourceSelectorModal`,打开 -> 处理 -> 关闭,整套代码在同一个地方 | |||
| ```ts | |||
| import { openAntdModal } from '@/utils/modal'; | |||
| import ResourceSelectorModal } from '@/components/ResourceSelectorModal'; | |||
| // 打开资源选择对话框 | |||
| const handleClick = () => { | |||
| const { close } = openAntdModal(ResourceSelectorModal, { | |||
| type: ResourceSelectorType.Dataset, | |||
| @@ -18,6 +27,11 @@ const handleClick = () => { | |||
| }); | |||
| ``` | |||
| <Canvas of={ResourceSelectorModalStories.OpenByFunction} /> | |||
| ### Primary | |||
| <Primary /> | |||
| <Controls /> | |||
| <Stories of={ResourceSelectorModalStories} /> | |||
| @@ -1,6 +1,5 @@ | |||
| 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'; | |||
| @@ -18,14 +17,42 @@ import { | |||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | |||
| const meta = { | |||
| title: 'Components/ResourceSelectorModal', | |||
| 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', | |||
| 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'], | |||
| tags: ['!autodocs'], | |||
| // More on argTypes: https://storybook.js.org/docs/api/argtypes | |||
| argTypes: { | |||
| // backgroundColor: { control: 'color' }, | |||
| @@ -45,158 +72,58 @@ 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 handleOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function handleCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| render: function Render(args) { | |||
| const handleClick = () => { | |||
| const { close } = openAntdModal(ResourceSelectorModal, { | |||
| type: args.type, | |||
| onOk: (res) => { | |||
| const { onOk } = args; | |||
| onOk?.(res); | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择数据集 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={handleOk} onCancel={handleCancel} /> | |||
| </> | |||
| <Button type="primary" onClick={handleClick}> | |||
| 选择数据集 | |||
| </Button> | |||
| ); | |||
| }, | |||
| }; | |||
| /** 选择模型 */ | |||
| 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 handleOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function handleCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| render: function Render(args) { | |||
| const handleClick = () => { | |||
| const { close } = openAntdModal(ResourceSelectorModal, { | |||
| type: args.type, | |||
| onOk: (res) => { | |||
| const { onOk } = args; | |||
| onOk?.(res); | |||
| close(); | |||
| }, | |||
| }); | |||
| }; | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择模型 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={handleOk} onCancel={handleCancel} /> | |||
| </> | |||
| <Button type="primary" onClick={handleClick}> | |||
| 选择模型 | |||
| </Button> | |||
| ); | |||
| }, | |||
| }; | |||
| /** 选择镜像 */ | |||
| 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 handleOk(res: any) { | |||
| updateArgs({ open: false }); | |||
| onOk?.(res); | |||
| } | |||
| function handleCancel() { | |||
| updateArgs({ open: false }); | |||
| onCancel?.(); | |||
| } | |||
| return ( | |||
| <> | |||
| <Button type="primary" onClick={onClick}> | |||
| 选择镜像 | |||
| </Button> | |||
| <ResourceSelectorModal {...args} open={open} onOk={handleOk} onCancel={handleCancel} /> | |||
| </> | |||
| ); | |||
| }, | |||
| }; | |||
| /** 通过 `openAntdModal` 函数打开 */ | |||
| export const OpenByFunction: Story = { | |||
| name: '通过函数的方式打开', | |||
| 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 handleClick = () => { | |||
| @@ -211,7 +138,7 @@ export const OpenByFunction: Story = { | |||
| }; | |||
| return ( | |||
| <Button type="primary" onClick={handleClick}> | |||
| 以函数的方式打开 | |||
| 选择镜像 | |||
| </Button> | |||
| ); | |||
| }, | |||
| @@ -4,7 +4,7 @@ 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/SubAreaTitle', | |||
| title: 'Components/SubAreaTitle 子区域标题', | |||
| component: SubAreaTitle, | |||
| parameters: { | |||
| // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout | |||
| @@ -122,10 +122,12 @@ export const formatBoolean = (value: boolean): string => { | |||
| return value ? '是' : '否'; | |||
| }; | |||
| type FormatEnum = (value: string | number) => string; | |||
| type FormatEnumFunc = (value: string | number) => string; | |||
| // 格式化枚举 | |||
| export const formatEnum = (options: { value: string | number; label: string }[]): FormatEnum => { | |||
| export const formatEnum = ( | |||
| options: { value: string | number; label: string }[], | |||
| ): FormatEnumFunc => { | |||
| return (value: string | number) => { | |||
| const option = options.find((item) => item.value === value); | |||
| return option ? option.label : '--'; | |||