This is an automated email from the ASF dual-hosted git repository.
jiafengzheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris-manager.git
The following commit(s) were added to refs/heads/master by this push:
new 4987e02 [fix] fix manager1.0.0 frontend bugs (#13)
4987e02 is described below
commit 4987e024dadb60808f184b8eadd484cdf5fc218a
Author: zhengbowen <[email protected]>
AuthorDate: Wed Mar 23 16:12:44 2022 +0800
[fix] fix manager1.0.0 frontend bugs (#13)
[fix] fix manager1.0.0 frontend bugs
---
frontend/src/components/sidebar/sidebar.tsx | 16 +++--
.../index.module.less => cluster/cluster.utils.ts} | 28 ++------
.../routes/cluster/configuration/check-modal.tsx | 4 +-
.../routes/cluster/configuration/edit-modal.tsx | 31 ++++++---
.../routes/space/access-cluster/access-cluster.tsx | 79 +++++++++++++++-------
.../steps/cluster-verify/cluster-verify.tsx | 65 +++++++++++-------
.../steps/connect-cluster/connect-cluster.tsx | 50 +++++++-------
.../space/components/node-verify/node-verify.tsx | 60 ++++++++++++----
.../src/routes/space/new-cluster/new-cluster.tsx | 36 +++++++---
.../space/new-cluster/steps/add-node/add-node.tsx | 38 +++++------
.../steps/add-node/node-list/node-list.tsx | 29 ++++++--
.../steps/cluster-deploy/cluster-deploy.tsx | 6 +-
.../steps/cluster-plan/cluster-plan.tsx | 56 +++++++++++++--
.../steps/install-options/install-options.tsx | 11 ---
.../index.module.less => space/space.utils.ts} | 32 +++------
frontend/src/routes/user-setting/index.module.less | 1 -
16 files changed, 335 insertions(+), 207 deletions(-)
diff --git a/frontend/src/components/sidebar/sidebar.tsx
b/frontend/src/components/sidebar/sidebar.tsx
index 2cebec4..6cc564c 100644
--- a/frontend/src/components/sidebar/sidebar.tsx
+++ b/frontend/src/components/sidebar/sidebar.tsx
@@ -25,14 +25,14 @@ import {
TableOutlined,
AppstoreOutlined,
} from '@ant-design/icons';
-import { Link, useHistory } from 'react-router-dom';
-import React, { useState, useEffect, useContext } from 'react';
+import { Link, useHistory, useLocation } from 'react-router-dom';
+import React, { useState, useEffect, useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import styles from './sidebar.less';
import { UserInfoContext } from '@src/common/common.context';
-const GLOBAL_PATHS = ['/settings', '/space'];
+const GLOBAL_PATHS = ['/settings', '/space', '/user-setting'];
export function Sidebar(props: any) {
const { t } = useTranslation();
@@ -42,9 +42,14 @@ export function Sidebar(props: any) {
const user = useContext(UserInfoContext);
const history = useHistory();
+ const { pathname } = useLocation();
const isSuperAdmin = user?.is_super_admin;
const isSpaceAdmin = user?.is_admin;
const isInSpace = !GLOBAL_PATHS.includes(selectedKeys);
+ const logoRoute = useMemo(
+ () => (GLOBAL_PATHS.some(path => pathname.startsWith(path)) ? '/space'
: '/cluster'),
+ [pathname],
+ );
useEffect(() => {
if (history.location.pathname.includes('configuration')) {
setSelectedKeys('/configuration');
@@ -130,10 +135,9 @@ export function Sidebar(props: any) {
alignItems: 'center',
}}
key="/logo"
+ onClick={() => history.push(logoRoute)}
>
- <div
- className={collapsed ? styles['logo-collapsed'] :
styles['logo']}
- />
+ <div className={collapsed ? styles['logo-collapsed'] :
styles['logo']} />
</Menu.Item>
{isInSpace && (
<>
diff --git a/frontend/src/routes/user-setting/index.module.less
b/frontend/src/routes/cluster/cluster.utils.ts
similarity index 66%
copy from frontend/src/routes/user-setting/index.module.less
copy to frontend/src/routes/cluster/cluster.utils.ts
index 9d2eaba..522dbf7 100644
--- a/frontend/src/routes/user-setting/index.module.less
+++ b/frontend/src/routes/cluster/cluster.utils.ts
@@ -14,29 +14,9 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-.tabs {
- transform: translate(35em, 0);
-}
-
-.input-gird {
- margin: 0 auto;
- width: 420px;
- // padding: 32px;
-
- line-height: 24px;
- background-color: #fff;
- border-radius: 6px;
- box-shadow: rgb(0 0 0 / 8%) 0 7px 20px;
- transition: all 0.2s linear 0s;
-
- input {
- width: 100%;
- padding: 0.75em;
- background: '#e8f0fe';
- border-radius: 4px;
- }
-}
-.input-pass {
- background: '#e8f0fe';
+export function transformHostToIp(host: string) {
+ if (!host.includes(':')) return host;
+ const sliceIndex = host.indexOf(':');
+ return host.slice(0, sliceIndex);
}
diff --git a/frontend/src/routes/cluster/configuration/check-modal.tsx
b/frontend/src/routes/cluster/configuration/check-modal.tsx
index b6209bd..6d4ad96 100644
--- a/frontend/src/routes/cluster/configuration/check-modal.tsx
+++ b/frontend/src/routes/cluster/configuration/check-modal.tsx
@@ -15,10 +15,11 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useState } from 'react';
+import React from 'react';
import { Button, Modal, Table } from 'antd';
import { useTranslation } from 'react-i18next';
import { ConfigurationItem } from '.';
+import { transformHostToIp } from '../cluster.utils';
interface CheckModalProps {
visible: boolean;
@@ -38,6 +39,7 @@ export default function CheckModal(props: CheckModalProps) {
{
title: t`hostIp`,
dataIndex: 'host',
+ render: (host: string) => transformHostToIp(host),
},
{
title: t`currentValue`,
diff --git a/frontend/src/routes/cluster/configuration/edit-modal.tsx
b/frontend/src/routes/cluster/configuration/edit-modal.tsx
index 38f33f3..d09d861 100644
--- a/frontend/src/routes/cluster/configuration/edit-modal.tsx
+++ b/frontend/src/routes/cluster/configuration/edit-modal.tsx
@@ -21,6 +21,7 @@ import { useTranslation } from 'react-i18next';
import { ConfigurationItem } from '.';
import { useAsync } from '@src/hooks/use-async';
import * as ClusterAPI from '../cluster.api';
+import { transformHostToIp } from '../cluster.utils';
interface EditModalProps {
visible: boolean;
@@ -33,12 +34,18 @@ interface FormInstanceProps {
value: string;
persist: boolean;
range: 'all' | 'part';
- nodes: number[];
+ nodes: string[];
+}
+
+const enum RangeEnum {
+ ALL = 'ALL',
+ PART = 'PART',
}
export default function EditModal(props: EditModalProps) {
const { t } = useTranslation();
const { visible, currentParameter, onOk, onCancel } = props;
+ const [range, setRange] = useState<RangeEnum>(RangeEnum.ALL);
const { loading: confirmLoading, run: runChangeConfiguration } =
useAsync();
const [form] = Form.useForm<FormInstanceProps>();
@@ -48,7 +55,7 @@ export default function EditModal(props: EditModalProps) {
runChangeConfiguration(
ClusterAPI.changeConfiguration(currentParameter.type ===
'Frontend' ? 'fe' : 'be', {
[currentParameter.name]: {
- node: [...currentParameter.nodes],
+ node: [...(range === RangeEnum.ALL ?
currentParameter.nodes : values.nodes)],
value: values.value,
persist: values.persist ? 'true' : 'false',
},
@@ -68,7 +75,7 @@ export default function EditModal(props: EditModalProps) {
const handleCancel = () => {
form.resetFields();
- // setRange('all');
+ setRange(RangeEnum.ALL);
onCancel();
};
@@ -99,7 +106,7 @@ export default function EditModal(props: EditModalProps) {
<Radio value={false}>{t`onceEffective`}</Radio>
</Radio.Group>
</Form.Item>
- {/* <Form.Item
+ <Form.Item
name="range"
label={t`effectiveRange`}
rules={[{ required: true, message:
t`effectiveRangeRequiredMessage` }]}
@@ -109,21 +116,25 @@ export default function EditModal(props: EditModalProps) {
setRange(e.target.value);
}}
>
- <Radio value="all">{t`allNodes`}</Radio>
- <Radio value="part">{t`certainNodes`}</Radio>
+ <Radio value={RangeEnum.ALL}>{t`allNodes`}</Radio>
+ <Radio value={RangeEnum.PART}>{t`certainNodes`}</Radio>
</Radio.Group>
- </Form.Item> */}
- {/* {range === 'part' && (
+ </Form.Item>
+ {range === RangeEnum.PART && (
<Form.Item
name="nodes"
label={t`effectiveNodes`}
rules={[{ required: true, message:
t`effectiveNodesPlaceholder` }]}
>
<Select mode="multiple"
placeholder={t`effectiveNodesPlaceholder`}>
- <Select.Option value="1">127.0.0.1</Select.Option>
+ {currentParameter.nodes.map(nodeHost => (
+ <Select.Option key={nodeHost} value={nodeHost}>
+ {transformHostToIp(nodeHost)}
+ </Select.Option>
+ ))}
</Select>
</Form.Item>
- )} */}
+ )}
</Form>
</Modal>
);
diff --git a/frontend/src/routes/space/access-cluster/access-cluster.tsx
b/frontend/src/routes/space/access-cluster/access-cluster.tsx
index 0fa5bf0..eefec29 100644
--- a/frontend/src/routes/space/access-cluster/access-cluster.tsx
+++ b/frontend/src/routes/space/access-cluster/access-cluster.tsx
@@ -35,16 +35,22 @@ import { useRecoilState, useRecoilValue } from 'recoil';
import { requestInfoState, stepDisabledState } from './access-cluster.recoil';
import { ClusterVerify } from './steps/cluster-verify/cluster-verify';
import { SpaceAccessFinish } from './steps/finish/finish';
+import { checkParam } from '../space.utils';
const { Step } = Steps;
export function AccessCluster(props: any) {
- const match = useRouteMatch<{requestId: string}>();
+ const match = useRouteMatch<{ requestId: string }>();
const history = useHistory();
const [step, setStep] = React.useState(0);
const [loading, setLoading] = useState(false);
const [requestInfo, setRequestInfo] = useRecoilState(requestInfoState);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
- const hidePrevSteps = [AccessClusterStepsEnum['space-register'],
AccessClusterStepsEnum['node-verify'],
AccessClusterStepsEnum['cluster-verify'], AccessClusterStepsEnum.finish];
+ const hidePrevSteps = [
+ AccessClusterStepsEnum['space-register'],
+ AccessClusterStepsEnum['node-verify'],
+ AccessClusterStepsEnum['cluster-verify'],
+ AccessClusterStepsEnum.finish,
+ ];
useEffect(() => {
if (history.location.pathname === '/space/list') {
@@ -55,9 +61,9 @@ export function AccessCluster(props: any) {
const step = (paths as string[])[2];
setStep(AccessClusterStepsEnum[step]);
- setStepDisabled({...stepDisabled, next: false});
+ setStepDisabled({ ...stepDisabled, next: false });
- if (match.params.requestId && +match.params.requestId !== 0) {
+ if (match.params.requestId && +match.params.requestId !== 0) {
getRequestInfo();
}
}, [history.location.pathname]);
@@ -74,20 +80,23 @@ export function AccessCluster(props: any) {
async function nextStep() {
const value = form.getFieldsValue();
+ let isParamsValid = true;
const newStep = step + 1;
- setLoading(true);
const params: ClusterAccessParams = {
...requestInfo.reqInfo,
cluster_id: requestInfo.clusterId,
request_id: requestInfo.requestId,
event_type: (step + 1).toString(),
- }
- if (value && step === AccessClusterStepsEnum['space-register']) {
+ };
+ if (value && step === AccessClusterStepsEnum['space-register']) {
params.spaceInfo = {
describe: value.describe,
name: value.name,
spaceAdminUsers: value.spaceAdminUsers,
- }
+ };
+ isParamsValid =
+ checkParam(params.spaceInfo.name, '请填写空间名称') &&
+ checkParam(params.spaceInfo.spaceAdminUsers, '请填写管理员姓名');
}
if (value && step === AccessClusterStepsEnum['connect-cluster']) {
params.clusterAccessInfo = {
@@ -97,7 +106,12 @@ export function AccessCluster(props: any) {
queryPort: value.queryPort,
type: value.type,
user: value.user,
- }
+ };
+ isParamsValid =
+ checkParam(params.clusterAccessInfo.address, '请填写集群地址') &&
+ checkParam(params.clusterAccessInfo.httpPort, '请填写HTTP端口') &&
+ checkParam(params.clusterAccessInfo.queryPort, '请填写JDBC端口') &&
+ checkParam(params.clusterAccessInfo.user, '请填写集群用户名');
}
if (value && step === AccessClusterStepsEnum['managed-options']) {
@@ -105,30 +119,34 @@ export function AccessCluster(props: any) {
sshKey: value.sshKey,
sshPort: value.sshPort,
sshUser: value.sshUser,
- }
- params.installInfo = value.installInfo
+ };
+ params.installInfo = value.installInfo;
+ isParamsValid =
+ checkParam(params.authInfo.sshUser, '请填写SSH用户') &&
+ checkParam(params.authInfo.sshPort, '请填写SSH端口') &&
+ checkParam(params.authInfo.sshKey, '请填写SSH私钥') &&
+ checkParam(params.installInfo, '请填写安装路径')
}
-
+ if (!isParamsValid) return;
+ setLoading(true);
const res = await SpaceAPI.accessCluster(params);
setLoading(false);
if (isSuccess(res)) {
setRequestInfo(res.data);
setStep(newStep);
- setStepDisabled({...stepDisabled, next: false});
+ setStepDisabled({ ...stepDisabled, next: false });
setTimeout(() => {
history.push(`/space/access/${res.data.requestId}/${AccessClusterStepsEnum[newStep]}`);
- }, 0)
-
+ }, 0);
} else {
message.error(res.msg);
}
}
-
function prevStep() {
const newStep = step - 1;
setStep(newStep);
- setStepDisabled({...stepDisabled, prev: false});
+ setStepDisabled({ ...stepDisabled, prev: false });
history.push(`/space/access/${requestInfo.requestId}/${AccessClusterStepsEnum[newStep]}`);
}
@@ -138,11 +156,13 @@ export function AccessCluster(props: any) {
return (
<>
- <NewSpaceInfoContext.Provider value={{
- step,
- form,
- reqInfo: requestInfo.reqInfo || {authInfo: {}, spaceInfo: {},
clusterAccessInfo: {} }
- }}>
+ <NewSpaceInfoContext.Provider
+ value={{
+ step,
+ form,
+ reqInfo: requestInfo.reqInfo || { authInfo: {}, spaceInfo:
{}, clusterAccessInfo: {} },
+ }}
+ >
<ProCard style={{ marginTop: 20 }}>
<div style={{ position: 'fixed', top: 80, right: 80 }}>
<Steps direction="vertical" current={step} style={{
padding: '20px 0 40px 0' }}>
@@ -157,11 +177,20 @@ export function AccessCluster(props: any) {
<div style={{ marginRight: 240 }}>
<CacheSwitch>
<CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[0]}`} component={SpaceRegister} />
- <CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[1]}`} component={ConnectCluster}
/>
- <CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[2]}`} component={ManagedOptions}
/>
+ <CacheRoute
+
path={`${match.path}/${AccessClusterStepsEnum[1]}`}
+ component={ConnectCluster}
+ />
+ <CacheRoute
+
path={`${match.path}/${AccessClusterStepsEnum[2]}`}
+ component={ManagedOptions}
+ />
<CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[3]}`} component={NodeVerify} />
<CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[4]}`} component={ClusterVerify} />
- <CacheRoute
path={`${match.path}/${AccessClusterStepsEnum[5]}`}
component={SpaceAccessFinish} />
+ <CacheRoute
+
path={`${match.path}/${AccessClusterStepsEnum[5]}`}
+ component={SpaceAccessFinish}
+ />
<Redirect
to={`${match.path}/${AccessClusterStepsEnum[0]}`} />
</CacheSwitch>
<Row justify="end" style={{ marginTop: 20 }}>
diff --git
a/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
b/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
index e46e891..20143ef 100644
---
a/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
+++
b/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
@@ -30,12 +30,15 @@ import { IResult } from '@src/interfaces/http.interface';
import { OperateStatusEnum } from '@src/routes/space/space.data';
import { useRecoilState } from 'recoil';
import { stepDisabledState } from '../../access-cluster.recoil';
+import { LoadingOutlined } from '@ant-design/icons';
const Step = Steps.Step;
+const ERROR_STATUS = [OperateStatusEnum.FAIL, OperateStatusEnum.CANCEL];
+
export function ClusterVerify(props: any) {
const [activeKey, setActiveKey] = useState(DorisNodeTypeEnum.FE);
- const {reqInfo} = useContext(NewSpaceInfoContext);
- const match = useRouteMatch<{spaceId: string}>();
+ const { reqInfo } = useContext(NewSpaceInfoContext);
+ const match = useRouteMatch<{ spaceId: string }>();
const [instance, setInstance] = useState([]);
const [nodeTypes, setNodeTypes] = useState<any[]>([]);
const [feNodes, setFENodes] = useState([]);
@@ -43,7 +46,6 @@ export function ClusterVerify(props: any) {
const [brokerNodes, setBrokerNodes] = useState([]);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
-
const columns = [
{
title: '序号',
@@ -60,16 +62,25 @@ export function ClusterVerify(props: any) {
key: 'operateStatus',
render: (record: any) => {
return (
- <Steps progressDot current={record.operateStage - 1}
percent={60} size="small" style={{marginLeft: -50}}
status={OperateStatusEnum.getStepStatus(record.operateStatus)}>
- <Step style={{width: 80}} />
+ <Steps
+ progressDot={(iconDot, { status }) => {
+ if (status === 'process') return <LoadingOutlined
style={{ color: '#1890ff' }} />;
+ return iconDot;
+ }}
+ current={record.operateStage - 1}
+ size="small"
+ style={{ marginLeft: -50 }}
+
status={OperateStatusEnum.getStepStatus(record.operateStatus)}
+ >
+ <Step style={{ width: 80 }} />
</Steps>
- )
- }
+ );
+ },
},
];
const getClusterInstance = useRequest<IResult<any>, any>(
(clusterId: string) => {
- return SpaceAPI.getClusterInstance<any>({clusterId});
+ return SpaceAPI.getClusterInstance<any>({ clusterId });
},
{
manual: true,
@@ -81,28 +92,38 @@ export function ClusterVerify(props: any) {
const types = [];
const feNodes = res.data.filter(item =>
item.moduleName?.toUpperCase() === DorisNodeTypeEnum.FE);
const beNodes = res.data.filter(item =>
item.moduleName?.toUpperCase() === DorisNodeTypeEnum.BE);
- const brokerNodes = res.data.filter(item =>
item.moduleName?.toUpperCase() === DorisNodeTypeEnum.BROKER);
+ const brokerNodes = res.data.filter(
+ item => item.moduleName?.toUpperCase() ===
DorisNodeTypeEnum.BROKER,
+ );
setFENodes(feNodes);
setBENodes(beNodes);
setBrokerNodes(brokerNodes);
if (feNodes.length > 0) {
- types.push({key: DorisNodeTypeEnum.FE, tab: 'FE节点',
moduleName: DorisNodeTypeEnum.FE });
+ types.push({ key: DorisNodeTypeEnum.FE, tab: 'FE节点',
moduleName: DorisNodeTypeEnum.FE });
}
if (beNodes.length > 0) {
- types.push({key: DorisNodeTypeEnum.BE, tab: 'BE节点',
moduleName: DorisNodeTypeEnum.BE });
+ types.push({ key: DorisNodeTypeEnum.BE, tab: 'BE节点',
moduleName: DorisNodeTypeEnum.BE });
}
if (brokerNodes.length > 0) {
- types.push({key: DorisNodeTypeEnum.BROKER, tab:
'Broker节点', moduleName: DorisNodeTypeEnum.BROKER });
+ types.push({
+ key: DorisNodeTypeEnum.BROKER,
+ tab: 'Broker节点',
+ moduleName: DorisNodeTypeEnum.BROKER,
+ });
}
setNodeTypes(types);
+ const failedInstance = data.find(item =>
ERROR_STATUS.includes(item.operateStatus));
+ if (failedInstance) {
+ message.error(failedInstance.operateResult);
+ }
const CANCEL_STATUS = [OperateStatusEnum.PROCESSING,
OperateStatusEnum.INIT];
if (data.filter(item =>
CANCEL_STATUS.includes(item.operateStatus)).length === 0) {
getClusterInstance.cancel();
}
if (data.filter(item => item.operateStatus !==
OperateStatusEnum.SUCCESS).length > 0) {
- setStepDisabled({...stepDisabled, next: true});
+ setStepDisabled({ ...stepDisabled, next: true });
} else {
- setStepDisabled({...stepDisabled, next: false});
+ setStepDisabled({ ...stepDisabled, next: false });
}
}
},
@@ -115,15 +136,12 @@ export function ClusterVerify(props: any) {
},
);
-
useEffect(() => {
if (reqInfo.cluster_id) {
- console.log(reqInfo.cluster_id)
getClusterInstance.run(reqInfo.cluster_id);
}
}, [reqInfo.cluster_id]);
-
return (
<PageContainer
header={{
@@ -132,18 +150,13 @@ export function ClusterVerify(props: any) {
>
<Tabs activeKey={activeKey} onChange={(key: any) =>
setActiveKey(key)} type="card">
{nodeTypes.map(item => (
- <TabPane tab={item.tab} key={item.key}>
- </TabPane>
+ <TabPane tab={item.tab} key={item.key}></TabPane>
))}
</Tabs>
- {activeKey === DorisNodeTypeEnum.FE && (
- <Table columns={columns} dataSource={feNodes}
rowKey="instanceId" />
- )}
- {activeKey === DorisNodeTypeEnum.BE && (
- <Table columns={columns} dataSource={beNodes}
rowKey="instanceId" />
- )}
+ {activeKey === DorisNodeTypeEnum.FE && <Table columns={columns}
dataSource={feNodes} rowKey="instanceId" />}
+ {activeKey === DorisNodeTypeEnum.BE && <Table columns={columns}
dataSource={beNodes} rowKey="instanceId" />}
{activeKey === DorisNodeTypeEnum.BROKER && (
- <Table columns={columns} dataSource={brokerNodes}
rowKey="instanceId" />
+ <Table columns={columns} dataSource={brokerNodes}
rowKey="instanceId" />
)}
</PageContainer>
);
diff --git
a/frontend/src/routes/space/access-cluster/steps/connect-cluster/connect-cluster.tsx
b/frontend/src/routes/space/access-cluster/steps/connect-cluster/connect-cluster.tsx
index 8dc7d9d..17283aa 100644
---
a/frontend/src/routes/space/access-cluster/steps/connect-cluster/connect-cluster.tsx
+++
b/frontend/src/routes/space/access-cluster/steps/connect-cluster/connect-cluster.tsx
@@ -23,22 +23,25 @@ import { SpaceAPI } from '@src/routes/space/space.api';
import styles from '../../../space.less';
import { stepDisabledState } from '../../access-cluster.recoil';
import { useRecoilState } from 'recoil';
+import { useLocation } from 'react-router';
+import { AccessClusterStepsEnum } from '../../access-cluster.data';
const tip = {
default: '请进行链接测试',
- fault: '链接测试未通过'
-}
+ fault: '链接测试未通过',
+};
export function ConnectCluster(props: any) {
- const { form, reqInfo, step } = useContext(NewSpaceInfoContext);
+ const { form, reqInfo } = useContext(NewSpaceInfoContext);
const [testFlag, setTestFlag] = useState<any>('none');
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
-
+ const { pathname } = useLocation();
useEffect(() => {
- form.setFieldsValue({...reqInfo.clusterAccessInfo});
- setStepDisabled({...stepDisabled, next: true});
- }, [reqInfo.cluster_id, step]);
-
+ if (pathname.includes(AccessClusterStepsEnum[1])) {
+ form.setFieldsValue({ ...reqInfo.clusterAccessInfo });
+ setStepDisabled({ ...stepDisabled, next: true });
+ }
+ }, [reqInfo.cluster_id, pathname]);
const handleLinkTest = () => {
const values = form.getFieldsValue();
@@ -52,21 +55,21 @@ export function ConnectCluster(props: any) {
const { msg, data, code } = res;
if (code === 0) {
Modal.success({
- title: "集群连接成功",
+ title: '集群连接成功',
content: msg,
});
- setStepDisabled({...stepDisabled, next: false});
- setTestFlag('success')
+ setStepDisabled({ ...stepDisabled, next: false });
+ setTestFlag('success');
} else {
Modal.error({
- title: "集群连接失败",
+ title: '集群连接失败',
content: msg,
});
- setStepDisabled({...stepDisabled, next: true});
+ setStepDisabled({ ...stepDisabled, next: true });
setTestFlag('failed');
}
});
- }
+ };
return (
<PageContainer
@@ -93,10 +96,10 @@ export function ConnectCluster(props: any) {
httpPort: reqInfo.clusterAccessInfo?.httpPort,
queryPort: reqInfo.clusterAccessInfo?.queryPort,
user: reqInfo.clusterAccessInfo?.user,
- passwd: reqInfo.clusterAccessInfo?.passwd
+ passwd: reqInfo.clusterAccessInfo?.passwd,
}}
>
- <Form.Item name="address" label="集群地址" required >
+ <Form.Item name="address" label="集群地址" required>
<Input placeholder="please input cluster address" />
</Form.Item>
<Form.Item name="httpPort" label="HTTP端口" required>
@@ -110,21 +113,20 @@ export function ConnectCluster(props: any) {
</Form.Item>
<Form.Item name="passwd" label="集群密码">
<Form.Item name="passwd" noStyle>
- <Input.Password placeholder="please input cluster
user password"/>
+ <Input.Password placeholder="please input cluster user
password" />
</Form.Item>
</Form.Item>
</Form>
- <Space style={{marginTop: 20, marginLeft: 82}}>
+ <Space style={{ marginTop: 20, marginLeft: 82 }}>
<Button onClick={() => handleLinkTest()}>链接测试</Button>
-
- {
- (testFlag !== 'success') && <Space>
+
+ {testFlag !== 'success' && (
+ <Space>
<div className={styles['light']}></div>
- <div className={styles['light-tip']}>{testFlag ===
'failed' ? tip.fault: tip.default}</div>
+ <div className={styles['light-tip']}>{testFlag ===
'failed' ? tip.fault : tip.default}</div>
</Space>
- }
+ )}
</Space>
</PageContainer>
);
}
-
diff --git a/frontend/src/routes/space/components/node-verify/node-verify.tsx
b/frontend/src/routes/space/components/node-verify/node-verify.tsx
index 6b0837a..c7648f5 100644
--- a/frontend/src/routes/space/components/node-verify/node-verify.tsx
+++ b/frontend/src/routes/space/components/node-verify/node-verify.tsx
@@ -27,16 +27,19 @@ import { IResult } from '@src/interfaces/http.interface';
import { OperateStatusEnum } from '../../space.data';
import { useRecoilState } from 'recoil';
import { stepDisabledState } from '../../access-cluster/access-cluster.recoil';
+import { LoadingOutlined } from '@ant-design/icons';
const Step = Steps.Step;
+const ERROR_STATUS = [OperateStatusEnum.FAIL, OperateStatusEnum.CANCEL];
+
export function NodeVerify(props: any) {
- const {reqInfo} = useContext(NewSpaceInfoContext);
+ const { reqInfo } = useContext(NewSpaceInfoContext);
const [nodes, setNodes] = useState<any[]>([]);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
const getClusterNodes = useRequest<IResult<any>, any>(
(clusterId: string) => {
- return SpaceAPI.getClusterNodes<any>({clusterId});
+ return SpaceAPI.getClusterNodes<any>({ clusterId });
},
{
manual: true,
@@ -45,13 +48,17 @@ export function NodeVerify(props: any) {
if (isSuccess(res)) {
const data: any[] = res.data;
setNodes(data);
+ const failedNode = data.find(item =>
ERROR_STATUS.includes(item.operateStatus));
+ if (failedNode) {
+ message.error(failedNode.operateResult);
+ }
if (data.filter(item => item.operateStatus ===
OperateStatusEnum.PROCESSING).length === 0) {
getClusterNodes.cancel();
}
if (data.filter(item => item.operateStatus !==
OperateStatusEnum.SUCCESS).length > 0) {
- setStepDisabled({...stepDisabled, next: true});
+ setStepDisabled({ ...stepDisabled, next: true });
} else {
- setStepDisabled({...stepDisabled, next: false});
+ setStepDisabled({ ...stepDisabled, next: false });
}
}
},
@@ -63,7 +70,6 @@ export function NodeVerify(props: any) {
},
);
-
useLayoutEffect(() => {
if (reqInfo.cluster_id) {
getClusterNodes.run(reqInfo.cluster_id);
@@ -86,17 +92,41 @@ export function NodeVerify(props: any) {
key: 'operateStage',
render: (record: any) => {
return (
- <Steps progressDot
status={OperateStatusEnum.getStepStatus(record.operateStatus)} percent={70}
current={record.operateStage - 1} size="small" style={{marginLeft: -50}}>
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.ACCESS_AUTH)} />
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.INSTALL_DIR_CHECK)} />
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.JDK_CHECK)} />
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_DEPLOY)} />
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_START)} />
- <Step style={{width: 80}}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_REGISTER)} />
+ <Steps
+ progressDot={(iconDot, { status }) => {
+ if (status === 'process') return <LoadingOutlined
style={{ color: '#1890ff' }} />;
+ return iconDot;
+ }}
+
status={OperateStatusEnum.getStepStatus(record.operateStatus)}
+ current={record.operateStage - 1}
+ size="small"
+ style={{ marginLeft: -50 }}
+ >
+ <Step
+ style={{ width: 80 }}
+
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.ACCESS_AUTH)}
+ />
+ <Step
+ style={{ width: 80 }}
+
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.INSTALL_DIR_CHECK)}
+ />
+ <Step style={{ width: 80 }}
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.JDK_CHECK)} />
+ <Step
+ style={{ width: 80 }}
+
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_DEPLOY)}
+ />
+ <Step
+ style={{ width: 80 }}
+
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_START)}
+ />
+ <Step
+ style={{ width: 80 }}
+
title={NodeVerifyStepEnum.getTitle(NodeVerifyStepEnum.AGENT_REGISTER)}
+ />
</Steps>
- )
- }
- }
+ );
+ },
+ },
];
return (
<PageContainer
diff --git a/frontend/src/routes/space/new-cluster/new-cluster.tsx
b/frontend/src/routes/space/new-cluster/new-cluster.tsx
index 830c2e8..582de4f 100644
--- a/frontend/src/routes/space/new-cluster/new-cluster.tsx
+++ b/frontend/src/routes/space/new-cluster/new-cluster.tsx
@@ -38,6 +38,7 @@ import { NodeVerify } from
'../components/node-verify/node-verify';
import { SpaceAPI } from '../space.api';
import { isSuccess } from '@src/utils/http';
import { requestInfoState, stepDisabledState } from
'../access-cluster/access-cluster.recoil';
+import { checkParam } from '../space.utils';
const { Step } = Steps;
const PREV_DISABLED_STEPS = [NewClusterStepsEnum[3], NewClusterStepsEnum[6],
NewClusterStepsEnum[7]];
@@ -52,6 +53,7 @@ export function NewCluster(props: any) {
const [curProcessId, setProcessId] = useRecoilState(processId);
const [requestInfo, setRequestInfo] = useRecoilState(requestInfoState);
const [loading, setLoading] = useState(false);
+ const [form] = useForm();
useEffect(() => {
if (history.location.pathname === '/space/list') {
@@ -69,9 +71,7 @@ export function NewCluster(props: any) {
if (match.params.requestId && +match.params.requestId !== 0) {
getRequestInfo();
}
- }, [history.location.pathname, step]);
-
- const [form] = useForm();
+ }, [history.location.pathname]);
async function getRequestInfo() {
const requestId = match.params.requestId;
@@ -84,7 +84,7 @@ export function NewCluster(props: any) {
async function nextStep() {
const value = form.getFieldsValue();
const newStep = step + 1;
- setLoading(true);
+ let isParamsValid = true;
const params = {
...requestInfo.reqInfo,
cluster_id: requestInfo.clusterId,
@@ -97,26 +97,45 @@ export function NewCluster(props: any) {
name: value.name,
spaceAdminUsers: value.spaceAdminUsers,
};
+ isParamsValid =
+ checkParam(params.spaceInfo.name, '请填写空间名称') &&
+ checkParam(params.spaceInfo.spaceAdminUsers, '请填写管理员姓名');
}
if (value && step === NewClusterStepsEnum['add-node']) {
params.authInfo = {
sshKey: value.sshKey,
- sshPort: parseInt(value.sshPort),
+ sshPort: value.sshPort ? parseInt(value.sshPort) :
value.sshPort,
sshUser: value.sshUser,
};
params.hosts = value.hosts;
+ isParamsValid =
+ checkParam(params.authInfo.sshUser, '请填写SSH用户') &&
+ checkParam(params.authInfo.sshPort, '请填写SSH端口') &&
+ checkParam(params.authInfo.sshKey, '请填写SSH私钥') &&
+ checkParam(params.hosts, '请填写节点列表');
}
if (value && step === NewClusterStepsEnum['install-options']) {
params.installInfo = value.installDir;
params.packageInfo = value.packageUrl;
+ isParamsValid =
+ checkParam(params.installInfo, '请填写代码包路径') &&
checkParam(params.packageInfo, '请填写安装路径');
}
if (value && step === NewClusterStepsEnum['cluster-plan']) {
params.nodeConfig = value.nodeConfig;
+ isParamsValid =
+ checkParam(params.nodeConfig?.[0]?.nodeIds, '请分配FE节点') &&
+ checkParam(params.nodeConfig?.[1]?.nodeIds, '请分配BE节点');
}
if (value && step === NewClusterStepsEnum['node-config']) {
params.deployConfigs = value.deployConfigs;
+ isParamsValid = params.deployConfigs.every((node: any) => {
+ return node.configs.every((config: any) => {
+ return checkParam(config.value,
`请完整配置${node.moduleName.toUpperCase()}节点参数`);
+ });
+ });
}
- console.log(params);
+ if (!isParamsValid) return;
+ setLoading(true);
const res = await SpaceAPI.createCluster(params);
setLoading(false);
if (isSuccess(res)) {
@@ -138,7 +157,6 @@ export function NewCluster(props: any) {
async function finish() {
const value = form.getFieldsValue();
- setLoading(true);
const params = {
...requestInfo.reqInfo,
cluster_id: requestInfo.clusterId,
@@ -146,7 +164,9 @@ export function NewCluster(props: any) {
event_type: (step + 1).toString(),
};
params.clusterPassword = value.clusterPassword;
- console.log(params);
+ const isFinishParamValid = checkParam(params.clusterPassword,
'请设定集群root密码');
+ if (!isFinishParamValid) return;
+ setLoading(true);
const res = await SpaceAPI.createCluster(params);
setLoading(false);
if (isSuccess(res)) {
diff --git a/frontend/src/routes/space/new-cluster/steps/add-node/add-node.tsx
b/frontend/src/routes/space/new-cluster/steps/add-node/add-node.tsx
index 1d370de..f3c6b5f 100644
--- a/frontend/src/routes/space/new-cluster/steps/add-node/add-node.tsx
+++ b/frontend/src/routes/space/new-cluster/steps/add-node/add-node.tsx
@@ -16,36 +16,34 @@
// under the License.
import { Button, Divider, Form, Input, message, Modal, PageHeader, Row, Space,
Steps, Table } from 'antd';
-import React, { useContext, useMemo, useRef, useState } from 'react';
+import React, { useContext, useMemo, useRef, useState, useEffect } from
'react';
import ProCard from '@ant-design/pro-card';
import { NewSpaceInfoContext, UserInfoContext } from
'@src/common/common.context';
-import {NodeList} from './node-list/node-list';
+import { NodeList } from './node-list/node-list';
const { TextArea } = Input;
export function AddNode(props: any) {
const userInfo = useContext(UserInfoContext);
- const {form} = useContext(NewSpaceInfoContext);
+ const { reqInfo, form } = useContext(NewSpaceInfoContext);
+ useEffect(() => {
+ const { sshUser, sshPort, sshKey } = reqInfo.authInfo || {};
+ form.setFieldsValue({
+ ...form.getFieldsValue(),
+ sshUser,
+ sshPort,
+ sshKey,
+ hosts: reqInfo.hosts,
+ });
+ }, [form, reqInfo.authInfo, reqInfo.hosts]);
return (
<ProCard title={<h2>添加节点</h2>} headerBordered>
<PageHeader className="site-page-header" title="SSH信任" style={{
paddingLeft: 0 }} />
-
<span>请提前完成Manager节点与其他节点间SSH信任,并在下方填入Manager节点的SSH信息。<a>如何进行SSH信任?</a></span>
+ <span>
+
请提前完成Manager节点与其他节点间SSH信任,并在下方填入Manager节点的SSH信息。<a>如何进行SSH信任?</a>
+ </span>
<Divider style={{ margin: 0, marginBottom: 24 }} />
- <Form
- form={form}
- name="basic"
- labelCol={{ span: 2 }}
- wrapperCol={{ span: 10 }}
- initialValues={{
- remember: true,
- user: 'root',
- sshPort: 8022,
- sshKey: '',
- installDir: '/usr/local/doris',
- packageUrl:
'http://172.16.0.4:8002/PALO-0.15.1-rc09-binary.tar.gz',
- }}
- autoComplete="off"
- >
+ <Form form={form} name="basic" labelCol={{ span: 2 }}
wrapperCol={{ span: 10 }} autoComplete="off">
<Form.Item label="SSH用户" name="sshUser" rules={[{ required:
true, message: '请输入SSH用户!' }]}>
<Input />
</Form.Item>
@@ -57,7 +55,7 @@ export function AddNode(props: any) {
</Form.Item>
<PageHeader className="site-page-header" title="节点列表" style={{
paddingLeft: 0 }} />
<Divider style={{ margin: 0, marginBottom: 24 }} />
- <Form.Item name="hosts" style={{width: '100%'}}
wrapperCol={{span: 24}}>
+ <Form.Item name="hosts" style={{ width: '100%' }}
wrapperCol={{ span: 24 }}>
<NodeList />
</Form.Item>
</Form>
diff --git
a/frontend/src/routes/space/new-cluster/steps/add-node/node-list/node-list.tsx
b/frontend/src/routes/space/new-cluster/steps/add-node/node-list/node-list.tsx
index 2e028d4..de8b204 100644
---
a/frontend/src/routes/space/new-cluster/steps/add-node/node-list/node-list.tsx
+++
b/frontend/src/routes/space/new-cluster/steps/add-node/node-list/node-list.tsx
@@ -16,7 +16,7 @@
// under the License.
import { EditableProTable, ProColumns } from '@ant-design/pro-table';
-import { Row, Button, Input, message, Modal } from 'antd';
+import { Row, Button, Input, message, Modal, InputRef } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import React, { useEffect, useRef, useState } from 'react';
type DataSourceType = {
@@ -47,7 +47,9 @@ export function NodeList(props: { value?: any; onChange?: any
}) {
{
title: 'IP地址',
dataIndex: 'ip',
- renderFormItem: (dom, rowData, index) => <IpInput
value={rowData.ip} />,
+ renderFormItem: (dom, rowData, index) => {
+ return <IpInput value={rowData.record?.ip}
id={rowData.record?.id as string} />;
+ },
render: (dom, rowData, index) => {
return <span className="customRender">{`${rowData.ip}`}</span>;
},
@@ -78,13 +80,14 @@ export function NodeList(props: { value?: any; onChange?:
any }) {
];
const IpInput: React.FC<{
+ id: string;
value?: string;
onChange?: (value: string) => void;
- }> = ({ value, onChange }) => {
- const ref = useRef<Input | null>(null);
+ }> = ({ value, id, onChange }) => {
+ const ref = useRef<InputRef | null>(null);
const handleInputConfirm = (val: string) => {
if (reg.test(val)) {
- if (dataSource.filter(item => item.ip === val).length) {
+ if (dataSource.filter(item => item.ip === val && item.id !==
id).length) {
message.error('此ip已存在!');
} else {
onChange?.(val);
@@ -106,7 +109,21 @@ export function NodeList(props: { value?: any; onChange?:
any }) {
useEffect(() => {
props?.onChange(dataSource.map(item => item.ip));
- }, [dataSource.length]);
+ }, [dataSource]);
+
+ useEffect(() => {
+ if (props.value && dataSource.length === 0) {
+ const dataSource = props.value.map((item: string, index: number)
=> ({
+ id: index.toString(),
+ order: index + 1,
+ index,
+ ip: item,
+ }));
+ if (dataSource.length) {
+ setDataSource(dataSource);
+ }
+ }
+ }, [props.value]);
function handleOk() {
let baseLength = dataSource.length || 0;
diff --git
a/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
b/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
index 4efae58..3542362 100644
---
a/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
+++
b/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
@@ -85,14 +85,16 @@ export function ClusterDeploy(props: any) {
if (isSuccess(res)) {
const data: any[] = res.data;
setInstances(data);
- if (data.some(item =>
ERROR_STATUS.includes(item.operateStatus))) {
+ const failedInstance = data.find(item =>
ERROR_STATUS.includes(item.operateStatus));
+ if (failedInstance) {
+ message.error(failedInstance.operateResult);
getClusterInstances.cancel();
}
if (
data.every(item => item.operateStatus ===
OperateStatusEnum.SUCCESS && item.operateStage === 3)
) {
getClusterInstances.cancel();
- getJDBCReady.run(reqInfo.cluster_id)
+ getJDBCReady.run(reqInfo.cluster_id);
}
}
},
diff --git
a/frontend/src/routes/space/new-cluster/steps/cluster-plan/cluster-plan.tsx
b/frontend/src/routes/space/new-cluster/steps/cluster-plan/cluster-plan.tsx
index 4d2db95..049da81 100644
--- a/frontend/src/routes/space/new-cluster/steps/cluster-plan/cluster-plan.tsx
+++ b/frontend/src/routes/space/new-cluster/steps/cluster-plan/cluster-plan.tsx
@@ -35,7 +35,13 @@ const { confirm } = Modal;
const { TabPane } = Tabs;
export function ClusterPlan() {
- const { form } = useContext(NewSpaceInfoContext);
+ const { form, reqInfo } = useContext(NewSpaceInfoContext);
+ useEffect(() => {
+ form.setFieldsValue({
+ ...form.getFieldsValue(),
+ nodeConfig: reqInfo.nodeConfig || [],
+ });
+ }, [form, reqInfo.nodeConfig]);
return (
<Form form={form} name="basic" labelCol={{ span: 2 }} wrapperCol={{
span: 10 }} autoComplete="off">
<Form.Item name="nodeConfig" style={{ width: '100%' }}
wrapperCol={{ span: 24 }}>
@@ -58,7 +64,7 @@ export function ClusterPlanContent(props: any) {
const [mixMode, setMixMode] = useState(false);
const [modal, setModal] = useRecoilState(modalState);
const processID = useRecoilValue(processId);
- const { data, run: runGetClusterNodes } = useAsync<any[]>({ data: [] });
+ const { data, run: runGetClusterNodes, loading } = useAsync<any[]>({ data:
[] });
const [modalAllData, setModalAllData] = useState<any[]>(data || []);
const [activeKey, setActiveKey] = useState(DorisNodeTypeEnum.FE);
@@ -75,6 +81,42 @@ export function ClusterPlanContent(props: any) {
}, [runGetClusterNodes, reqInfo.cluster_id]);
useEffect(() => {
+ if (loading) return;
+ if (props.value && feData.length === 0 && beData.length === 0 && data)
{
+ const feNodes = props.value.find((item: any) =>
item.moduleName.toUpperCase() === DorisNodeTypeEnum.FE);
+ const beNodes = props.value.find((item: any) =>
item.moduleName.toUpperCase() === DorisNodeTypeEnum.BE);
+ if (feNodes && feNodes.nodeIds && feNodes.nodeIds.length > 0) {
+ const feHosts = feNodes.nodeIds.map(
+ (nodeId: number) => data.find(item => item.nodeId ===
nodeId)?.host,
+ );
+ setFeChecked(feNodes.nodeIds);
+ setFeData(
+ feNodes.nodeIds.map((nodeId: number, index: number) => {
+ return {
+ nodeId: nodeId,
+ host: feHosts[index],
+ };
+ }),
+ );
+ }
+ if (beNodes && beNodes.nodeIds && beNodes.nodeIds.length > 0) {
+ const beHosts = beNodes.nodeIds.map(
+ (nodeId: number) => data.find(item => item.nodeId ===
nodeId)?.host,
+ );
+ setBeChecked(beNodes.nodeIds);
+ setBeData(
+ beNodes.nodeIds.map((nodeId: number, index: number) => {
+ return {
+ nodeId: nodeId,
+ host: beHosts[index],
+ };
+ }),
+ );
+ }
+ }
+ }, [props.value, data, loading]);
+
+ useEffect(() => {
props?.onChange([
{
moduleName: 'fe',
@@ -130,13 +172,13 @@ export function ClusterPlanContent(props: any) {
const feIndex = feData.findIndex(item => item.nodeId ===
record.nodeId);
feData.splice(feIndex, 1);
setFeData([...feData]);
- setFeChecked(feChecked.filter(item => item !== record.host));
+ setFeChecked(feChecked.filter(item => item !== record.nodeId));
break;
case 'be':
const beIndex = beData.findIndex(item => item.nodeId ===
record.nodeId);
beData.splice(beIndex, 1);
setBeData([...beData]);
- setBeChecked(beChecked.filter(item => item !== record.host));
+ setBeChecked(beChecked.filter(item => item !== record.nodeId));
break;
default:
break;
@@ -159,12 +201,12 @@ export function ClusterPlanContent(props: any) {
if (roleType === DorisNodeTypeEnum.FE) {
setFeChecked(selectedRowKeys);
- let tempFeData = data?.filter(item =>
selectedRowKeys.includes(item.host));
+ let tempFeData = data?.filter(item =>
selectedRowKeys.includes(item.nodeId));
setFeData(tempFeData || []);
}
if (roleType === DorisNodeTypeEnum.BE) {
setBeChecked(selectedRowKeys);
- let tempBeData = data?.filter(item =>
selectedRowKeys.includes(item.host));
+ let tempBeData = data?.filter(item =>
selectedRowKeys.includes(item.nodeId));
setBeData(tempBeData || []);
}
};
@@ -243,7 +285,7 @@ export function ClusterPlanContent(props: any) {
rowSelection={rowSelection}
columns={nodeColumns}
dataSource={modalAllData}
- rowKey={'host'}
+ rowKey={'nodeId'}
/>
</>
</Modal>
diff --git
a/frontend/src/routes/space/new-cluster/steps/install-options/install-options.tsx
b/frontend/src/routes/space/new-cluster/steps/install-options/install-options.tsx
index a238108..962b1a8 100644
---
a/frontend/src/routes/space/new-cluster/steps/install-options/install-options.tsx
+++
b/frontend/src/routes/space/new-cluster/steps/install-options/install-options.tsx
@@ -36,14 +36,6 @@ export function InstallOptions(props: any) {
name="basic"
labelCol={{ span: 2 }}
wrapperCol={{ span: 10 }}
- initialValues={{
- remember: true,
- user: 'root',
- sshPort: 8022,
- sshKey: '',
- installDir: '/usr/local/doris',
- packageUrl:
'http://10.193.215.27:8091/download/PALO-0.15.1-rc09-binary.tar.gz',
- }}
autoComplete="off"
>
<Form.Item label="代码包路径" name="packageUrl" rules={[{ required:
true, message: '请输入安装路径' }]}>
@@ -59,9 +51,6 @@ export function InstallOptions(props: any) {
name="basic"
labelCol={{ span: 2 }}
wrapperCol={{ span: 10 }}
- initialValues={{
- installDir: '/usr/local/doris',
- }}
autoComplete="off"
>
<Form.Item label="安装路径" name="installDir" rules={[{ required:
true, message: '请输入安装路径' }]}>
diff --git a/frontend/src/routes/user-setting/index.module.less
b/frontend/src/routes/space/space.utils.ts
similarity index 66%
copy from frontend/src/routes/user-setting/index.module.less
copy to frontend/src/routes/space/space.utils.ts
index 9d2eaba..00712e9 100644
--- a/frontend/src/routes/user-setting/index.module.less
+++ b/frontend/src/routes/space/space.utils.ts
@@ -14,29 +14,19 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-.tabs {
- transform: translate(35em, 0);
-}
-.input-gird {
- margin: 0 auto;
- width: 420px;
- // padding: 32px;
-
- line-height: 24px;
- background-color: #fff;
- border-radius: 6px;
- box-shadow: rgb(0 0 0 / 8%) 0 7px 20px;
- transition: all 0.2s linear 0s;
+import { message } from 'antd';
- input {
- width: 100%;
- padding: 0.75em;
- background: '#e8f0fe';
- border-radius: 4px;
- }
+export function isVoid<T extends any>(val: T) {
+ if (val == null || val === '') return true;
+ if (Array.isArray(val)) return val.length === 0;
+ return false;
}
-.input-pass {
- background: '#e8f0fe';
+export function checkParam<T extends any>(param: T, errorMessage: string) {
+ const isValid = !isVoid(param);
+ if (!isValid) {
+ message.error(errorMessage);
+ }
+ return isValid;
}
diff --git a/frontend/src/routes/user-setting/index.module.less
b/frontend/src/routes/user-setting/index.module.less
index 9d2eaba..8751f12 100644
--- a/frontend/src/routes/user-setting/index.module.less
+++ b/frontend/src/routes/user-setting/index.module.less
@@ -26,7 +26,6 @@
line-height: 24px;
background-color: #fff;
border-radius: 6px;
- box-shadow: rgb(0 0 0 / 8%) 0 7px 20px;
transition: all 0.2s linear 0s;
input {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]