Browse Source

Merge branch 'dev' of https://gitlink.org.cn/ci4s/ci4sManagement-cloud into dev

dev-active_learn
somunslotus 11 months ago
parent
commit
2b38895a53
45 changed files with 254 additions and 297 deletions
  1. +19
    -0
      react-ui/.storybook/blocks/StoryName.tsx
  2. +1
    -1
      react-ui/.storybook/main.ts
  3. +6
    -0
      react-ui/.storybook/manager.ts
  4. +7
    -0
      react-ui/.storybook/theme.ts
  5. +4
    -2
      react-ui/package.json
  6. +0
    -0
      react-ui/public/mockServiceWorker.js
  7. +6
    -0
      react-ui/src/components/BasicInfo/index.tsx
  8. +25
    -6
      react-ui/src/components/FormInfo/index.tsx
  9. +3
    -3
      react-ui/src/hooks/resource.ts
  10. +1
    -1
      react-ui/src/pages/AutoML/Instance/index.tsx
  11. +2
    -2
      react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx
  12. +1
    -1
      react-ui/src/pages/Experiment/components/LogGroup/index.tsx
  13. +9
    -10
      react-ui/src/pages/HyperParameter/Instance/index.tsx
  14. +1
    -1
      react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx
  15. +1
    -1
      react-ui/src/pages/HyperParameter/types.ts
  16. +2
    -2
      react-ui/src/pages/Mirror/Create/index.tsx
  17. +1
    -1
      react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx
  18. +1
    -1
      react-ui/src/stories/BasicInfo.stories.tsx
  19. +1
    -1
      react-ui/src/stories/BasicTableInfo.stories.tsx
  20. +1
    -1
      react-ui/src/stories/CodeSelect.stories.tsx
  21. +3
    -35
      react-ui/src/stories/CodeSelectorModal.stories.tsx
  22. +1
    -1
      react-ui/src/stories/Config.stories.tsx
  23. +20
    -42
      react-ui/src/stories/FormInfo.stories.tsx
  24. +1
    -1
      react-ui/src/stories/FullScreenFrame.stories.tsx
  25. +1
    -1
      react-ui/src/stories/IFramePage.stories.tsx
  26. +1
    -1
      react-ui/src/stories/InfoGroup.stories.tsx
  27. +1
    -1
      react-ui/src/stories/KFEmpty.stories.tsx
  28. +1
    -1
      react-ui/src/stories/KFIcon.stories.tsx
  29. +1
    -1
      react-ui/src/stories/KFModal.stories.tsx
  30. +1
    -1
      react-ui/src/stories/KFRadio.stories.tsx
  31. +1
    -1
      react-ui/src/stories/KFSpin.stories.tsx
  32. +1
    -1
      react-ui/src/stories/MenuIconSelector.stories.tsx
  33. +1
    -1
      react-ui/src/stories/PageTitle.stories.tsx
  34. +1
    -1
      react-ui/src/stories/ParameterInput.stories.tsx
  35. +1
    -1
      react-ui/src/stories/ResourceSelect.stories.tsx
  36. +20
    -6
      react-ui/src/stories/ResourceSelectorModal.mdx
  37. +62
    -135
      react-ui/src/stories/ResourceSelectorModal.stories.tsx
  38. +1
    -1
      react-ui/src/stories/SubAreaTitle.stories.tsx
  39. +4
    -2
      react-ui/src/utils/format.ts
  40. BIN
      react-ui/static/favicon.ico
  41. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/ray/RayInsController.java
  42. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/RayInsService.java
  43. +36
    -23
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java
  44. +1
    -2
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java
  45. +0
    -2
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java

+ 19
- 0
react-ui/.storybook/blocks/StoryName.tsx View File

@@ -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>;
}
}
};

+ 1
- 1
react-ui/.storybook/main.ts View File

