diff --git a/src/locales/en-US/clusters.ts b/src/locales/en-US/clusters.ts
index 1f43158f..d05dd0eb 100644
--- a/src/locales/en-US/clusters.ts
+++ b/src/locales/en-US/clusters.ts
@@ -90,5 +90,7 @@ Same applies to the /opt/dtk directory.`,
'Need to create a new token? Click here.',
'clusters.addworker.amdNotes-01': `If the /opt/rocm directory does not exist, please create a symbolic link pointing to the ROCm installed path: ln -s /path/to/rocm /opt/rocm.`,
'clusters.addworker.message.success':
- '{count} workers have been added to the cluster.'
+ '{count} workers have been added to the cluster.',
+ 'clusters.create.serverUrl': 'Server URL',
+ 'clusters.create.workerConfig': 'Worker Configuration'
};
diff --git a/src/locales/ja-JP/clusters.ts b/src/locales/ja-JP/clusters.ts
index 0104b161..48879d60 100644
--- a/src/locales/ja-JP/clusters.ts
+++ b/src/locales/ja-JP/clusters.ts
@@ -90,7 +90,9 @@ Same applies to the /opt/dtk directory.`,
'Need to create a new token? Click here.',
'clusters.addworker.amdNotes-01': `If the /opt/rocm directory does not exist, please create a symbolic link pointing to the ROCm installed path: ln -s /path/to/rocm /opt/rocm.`,
'clusters.addworker.message.success':
- '{count} workers have been added to the cluster.'
+ '{count} workers have been added to the cluster.',
+ 'clusters.create.serverUrl': 'Server URL',
+ 'clusters.create.workerConfig': 'Worker Configuration'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -167,5 +169,7 @@ Same applies to the /opt/dtk directory.`,
// 71. 'clusters.addworker.cacheVolume': 'Model Cache Volume Mount',
// 72. 'clusters.addworker.cacheVolume.tips': 'If you want to customize the model cache directory, you can specify the path to mount it.',
// 73. 'clusters.addworker.cacheVolume.holder': 'e.g. /data/cache (path must start with /)',
-// 74. 'clusters.addworker.message.success': '{count} workers have been added to the cluster.'
+// 74. 'clusters.addworker.message.success': '{count} workers have been added to the cluster.',
+// 75. 'clusters.create.serverUrl': 'Server URL',
+// 76. 'clusters.create.workerConfig': 'Worker Configuration'
// ========== End of To-Do List ==========
diff --git a/src/locales/ru-RU/clusters.ts b/src/locales/ru-RU/clusters.ts
index 46ff3f38..67fe2153 100644
--- a/src/locales/ru-RU/clusters.ts
+++ b/src/locales/ru-RU/clusters.ts
@@ -90,7 +90,9 @@ export default {
'Need to create a new token? Click here.',
'clusters.addworker.amdNotes-01': `If the /opt/rocm directory does not exist, please create a symbolic link pointing to the ROCm installed path: ln -s /path/to/rocm /opt/rocm.`,
'clusters.addworker.message.success':
- '{count} workers have been added to the cluster.'
+ '{count} workers have been added to the cluster.',
+ 'clusters.create.serverUrl': 'Server URL',
+ 'clusters.create.workerConfig': 'Worker Configuration'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -98,5 +100,7 @@ export default {
// 2. 'clusters.button.genToken': 'Need to create a new token? Click here.',
// 3. 'clusters.addworker.cacheVolume': 'Model Cache Volume Mount',
// 4. 'clusters.addworker.cacheVolume.tips': 'If you want to customize the model cache directory, you can specify the path to mount it.',
-// 5. 'clusters.addworker.message.success': '{count} workers have been added to the cluster.'
+// 5. 'clusters.addworker.message.success': '{count} workers have been added to the cluster.',
+// 6. 'clusters.create.serverUrl': 'Server URL',
+// 7. 'clusters.create.workerConfig': 'Worker Configuration'
// ================================================================
diff --git a/src/locales/zh-CN/clusters.ts b/src/locales/zh-CN/clusters.ts
index 5f6d220c..d6fd0c3d 100644
--- a/src/locales/zh-CN/clusters.ts
+++ b/src/locales/zh-CN/clusters.ts
@@ -88,5 +88,7 @@ export default {
'需要创建令牌?点击这里。',
'clusters.addworker.amdNotes-01':
'如果 /opt/rocm 目录不存在,请创建一个指向已安装 ROCm 路径的符号链接:ln -s /path/to/rocm /opt/rocm。',
- 'clusters.addworker.message.success': '已将 {count} 个工作节点添加到集群中。'
+ 'clusters.addworker.message.success': '已将 {count} 个工作节点添加到集群中。',
+ 'clusters.create.serverUrl': '服务器地址',
+ 'clusters.create.workerConfig': '节点配置'
};
diff --git a/src/pages/backends/components/yaml-editor.tsx b/src/pages/_components/yaml-editor/editor.tsx
similarity index 81%
rename from src/pages/backends/components/yaml-editor.tsx
rename to src/pages/_components/yaml-editor/editor.tsx
index 3bdcb365..ec9aa68d 100644
--- a/src/pages/backends/components/yaml-editor.tsx
+++ b/src/pages/_components/yaml-editor/editor.tsx
@@ -1,6 +1,4 @@
import EditorWrap from '@/components/editor-wrap';
-import { PageAction } from '@/config';
-import { PageActionType } from '@/config/types';
import { LoadingOutlined } from '@ant-design/icons';
import Editor, { loader } from '@monaco-editor/react';
import * as monaco from 'monaco-editor';
@@ -11,15 +9,11 @@ import React, {
useImperativeHandle,
useRef
} from 'react';
-import createSchema from '../config/schema/create.json';
-import updateBuiltinSchema from '../config/schema/update-builtin.json';
-import udpateCustomSchema from '../config/schema/update-custom.json';
loader.config({ monaco });
interface ViewerProps {
ref?: any;
- lang: string;
defaultLang?: string;
config?: any;
value: string;
@@ -28,22 +22,19 @@ interface ViewerProps {
header?: React.ReactNode;
placeholder?: string;
variant?: 'bordered' | 'borderless';
- actionStatus: {
- action: PageActionType;
- isBuiltIn: boolean;
- };
+ schema?: any;
}
const path = 'inmemory://model/config.yaml';
-const ViewerEditor: React.FC = forwardRef((props, ref) => {
+const EditorInner: React.FC = forwardRef((props, ref) => {
const {
value,
height = 380,
theme = 'vs-dark',
header,
variant = 'borderless',
- actionStatus,
+ schema,
placeholder
} = props;
@@ -59,12 +50,7 @@ const ViewerEditor: React.FC = forwardRef((props, ref) => {
{
uri: 'http://example.com/schema-name.json',
fileMatch: [yamlUri.toString()],
- schema:
- actionStatus.action === PageAction.CREATE
- ? createSchema
- : actionStatus.isBuiltIn
- ? updateBuiltinSchema
- : udpateCustomSchema
+ schema: schema
}
]
});
@@ -151,4 +137,4 @@ const ViewerEditor: React.FC = forwardRef((props, ref) => {
);
});
-export default ViewerEditor;
+export default EditorInner;
diff --git a/src/pages/_components/yaml-editor/index.tsx b/src/pages/_components/yaml-editor/index.tsx
new file mode 100644
index 00000000..24ff2aba
--- /dev/null
+++ b/src/pages/_components/yaml-editor/index.tsx
@@ -0,0 +1,172 @@
+import useUserSettings from '@/hooks/use-user-settings';
+import { ImportOutlined } from '@ant-design/icons';
+import { loader } from '@monaco-editor/react';
+import { useIntl } from '@umijs/max';
+import { Button, message, Typography, Upload } from 'antd';
+import { RcFile } from 'antd/lib/upload';
+import * as monaco from 'monaco-editor';
+import React, {
+ forwardRef,
+ useEffect,
+ useImperativeHandle,
+ useRef
+} from 'react';
+import styled from 'styled-components';
+import EditorInner from './editor';
+
+const { Text } = Typography;
+
+loader.config({ monaco });
+
+const Container = styled.div`
+ position: relative;
+ border: 1px solid var(--ant-color-border);
+ border-radius: var(--ant-border-radius);
+ .monaco-editor .scroll-decoration {
+ box-shadow: none;
+ }
+`;
+
+const ErrorText = styled(Text)`
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 4px 6px;
+ background-color: var(--ant-color-bg-elevated);
+ border-radius: 0 0 var(--ant-border-radius) var(--ant-border-radius);
+`;
+
+const Header = styled.div`
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 40px;
+ padding-inline: 10px;
+ font-size: 14px;
+ border-bottom: 1px solid var(--ant-color-border);
+ background-color: var(--ant-color-fill-tertiary);
+`;
+
+interface ViewerProps {
+ ref?: any;
+ title?: React.ReactNode;
+ defaultLang?: string;
+ config?: any;
+ value: string;
+ height?: string | number;
+ placeholder?: string;
+ variant?: 'bordered' | 'borderless';
+ validateMessage?: React.ReactNode;
+ schema?: any;
+ onUpload?: (content: string) => void;
+}
+
+const YamlEditor: React.FC = forwardRef((props, ref) => {
+ const {
+ value,
+ height = 380,
+ variant = 'borderless',
+ schema,
+ placeholder,
+ validateMessage,
+ title,
+ onUpload
+ } = props;
+
+ const intl = useIntl();
+ const { userSettings } = useUserSettings();
+
+ const editorRef = useRef(null);
+
+ const setContent = (val: string) => {
+ editorRef.current?.setValue?.(val);
+ };
+
+ const beforeUpload = (file: RcFile) => {
+ const isYaml =
+ file.type === 'application/x-yaml' ||
+ file.type === 'text/yaml' ||
+ file.name.endsWith('.yaml') ||
+ file.name.endsWith('.yml');
+ if (!isYaml) {
+ message.error('You can only upload YAML file!');
+ }
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const content = e.target?.result;
+ if (typeof content === 'string') {
+ onUpload?.(content);
+ setContent(content);
+ } else {
+ message.error('Failed to read file content!');
+ }
+ };
+ reader.readAsText(file);
+ // Prevent upload
+ return false;
+ };
+
+ const renderHeader = () => {
+ return (
+
+ {title || 'YAML'}
+
+ } type="text" size="small">
+ {intl.formatMessage({ id: 'common.button.import' })}
+
+
+
+ );
+ };
+
+ useImperativeHandle(ref, () => ({
+ format: () => {
+ editorRef.current?.format();
+ },
+ getValue: () => {
+ return editorRef.current?.getValue?.();
+ },
+ setValue: (val: string) => {
+ editorRef.current?.setValue?.(val);
+ },
+ dispose: () => {
+ editorRef.current?.dispose?.();
+ },
+ validate() {
+ return editorRef.current?.validate();
+ },
+ editor: editorRef.current
+ }));
+
+ useEffect(() => {
+ editorRef.current?.format();
+ }, [value]);
+
+ return (
+
+
+ {validateMessage && (
+ {validateMessage}
+ )}
+
+ );
+});
+
+export default YamlEditor;
diff --git a/src/pages/backends/components/import-yaml.tsx b/src/pages/backends/components/import-yaml.tsx
index 7e2fd88e..a3cf2276 100644
--- a/src/pages/backends/components/import-yaml.tsx
+++ b/src/pages/backends/components/import-yaml.tsx
@@ -1,51 +1,17 @@
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
-import useUserSettings from '@/hooks/use-user-settings';
-import { ImportOutlined } from '@ant-design/icons';
+import YamlEditor from '@/pages/_components/yaml-editor';
import { useIntl } from '@umijs/max';
-import { Button, message, Typography, Upload } from 'antd';
-import { RcFile } from 'antd/lib/upload';
import React, {
forwardRef,
useImperativeHandle,
useRef,
useState
} from 'react';
-import styled from 'styled-components';
import { yaml2Json, yamlTemplate } from '../config';
-import YamlEditor from './yaml-editor';
-
-const { Text } = Typography;
-
-const ErrorText = styled(Text)`
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 4px 6px;
- background-color: var(--ant-color-bg-elevated);
- border-radius: 0 0 var(--ant-border-radius) var(--ant-border-radius);
-`;
-
-const Header = styled.div`
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 40px;
- padding-inline: 10px;
- border-bottom: 1px solid var(--ant-color-border);
- background-color: var(--ant-color-fill-tertiary);
-`;
-
-const Container = styled.div`
- position: relative;
- border: 1px solid var(--ant-color-border);
- border-radius: var(--ant-border-radius);
- .monaco-editor .scroll-decoration {
- box-shadow: none;
- }
-`;
+import createSchema from '../config/schema/create.json';
+import updateBuiltinSchema from '../config/schema/update-builtin.json';
+import udpateCustomSchema from '../config/schema/update-custom.json';
interface ImportYAMLProps {
ref?: any;
@@ -60,7 +26,6 @@ interface ImportYAMLProps {
const ImportYAML: React.FC = forwardRef(
({ actionStatus, content = '' }, ref) => {
const intl = useIntl();
- const { userSettings } = useUserSettings();
const editorRef = useRef(null);
const [fileContent, setFileContent] = useState(
actionStatus.action === PageAction.CREATE ? yamlTemplate : content
@@ -71,30 +36,6 @@ const ImportYAML: React.FC = forwardRef(
editorRef.current?.setValue?.(val);
};
- const beforeUpload = (file: RcFile) => {
- const isYaml =
- file.type === 'application/x-yaml' ||
- file.type === 'text/yaml' ||
- file.name.endsWith('.yaml') ||
- file.name.endsWith('.yml');
- if (!isYaml) {
- message.error('You can only upload YAML file!');
- }
- const reader = new FileReader();
- reader.onload = (e) => {
- const content = e.target?.result;
- if (typeof content === 'string') {
- setFileContent(content);
- setContent(content);
- } else {
- message.error('Failed to read file content!');
- }
- };
- reader.readAsText(file);
- // Prevent upload
- return false;
- };
-
const validate = () => {
const markers = editorRef.current?.validate();
if (markers && markers.length > 0) {
@@ -152,25 +93,6 @@ const ImportYAML: React.FC = forwardRef(
}
};
- const renderHeader = () => {
- return (
-
- YAML
-
- } type="text" size="small">
- {intl.formatMessage({ id: 'common.button.import' })}
-
-
-
- );
- };
-
useImperativeHandle(ref, () => ({
getContent: () => {
return getContent();
@@ -182,18 +104,23 @@ const ImportYAML: React.FC = forwardRef(
}));
return (
-
-
- {error && {error}}
-
+ {
+ setError('');
+ setContent(content);
+ }}
+ schema={
+ actionStatus.action === PageAction.CREATE
+ ? createSchema
+ : actionStatus.isBuiltIn
+ ? updateBuiltinSchema
+ : udpateCustomSchema
+ }
+ >
);
}
);
diff --git a/src/pages/cluster-management/components/cluster-form.tsx b/src/pages/cluster-management/components/cluster-form.tsx
index 3e0499b3..22567586 100644
--- a/src/pages/cluster-management/components/cluster-form.tsx
+++ b/src/pages/cluster-management/components/cluster-form.tsx
@@ -1,6 +1,8 @@
import SealInput from '@/components/seal-form/seal-input';
import SealTextArea from '@/components/seal-form/seal-textarea';
import { PageActionType } from '@/config/types';
+import CollapsePanel from '@/pages/_components/collapse-panel';
+import { json2Yaml, yaml2Json } from '@/pages/backends/config';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
@@ -9,6 +11,7 @@ import {
ClusterFormData as FormData,
ClusterListItem as ListItem
} from '../config/types';
+import AdvanceConfig from '../step-forms/advance-config';
import CloudProvider from './cloud-provider-form';
type AddModalProps = {
@@ -23,12 +26,27 @@ const ClusterForm: React.FC = forwardRef(
({ action, provider, currentData, credentialList, onFinish }, ref) => {
const [form] = Form.useForm();
const intl = useIntl();
+ const [activeKey, setActiveKey] = React.useState([]);
+ const advanceConfigRef = React.useRef(null);
+
+ const handleOnCollapseChange = (keys: string | string[]) => {
+ setActiveKey(Array.isArray(keys) ? keys : [keys]);
+ if (currentData && advanceConfigRef.current) {
+ }
+ };
useEffect(() => {
if (currentData) {
form.setFieldsValue(currentData);
+
+ if (advanceConfigRef.current) {
+ const workerConfigYaml = json2Yaml({
+ worker_config: currentData.worker_config || {}
+ });
+ advanceConfigRef.current?.setYamlValue(workerConfigYaml);
+ }
}
- }, [currentData]);
+ }, [currentData, advanceConfigRef.current]);
useImperativeHandle(ref, () => ({
resetFields: () => {
@@ -44,7 +62,15 @@ const ClusterForm: React.FC = forwardRef(
return form.getFieldsValue();
},
validateFields: async () => {
- return await form.validateFields();
+ const values = await form.validateFields();
+ const workerConfig = yaml2Json(
+ advanceConfigRef.current?.getYamlValue()
+ );
+
+ return {
+ ...values,
+ ...workerConfig
+ };
}
}));
@@ -91,6 +117,24 @@ const ClusterForm: React.FC = forwardRef(
label={intl.formatMessage({ id: 'common.table.description' })}
>
+
+ )
+ }
+ ]}
+ >
);
}
diff --git a/src/pages/cluster-management/config/types.ts b/src/pages/cluster-management/config/types.ts
index c8a5ba70..7ca3c971 100644
--- a/src/pages/cluster-management/config/types.ts
+++ b/src/pages/cluster-management/config/types.ts
@@ -53,6 +53,7 @@ export interface ClusterListItem {
name: string;
display_name: string;
description: string;
+ worker_config: Record;
provider: ProviderType;
credential_id: number;
zone: string;
@@ -74,5 +75,7 @@ export interface ClusterFormData {
credential_id: number;
zone: string;
region: string;
+ server_url?: string;
+ worker_config?: Record;
worker_pools?: NodePoolFormData[];
}
diff --git a/src/pages/cluster-management/config/worker-config.json b/src/pages/cluster-management/config/worker-config.json
new file mode 100644
index 00000000..8f81f734
--- /dev/null
+++ b/src/pages/cluster-management/config/worker-config.json
@@ -0,0 +1,119 @@
+{
+ "type": "object",
+ "properties": {
+ "worker_config": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "debug": {
+ "type": "boolean",
+ "description": "Enable debug mode"
+ },
+ "cache_dir": {
+ "type": "string",
+ "description": "Cache directory path"
+ },
+ "log_dir": {
+ "type": "string",
+ "description": "Log directory path"
+ },
+ "bin_dir": {
+ "type": "string",
+ "description": "Binary directory path"
+ },
+ "system_default_container_registry": {
+ "type": "string",
+ "description": "Default container registry"
+ },
+ "image_name_override": {
+ "type": "string",
+ "description": "Override image name"
+ },
+ "image_repo": {
+ "type": "string",
+ "description": "Container image repository"
+ },
+ "gateway_mode": {
+ "type": "string",
+ "description": "Gateway mode",
+ "enum": ["worker", "gateway", "disabled"]
+ },
+ "gateway_kubeconfig": {
+ "type": "string",
+ "description": "Path to kubeconfig used by gateway"
+ },
+ "gateway_concurrency": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Gateway concurrency limit"
+ },
+ "service_discovery_name": {
+ "type": "string",
+ "description": "Service discovery name"
+ },
+ "namespace": {
+ "type": "string",
+ "description": "Kubernetes namespace"
+ },
+ "huggingface_token": {
+ "type": "string",
+ "description": "Hugging Face access token"
+ },
+ "disable_worker_metrics": {
+ "type": "boolean",
+ "description": "Disable worker metrics collection"
+ },
+ "worker_port": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 65535,
+ "description": "Worker service port"
+ },
+ "worker_metrics_port": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 65535,
+ "description": "Worker metrics port"
+ },
+ "service_port_range": {
+ "type": "string",
+ "pattern": "^\\d+-\\d+$",
+ "description": "Service port range, e.g. 30000-31000"
+ },
+ "ray_port_range": {
+ "type": "string",
+ "pattern": "^\\d+-\\d+$",
+ "description": "Ray port range, e.g. 20000-20100"
+ },
+ "resources": {
+ "type": "object",
+ "description": "Additional resource definitions",
+ "additionalProperties": {
+ "type": "object"
+ }
+ },
+ "pipx_path": {
+ "type": "string",
+ "description": "pipx installation path"
+ },
+ "tools_download_base_url": {
+ "type": "string",
+ "description": "Base URL for downloading tools"
+ },
+ "enable_hf_transfer": {
+ "type": "boolean",
+ "description": "Enable Hugging Face transfer acceleration"
+ },
+ "enable_hf_xet": {
+ "type": "boolean",
+ "description": "Enable Hugging Face Xet support"
+ },
+ "proxy_mode": {
+ "type": "string",
+ "enum": ["worker", "system", "disabled"],
+ "description": "Proxy mode"
+ }
+ }
+ }
+ }
+}
diff --git a/src/pages/cluster-management/config/yaml-template.ts b/src/pages/cluster-management/config/yaml-template.ts
new file mode 100644
index 00000000..766c6f03
--- /dev/null
+++ b/src/pages/cluster-management/config/yaml-template.ts
@@ -0,0 +1,53 @@
+export default `# This is a template for worker_config.
+
+worker_config:
+ debug: true
+
+ # directories
+ cache_dir:
+ log_dir:
+ bin_dir:
+
+ # container & image
+ system_default_container_registry:
+ image_repo: gpustack/worker
+ image_name_override: ""
+
+ # gateway
+ gateway_mode:
+ gateway_concurrency: 0
+ gateway_kubeconfig: ""
+
+ # service & networking
+ service_discovery_name:
+ namespace: default
+ worker_port:
+ worker_metrics_port:
+ service_port_range:
+ ray_port_range:
+
+ # resources
+ resources:
+ gpu:
+ count:
+ type:
+ cpu:
+ limit:
+ memory:
+ limit:
+
+ # huggingface
+ huggingface_token: ""
+ enable_hf_transfer: true
+ enable_hf_xet: true
+
+ # metrics
+ disable_worker_metrics: false
+
+ # tools & runtime
+ pipx_path:
+ tools_download_base_url:
+
+ # proxy
+ proxy_mode: worker
+`;
diff --git a/src/pages/cluster-management/step-forms/advance-config.tsx b/src/pages/cluster-management/step-forms/advance-config.tsx
new file mode 100644
index 00000000..b7144fbb
--- /dev/null
+++ b/src/pages/cluster-management/step-forms/advance-config.tsx
@@ -0,0 +1,75 @@
+import SealInput from '@/components/seal-form/seal-input';
+import { PageActionType } from '@/config/types';
+import YamlEditor from '@/pages/_components/yaml-editor';
+import { useIntl } from '@umijs/max';
+import { Form } from 'antd';
+import React, { forwardRef, useImperativeHandle } from 'react';
+import { ClusterFormData as FormData } from '../config/types';
+import schema from '../config/worker-config.json';
+import yamlTemplate from '../config/yaml-template';
+
+const ClusterAdvanceConfig: React.FC<{ action: PageActionType; ref?: any }> =
+ forwardRef(({ action }, ref) => {
+ const [form] = Form.useForm();
+ const intl = useIntl();
+ const editorRef = React.useRef(null);
+ const [fileContent, setFileContent] = React.useState('');
+
+ useImperativeHandle(ref, () => ({
+ getYamlValue: () => {
+ return editorRef.current?.getValue();
+ },
+ setYamlValue: (values: any) => {
+ console.log('setYamlValue:', values, editorRef.current);
+ editorRef.current?.setValue(values);
+ }
+ }));
+
+ return (
+ <>
+
+ name="server_url"
+ rules={[
+ {
+ required: false,
+ message: ''
+ }
+ ]}
+ >
+
+
+
+ hidden
+ name="worker_config"
+ rules={[
+ {
+ required: false,
+ message: ''
+ }
+ ]}
+ >
+
+
+ {
+ setFileContent(content);
+ }}
+ schema={schema}
+ placeholder={yamlTemplate}
+ >
+ >
+ );
+ });
+
+export default ClusterAdvanceConfig;