diff --git a/react-ui/.storybook/blocks/StoryName.tsx b/react-ui/.storybook/blocks/StoryName.tsx new file mode 100644 index 00000000..074c73cb --- /dev/null +++ b/react-ui/.storybook/blocks/StoryName.tsx @@ -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

{resolvedOf.story.name}

; + } + case 'meta': { + return

{resolvedOf.preparedMeta.title}

; + } + } +}; diff --git a/react-ui/.storybook/main.ts b/react-ui/.storybook/main.ts index 54824837..820a0eeb 100644 --- a/react-ui/.storybook/main.ts +++ b/react-ui/.storybook/main.ts @@ -16,7 +16,7 @@ const config: StorybookConfig = { name: '@storybook/react-webpack5', options: {}, }, - staticDirs: ['../static'], + staticDirs: ['../public'], docs: { defaultName: 'Documentation', }, diff --git a/react-ui/.storybook/manager.ts b/react-ui/.storybook/manager.ts new file mode 100644 index 00000000..baf80b25 --- /dev/null +++ b/react-ui/.storybook/manager.ts @@ -0,0 +1,6 @@ +import { addons } from '@storybook/manager-api'; +import theme from './theme'; + +addons.setConfig({ + theme: theme, +}); diff --git a/react-ui/.storybook/theme.ts b/react-ui/.storybook/theme.ts new file mode 100644 index 00000000..7b624111 --- /dev/null +++ b/react-ui/.storybook/theme.ts @@ -0,0 +1,7 @@ +import { create } from '@storybook/theming'; +export default create({ + base: 'light', + brandTitle: '组件库文档', + brandUrl: 'https://storybook.js.org/docs', + brandTarget: '_blank', +}); diff --git a/react-ui/package.json b/react-ui/package.json index 56a4b735..1a8d7ebc 100644 --- a/react-ui/package.json +++ b/react-ui/package.json @@ -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" ] } } diff --git a/react-ui/static/mockServiceWorker.js b/react-ui/public/mockServiceWorker.js similarity index 100% rename from react-ui/static/mockServiceWorker.js rename to react-ui/public/mockServiceWorker.js diff --git a/react-ui/src/components/BasicInfo/index.tsx b/react-ui/src/components/BasicInfo/index.tsx index 11eacfde..68622d7c 100644 --- a/react-ui/src/components/BasicInfo/index.tsx +++ b/react-ui/src/components/BasicInfo/index.tsx @@ -24,6 +24,12 @@ export type BasicInfoProps = { /** * 基础信息展示组件,用于展示基础信息,支持一行两列或一行三列,支持数据格式化 + * + * ### usage + * ```tsx + * import { BasicInfo } from '@/components/BasicInfo'; + * + * ``` */ export default function BasicInfo({ datas, diff --git a/react-ui/src/components/FormInfo/index.tsx b/react-ui/src/components/FormInfo/index.tsx index a784e433..7e8e95ad 100644 --- a/react-ui/src/components/FormInfo/index.tsx +++ b/react-ui/src/components/FormInfo/index.tsx @@ -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 (
- + {data}
diff --git a/react-ui/src/hooks/resource.ts b/react-ui/src/hooks/resource.ts index 0b491aeb..82a3ee78 100644 --- a/react-ui/src/hooks/resource.ts +++ b/react-ui/src/hooks/resource.ts @@ -15,11 +15,11 @@ import { useSnapshot } from 'umi'; // 获取资源规格 export function useComputingResource() { const [resourceStandardList, setResourceStandardList] = useState([]); - 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(); } diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 947ac63d..aefee532 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -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( diff --git a/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx index 6af530e1..8d2b27fa 100644 --- a/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx +++ b/react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx @@ -67,8 +67,8 @@ function CreateMirrorModal({ envId, onOk, ...rest }: CreateMirrorModalProps) { message: '请输入镜像Tag', }, { - pattern: /^[a-zA-Z0-9_-]*$/, - message: '只支持字母、数字、下划线(_)、中横线(-)', + pattern: /^[a-zA-Z0-9._-]+$/, + message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', }, ]} > diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx index 1b448930..6dd31166 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx @@ -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}"}`, diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx index 8d29521b..6a1d3931 100644 --- a/react-ui/src/pages/HyperParameter/Instance/index.tsx +++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx @@ -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(TabKeys.Params); - const [autoMLInfo, setAutoMLInfo] = useState(undefined); + const [experimentInfo, setExperimentInfo] = useState(undefined); const [instanceInfo, setInstanceInfo] = useState(undefined); const params = useParams(); - // const autoMLId = safeInvoke(Number)(params.autoMLId); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(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: ( @@ -189,7 +188,7 @@ function AutoMLInstance() { children: ( ), }, @@ -212,4 +211,4 @@ function AutoMLInstance() { ); } -export default AutoMLInstance; +export default HyperParameterInstance; diff --git a/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx b/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx index 1609328c..672f9094 100644 --- a/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx +++ b/react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx @@ -109,7 +109,7 @@ function ExecuteConfig() { diff --git a/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx b/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx index 38171380..430eae87 100644 --- a/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx +++ b/react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx @@ -247,7 +247,7 @@ function CreateServiceVersion() { }, { pattern: /^[a-zA-Z0-9._-]+$/, - message: '版本只支持字母、数字、点、下划线、中横线', + message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)', }, ]} > diff --git a/react-ui/src/stories/BasicInfo.stories.tsx b/react-ui/src/stories/BasicInfo.stories.tsx index 80a0337c..eddbec12 100644 --- a/react-ui/src/stories/BasicInfo.stories.tsx +++ b/react-ui/src/stories/BasicInfo.stories.tsx @@ -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 diff --git a/react-ui/src/stories/BasicTableInfo.stories.tsx b/react-ui/src/stories/BasicTableInfo.stories.tsx index 82581f6a..cdde73fc 100644 --- a/react-ui/src/stories/BasicTableInfo.stories.tsx +++ b/react-ui/src/stories/BasicTableInfo.stories.tsx @@ -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 diff --git a/react-ui/src/stories/CodeSelect.stories.tsx b/react-ui/src/stories/CodeSelect.stories.tsx index b5520c96..08520603 100644 --- a/react-ui/src/stories/CodeSelect.stories.tsx +++ b/react-ui/src/stories/CodeSelect.stories.tsx @@ -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 diff --git a/react-ui/src/stories/CodeSelectorModal.stories.tsx b/react-ui/src/stories/CodeSelectorModal.stories.tsx index a042f238..9faae0ae 100644 --- a/react-ui/src/stories/CodeSelectorModal.stories.tsx +++ b/react-ui/src/stories/CodeSelectorModal.stories.tsx @@ -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; // 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 ( - <> - - - - ); - }, -}; - -/** 通过 `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 ( ); }, diff --git a/react-ui/src/stories/Config.stories.tsx b/react-ui/src/stories/Config.stories.tsx index 0287d718..5c2a42ce 100644 --- a/react-ui/src/stories/Config.stories.tsx +++ b/react-ui/src/stories/Config.stories.tsx @@ -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 diff --git a/react-ui/src/stories/FormInfo.stories.tsx b/react-ui/src/stories/FormInfo.stories.tsx index b822427f..09466a46 100644 --- a/react-ui/src/stories/FormInfo.stories.tsx +++ b/react-ui/src/stories/FormInfo.stories.tsx @@ -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; // 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, }} > @@ -54,7 +61,7 @@ export const InForm: Story = { - + @@ -62,12 +69,9 @@ export const InForm: Story = { - - - - - { - return ( -
- - {props.label} - -
- ); - }} - disabled - options={[ - { - label: '选择文本', - value: 1, - }, - ]} - /> + + - +