@@ -16,7 +16,7 @@ const config: StorybookConfig = {
name: '@storybook/react-webpack5',
options: {},
},
staticDirs: ['../static'],
staticDirs: ['../public'],
docs: {
defaultName: 'Documentation',
},


+ 6
- 0
react-ui/.storybook/manager.ts View File

@@ -0,0 +1,6 @@
import { addons } from '@storybook/manager-api';
import theme from './theme';

addons.setConfig({
theme: theme,
});

+ 7
- 0
react-ui/.storybook/theme.ts View File

@@ -0,0 +1,7 @@
import { create } from '@storybook/theming';
export default create({
base: 'light',
brandTitle: '组件库文档',
brandUrl: 'https://storybook.js.org/docs',
brandTarget: '_blank',
});

+ 4
- 2
react-ui/package.json View File

@@ -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"
]
}
}

react-ui/static/mockServiceWorker.js → react-ui/public/mockServiceWorker.js View File


+ 6
- 0
react-ui/src/components/BasicInfo/index.tsx View File

@@ -24,6 +24,12 @@ export type BasicInfoProps = {

/**
* 基础信息展示组件,用于展示基础信息,支持一行两列或一行三列,支持数据格式化
*
* ### usage
* ```tsx
* import { BasicInfo } from '@/components/BasicInfo';
* <BasicInfo datas={datas} labelWidth={80} />
* ```
*/
export default function BasicInfo({
datas,


+ 25
- 6
react-ui/src/components/FormInfo/index.tsx View File

@@ -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>


+ 3
- 3
react-ui/src/hooks/resource.ts View File

@@ -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();
}


+ 1
- 1
react-ui/src/pages/AutoML/Instance/index.tsx View File

@@ -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(


+ 2
- 2
react-ui/src/pages/DevelopmentEnvironment/components/CreateMirrorModal/index.tsx View File

@@ -67,8 +67,8 @@ function CreateMirrorModal({ envId, onOk, ...rest }: CreateMirrorModalProps) {
message: '请输入镜像Tag',
},
{
pattern: /^[a-zA-Z0-9_-]*$/,
message: '只支持字母、数字、下划线(_)、中横线(-)',
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)',
},
]}
>


+ 1
- 1
react-ui/src/pages/Experiment/components/LogGroup/index.tsx View File

@@ -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}"}`,


+ 9
- 10
react-ui/src/pages/HyperParameter/Instance/index.tsx View File

@@ -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;

+ 1
- 1
react-ui/src/pages/HyperParameter/components/CreateForm/ExecuteConfig.tsx View File

@@ -109,7 +109,7 @@ function ExecuteConfig() {
<Col span={10}>
<Form.Item
label="代码配置"
name="code"
name="code_config"
rules={[
{
validator: requiredValidator,


+ 1
- 1
react-ui/src/pages/HyperParameter/types.ts View File

@@ -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; // 镜像


+ 2
- 2
react-ui/src/pages/Mirror/Create/index.tsx View File

@@ -177,8 +177,8 @@ function MirrorCreate() {
message: '请输入镜像Tag',
},
{
pattern: /^[a-zA-Z0-9_-]*$/,
message: '只支持字母、数字、下划线(_)、中横线(-)',
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)',
},
]}
>


+ 1
- 1
react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx View File

@@ -247,7 +247,7 @@ function CreateServiceVersion() {
},
{
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、点、下划线、中横线',
message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)',
},
]}
>


+ 1
- 1
react-ui/src/stories/BasicInfo.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/BasicTableInfo.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/CodeSelect.stories.tsx View File

@@ -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


+ 3
- 35
react-ui/src/stories/CodeSelectorModal.stories.tsx View File

@@ -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>
);
},


+ 1
- 1
react-ui/src/stories/Config.stories.tsx View File

@@ -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


+ 20
- 42
react-ui/src/stories/FormInfo.stories.tsx View File

@@ -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={[
{


+ 1
- 1
react-ui/src/stories/FullScreenFrame.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/IFramePage.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/InfoGroup.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/KFEmpty.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/KFIcon.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/KFModal.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/KFRadio.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/KFSpin.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/MenuIconSelector.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/PageTitle.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/ParameterInput.stories.tsx View File

@@ -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


+ 1
- 1
react-ui/src/stories/ResourceSelect.stories.tsx View File

@@ -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


+ 20
- 6
react-ui/src/stories/ResourceSelectorModal.mdx View File

@@ -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} />

+ 62
- 135
react-ui/src/stories/ResourceSelectorModal.stories.tsx View File

@@ -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>
);
},


+ 1
- 1
react-ui/src/stories/SubAreaTitle.stories.tsx View File

@@ -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


+ 4
- 2
react-ui/src/utils/format.ts View File

@@ -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 : '--';


BIN
react-ui/static/favicon.ico View File

Before After

+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/ray/RayInsController.java View File

@@ -54,7 +54,7 @@ public class RayInsController extends BaseController {

@GetMapping("{id}")
@ApiOperation("查看实验实例详情")
public GenericsAjaxResult<RayIns> getDetailById(@PathVariable("id") Long id) throws IOException {
public GenericsAjaxResult<RayIns> getDetailById(@PathVariable("id") Long id) throws Exception {
return genericsSuccess(this.rayInsService.getDetailById(id));
}
}

+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/RayInsService.java View File

@@ -15,7 +15,7 @@ public interface RayInsService {

boolean terminateRayIns(Long id) throws Exception;

RayIns getDetailById(Long id) throws IOException;
RayIns getDetailById(Long id) throws Exception;

void updateRayStatus(Long rayId);



+ 36
- 23
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayInsServiceImpl.java View File

@@ -9,6 +9,7 @@ import com.ruoyi.platform.service.RayInsService;
import com.ruoyi.platform.utils.DateUtils;
import com.ruoyi.platform.utils.HttpUtils;
import com.ruoyi.platform.utils.JsonUtils;
import com.ruoyi.platform.utils.MinioUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
@@ -18,7 +19,6 @@ import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
@@ -32,6 +32,8 @@ public class RayInsServiceImpl implements RayInsService {
private String argoWorkflowStatus;
@Value("${argo.workflowTermination}")
private String argoWorkflowTermination;
@Value("${minio.dataReleaseBucketName}")
private String bucketName;

@Resource
private RayInsDao rayInsDao;
@@ -39,6 +41,9 @@ public class RayInsServiceImpl implements RayInsService {
@Resource
private RayDao rayDao;

@Resource
private MinioUtil minioUtil;

@Override
public Page<RayIns> queryByPage(Long rayId, PageRequest pageRequest) throws IOException {
long total = this.rayInsDao.count(rayId);
@@ -161,7 +166,7 @@ public class RayInsServiceImpl implements RayInsService {
}

@Override
public RayIns getDetailById(Long id) throws IOException {
public RayIns getDetailById(Long id) throws Exception {
RayIns rayIns = rayInsDao.queryById(id);
if (Constant.Running.equals(rayIns.getStatus()) || Constant.Pending.equals(rayIns.getStatus())) {
rayIns = queryStatusFromArgo(rayIns);
@@ -260,34 +265,42 @@ public class RayInsServiceImpl implements RayInsService {
return rayInsDao.queryByRayInsIsNotTerminated();
}

public ArrayList<Map<String, Object>> getTrialList(String directoryPath) throws IOException {
public ArrayList<Map<String, Object>> getTrialList(String directoryPath) throws Exception {
// 获取指定路径下的所有文件
Path dirPath = Paths.get(directoryPath);
Path experimentState = Files.list(dirPath).filter(path -> Files.isRegularFile(path) && path.getFileName().toString().startsWith("experiment_state")).collect(Collectors.toList()).get(0);
String content = new String(Files.readAllBytes(experimentState));
Map<String, Object> result = JsonUtils.jsonToMap(content);
ArrayList<ArrayList> trial_data_list = (ArrayList<ArrayList>) result.get("trial_data");
String prefix = directoryPath.substring(directoryPath.indexOf("/") + 1, directoryPath.length()) + "/";
List<Map> maps = minioUtil.listFilesInDirectory(bucketName, prefix);

if (!maps.isEmpty()) {
List<Map> collect = maps.stream().filter(map -> map.get("name").toString().startsWith("experiment_state")).collect(Collectors.toList());
if (!collect.isEmpty()) {
Path experimentState = Paths.get(collect.get(0).get("name").toString());
String content = minioUtil.readObjectAsString(bucketName, prefix + "/" + experimentState);

ArrayList<Map<String, Object>> trialList = new ArrayList<>();
Map<String, Object> result = JsonUtils.jsonToMap(content);
ArrayList<ArrayList> trial_data_list = (ArrayList<ArrayList>) result.get("trial_data");
ArrayList<Map<String, Object>> trialList = new ArrayList<>();

for (ArrayList trial_data : trial_data_list) {
Map<String, Object> trial_data_0 = JsonUtils.jsonToMap((String) trial_data.get(0));
Map<String, Object> trial_data_1 = JsonUtils.jsonToMap((String) trial_data.get(1));
for (ArrayList trial_data : trial_data_list) {
Map<String, Object> trial_data_0 = JsonUtils.jsonToMap((String) trial_data.get(0));
Map<String, Object> trial_data_1 = JsonUtils.jsonToMap((String) trial_data.get(1));

Map<String, Object> trial = new HashMap<>();
trial.put("trial_id", trial_data_0.get("trial_id"));
trial.put("config", trial_data_0.get("config"));
trial.put("status", trial_data_0.get("status"));
Map<String, Object> trial = new HashMap<>();
trial.put("trial_id", trial_data_0.get("trial_id"));
trial.put("config", trial_data_0.get("config"));
trial.put("status", trial_data_0.get("status"));

Map<String, Object> last_result = (Map<String, Object>) trial_data_1.get("last_result");
Map<String, Object> metric_analysis = (Map<String, Object>) trial_data_1.get("metric_analysis");
Map<String, Object> time_total_s = (Map<String, Object>) metric_analysis.get("time_total_s");
Map<String, Object> last_result = (Map<String, Object>) trial_data_1.get("last_result");
Map<String, Object> metric_analysis = (Map<String, Object>) trial_data_1.get("metric_analysis");
Map<String, Object> time_total_s = (Map<String, Object>) metric_analysis.get("time_total_s");

trial.put("training_iteration", last_result.get("training_iteration"));
trial.put("time", time_total_s.get("avg"));
trial.put("training_iteration", last_result.get("training_iteration"));
trial.put("time", time_total_s.get("avg"));

trialList.add(trial);
trialList.add(trial);
}
return trialList;
}
}
return trialList;
return null;
}
}

+ 1
- 2
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/RayServiceImpl.java View File

@@ -197,8 +197,7 @@ public class RayServiceImpl implements RayService {
Map<String, Object> param_output = (Map<String, Object>) output.get("param_output");
List output1 = (ArrayList) param_output.values().toArray()[0];
Map<String, String> output2 = (Map<String, String>) output1.get(0);
String outputPath = minioEndpoint + "/" + output2.get("path").replace("{{workflow.name}}", (String) metadata.get("name")) + "/" + ray.getName();

String outputPath = output2.get("path").replace("{{workflow.name}}", (String) metadata.get("name")) + "/hpo";
rayIns.setResultPath(outputPath);
rayInsDao.insert(rayIns);
rayInsService.updateRayStatus(id);


+ 0
- 2
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/RayParamVo.java View File

@@ -24,8 +24,6 @@ public class RayParamVo {

private String mainPy;

private String name;

private Integer numSamples;

private String parameters;


Loading…
Cancel
Save