add step of creating new cluster
This commit is contained in:
parent
77fc87c3dc
commit
62a61ec2de
|
@ -1,7 +1,7 @@
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
- name: default
|
- name: default
|
||||||
enabled: true
|
enabled: true
|
||||||
endpoint: https://192.168.3.98:9200
|
endpoint: http://127.0.0.1:9200
|
||||||
basic_auth:
|
basic_auth:
|
||||||
username: elastic
|
username: elastic
|
||||||
password: ZBdkVQUUdF1Sir4X4BGB
|
password: ZBdkVQUUdF1Sir4X4BGB
|
||||||
|
@ -29,6 +29,7 @@ elastic:
|
||||||
init_template: true
|
init_template: true
|
||||||
template_name: ".infini-search-center"
|
template_name: ".infini-search-center"
|
||||||
index_prefix: ".infini-search-center_"
|
index_prefix: ".infini-search-center_"
|
||||||
|
# load_remote_elasticsearch_configs: true
|
||||||
|
|
||||||
search-center:
|
search-center:
|
||||||
ui_path: .public
|
ui_path: .public
|
||||||
|
|
|
@ -442,6 +442,12 @@ export default [
|
||||||
name: 'cluster',
|
name: 'cluster',
|
||||||
component: './System/Cluster/Index',
|
component: './System/Cluster/Index',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/system/cluster/regist',
|
||||||
|
name: 'registCluster',
|
||||||
|
component: './System/Cluster/Step',
|
||||||
|
hideInMenu: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/system/cluster/edit',
|
path: '/system/cluster/edit',
|
||||||
name: 'editCluster',
|
name: 'editCluster',
|
||||||
|
|
|
@ -29,6 +29,8 @@ import { IndexPatternCreationOption } from '../../types';
|
||||||
import { CreateButton } from '../../create_button';
|
import { CreateButton } from '../../create_button';
|
||||||
import { Illustration } from './assets/index_pattern_illustration';
|
import { Illustration } from './assets/index_pattern_illustration';
|
||||||
import { ManagementAppMountParams } from '../../../../../management/public';
|
import { ManagementAppMountParams } from '../../../../../management/public';
|
||||||
|
import Link from 'umi/link';
|
||||||
|
import Exception from '@/components/Exception';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
canSave: boolean;
|
canSave: boolean;
|
||||||
|
@ -53,9 +55,9 @@ export const EmptyIndexPatternPrompt = ({
|
||||||
horizontalPosition="center"
|
horizontalPosition="center"
|
||||||
>
|
>
|
||||||
<EuiFlexGroup gutterSize="xl" alignItems="center" direction="rowReverse" wrap>
|
<EuiFlexGroup gutterSize="xl" alignItems="center" direction="rowReverse" wrap>
|
||||||
<EuiFlexItem grow={1} className="inpEmptyIndexPatternPrompt__illustration">
|
{/* <EuiFlexItem grow={1} className="inpEmptyIndexPatternPrompt__illustration">
|
||||||
<Illustration />
|
<Illustration />
|
||||||
</EuiFlexItem>
|
</EuiFlexItem> */}
|
||||||
<EuiFlexItem grow={2} className="inpEmptyIndexPatternPrompt__text">
|
<EuiFlexItem grow={2} className="inpEmptyIndexPatternPrompt__text">
|
||||||
<EuiText grow={false}>
|
<EuiText grow={false}>
|
||||||
<h2>
|
<h2>
|
||||||
|
|
|
@ -123,6 +123,7 @@ export default {
|
||||||
|
|
||||||
'menu.system': 'SYSTEM',
|
'menu.system': 'SYSTEM',
|
||||||
'menu.system.cluster': 'CLUSTERS',
|
'menu.system.cluster': 'CLUSTERS',
|
||||||
|
'menu.system.registCluster': 'REGIST CLUSTER',
|
||||||
'menu.system.editCluster': 'EDIT CLUSTER',
|
'menu.system.editCluster': 'EDIT CLUSTER',
|
||||||
'menu.system.settings': 'SETTINGS',
|
'menu.system.settings': 'SETTINGS',
|
||||||
'menu.system.settings.global': 'GLOBAL',
|
'menu.system.settings.global': 'GLOBAL',
|
||||||
|
|
|
@ -130,7 +130,8 @@ export default {
|
||||||
|
|
||||||
'menu.system': '系统管理',
|
'menu.system': '系统管理',
|
||||||
'menu.system.cluster': '集群管理',
|
'menu.system.cluster': '集群管理',
|
||||||
'menu.system.editCluster': '集群编辑',
|
'menu.system.registCluster': '集群注册',
|
||||||
|
'menu.system.editCluster': '集群修改',
|
||||||
'menu.system.settings': '系统设置',
|
'menu.system.settings': '系统设置',
|
||||||
'menu.system.settings.global': '全局设置',
|
'menu.system.settings.global': '全局设置',
|
||||||
'menu.system.settings.gateway': '网关设置',
|
'menu.system.settings.gateway': '网关设置',
|
||||||
|
|
|
@ -146,7 +146,7 @@ const vstyle = {
|
||||||
const MonitorDatePicker = ({timeRange, commonlyUsedRanges, onChange, isLoading}) => {
|
const MonitorDatePicker = ({timeRange, commonlyUsedRanges, onChange, isLoading}) => {
|
||||||
// const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]);
|
// const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]);
|
||||||
const [isPaused, setIsPaused] = useState(true);
|
const [isPaused, setIsPaused] = useState(true);
|
||||||
const [refreshInterval, setRefreshInterval] = useState();
|
const [refreshInterval, setRefreshInterval] = useState(10000);
|
||||||
|
|
||||||
const onTimeChange = ({ start, end }) => {
|
const onTimeChange = ({ start, end }) => {
|
||||||
onChange({
|
onChange({
|
||||||
|
|
|
@ -164,8 +164,8 @@ const filterManager = new FilterManager();
|
||||||
const storage = new Storage(localStorage);
|
const storage = new Storage(localStorage);
|
||||||
const queryStringManager = new QueryStringManager(storage);
|
const queryStringManager = new QueryStringManager(storage);
|
||||||
const timefilterConfig = {
|
const timefilterConfig = {
|
||||||
timeDefaults: { from: 'now-15m', to: 'now' },
|
timeDefaults: { from: 'now-1y', to: 'now' },
|
||||||
refreshIntervalDefaults: { pause: false, value: 0 },
|
refreshIntervalDefaults: { pause: true, value: 10000 },
|
||||||
};
|
};
|
||||||
const timeHistory = new TimeHistory(storage);
|
const timeHistory = new TimeHistory(storage);
|
||||||
const timefilter = new Timefilter(timefilterConfig, timeHistory);
|
const timefilter = new Timefilter(timefilterConfig, timeHistory);
|
||||||
|
|
|
@ -53,7 +53,7 @@ class ClusterForm extends React.Component{
|
||||||
//console.log(values);
|
//console.log(values);
|
||||||
let newVals = {
|
let newVals = {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
endpoint: values.endpoint,
|
host: values.host,
|
||||||
basic_auth: {
|
basic_auth: {
|
||||||
username: values.username,
|
username: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
|
@ -61,7 +61,8 @@ class ClusterForm extends React.Component{
|
||||||
description: values.description,
|
description: values.description,
|
||||||
enabled: values.enabled,
|
enabled: values.enabled,
|
||||||
monitored: values.monitored,
|
monitored: values.monitored,
|
||||||
order: values.order,
|
schema: values.isTLS === true ? 'https': 'http',
|
||||||
|
// order: values.order,
|
||||||
}
|
}
|
||||||
if(clusterConfig.editMode === 'NEW') {
|
if(clusterConfig.editMode === 'NEW') {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -125,7 +126,6 @@ class ClusterForm extends React.Component{
|
||||||
router.push('/system/cluster');
|
router.push('/system/cluster');
|
||||||
}}>返回</Button>]}
|
}}>返回</Button>]}
|
||||||
>
|
>
|
||||||
{/* <NewCluster/> */}
|
|
||||||
<Form {...formItemLayout}>
|
<Form {...formItemLayout}>
|
||||||
<Form.Item label="集群名称">
|
<Form.Item label="集群名称">
|
||||||
{getFieldDecorator('name', {
|
{getFieldDecorator('name', {
|
||||||
|
@ -138,20 +138,31 @@ class ClusterForm extends React.Component{
|
||||||
],
|
],
|
||||||
})(<Input autoComplete='off' placeholder="cluster-name" />)}
|
})(<Input autoComplete='off' placeholder="cluster-name" />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="集群 URL">
|
<Form.Item label="集群地址">
|
||||||
{getFieldDecorator('endpoint', {
|
{getFieldDecorator('host', {
|
||||||
initialValue: editValue.endpoint,
|
initialValue: editValue.host,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
type: 'url', //https://github.com/yiminghe/async-validator#type
|
type: 'string',
|
||||||
message: 'The input is not valid url!',
|
pattern: /^[\w\.]+\:\d+$/, //(https?:\/\/)?
|
||||||
|
message: '请输入域名或 IP 地址和端口号',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: 'Please input cluster name!',
|
message: '请输入域名或 IP 地址和端口号!',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})(<Input placeholder="http://127.0.0.1:9200" />)}
|
})(<Input placeholder="127.0.0.1:9200" />)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="TLS">
|
||||||
|
{getFieldDecorator('isTLS', {
|
||||||
|
initialValue: editValue?.schema === "https",
|
||||||
|
})(
|
||||||
|
<Switch
|
||||||
|
defaultChecked={editValue?.schema === "https"}
|
||||||
|
checkedChildren={<Icon type="check" />}
|
||||||
|
unCheckedChildren={<Icon type="close" />}
|
||||||
|
/>)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="是否需要身份验证">
|
<Form.Item label="是否需要身份验证">
|
||||||
<Switch
|
<Switch
|
||||||
|
@ -177,22 +188,17 @@ class ClusterForm extends React.Component{
|
||||||
})(<Input.Password />)}
|
})(<Input.Password />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>):''}
|
</div>):''}
|
||||||
{/* <Form.Item label="Elasticsearch 版本">
|
{/* <Form.Item label="排序权重">
|
||||||
{getFieldDecorator('version', {
|
|
||||||
initialValue: editValue.version || '',
|
|
||||||
})(<Input readOnly={true} />)}
|
|
||||||
</Form.Item> */}
|
|
||||||
<Form.Item label="排序权重">
|
|
||||||
{getFieldDecorator('order', {
|
{getFieldDecorator('order', {
|
||||||
initialValue: editValue.order || 0,
|
initialValue: editValue.order || 0,
|
||||||
})(<InputNumber />)}
|
})(<InputNumber />)}
|
||||||
</Form.Item>
|
</Form.Item> */}
|
||||||
<Form.Item label="描述">
|
<Form.Item label="描述">
|
||||||
{getFieldDecorator('description', {
|
{getFieldDecorator('description', {
|
||||||
initialValue: editValue.description,
|
initialValue: editValue.description,
|
||||||
})(<Input.TextArea placeholder="集群应用描述" />)}
|
})(<Input.TextArea placeholder="集群应用描述" />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="是否启用">
|
{/* <Form.Item label="是否启用">
|
||||||
{getFieldDecorator('enabled', {
|
{getFieldDecorator('enabled', {
|
||||||
valuePropName: 'checked',
|
valuePropName: 'checked',
|
||||||
initialValue: typeof editValue.enabled === 'undefined' ? true: editValue.enabled,
|
initialValue: typeof editValue.enabled === 'undefined' ? true: editValue.enabled,
|
||||||
|
@ -200,7 +206,7 @@ class ClusterForm extends React.Component{
|
||||||
checkedChildren={<Icon type="check" />}
|
checkedChildren={<Icon type="check" />}
|
||||||
unCheckedChildren={<Icon type="close" />}
|
unCheckedChildren={<Icon type="close" />}
|
||||||
/>)}
|
/>)}
|
||||||
</Form.Item>
|
</Form.Item> */}
|
||||||
<Form.Item label="启用监控">
|
<Form.Item label="启用监控">
|
||||||
{getFieldDecorator('monitored', {
|
{getFieldDecorator('monitored', {
|
||||||
valuePropName: 'checked',
|
valuePropName: 'checked',
|
||||||
|
@ -214,9 +220,6 @@ class ClusterForm extends React.Component{
|
||||||
<Button type="primary" onClick={this.handleSubmit}>
|
<Button type="primary" onClick={this.handleSubmit}>
|
||||||
{editMode === 'NEW' ? '注册': '保存'}
|
{editMode === 'NEW' ? '注册': '保存'}
|
||||||
</Button>
|
</Button>
|
||||||
{/* <Button style={{marginLeft:20}}>
|
|
||||||
测试连接
|
|
||||||
</Button> */}
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -40,14 +40,14 @@ class Index extends React.Component {
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
title: '部署环境',
|
title: '部署环境',
|
||||||
dataIndex: 'business_department',
|
dataIndex: 'deploy_env',
|
||||||
key: 'business_department',
|
key: 'deploy_env',
|
||||||
render: ()=>{
|
render: ()=>{
|
||||||
return 'PROD'
|
return 'PROD'
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
title: '程序版本',
|
title: '程序版本',
|
||||||
dataIndex: 'status.version',
|
dataIndex: 'version',
|
||||||
key: 'elasticsearch_version',
|
key: 'elasticsearch_version',
|
||||||
// render: (data)=>{
|
// render: (data)=>{
|
||||||
// return
|
// return
|
||||||
|
@ -212,7 +212,7 @@ class Index extends React.Component {
|
||||||
onChange={this.handleEnabledChange}
|
onChange={this.handleEnabledChange}
|
||||||
defaultChecked
|
defaultChecked
|
||||||
/>是否启用</span>
|
/>是否启用</span>
|
||||||
<Link to='/system/cluster/edit' onClick={this.handleNewClick}> <Button type="primary" icon="plus">新建集群</Button></Link>
|
<Link to='/system/cluster/regist' onClick={this.handleNewClick}> <Button type="primary" icon="plus">注册集群</Button></Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { Steps, Button, message } from 'antd';
|
import { Steps, Button, message, Spin, Card } from 'antd';
|
||||||
import {connect} from "dva";
|
import {connect} from "dva";
|
||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import InitialStep from './steps/initial_step';
|
import {InitialStep, ExtraStep, ResultStep} from './steps';
|
||||||
|
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
|
||||||
|
import styles from './step.less';
|
||||||
|
|
||||||
const { Step } = Steps;
|
const { Step } = Steps;
|
||||||
|
|
||||||
|
@ -10,7 +12,7 @@ const steps = [
|
||||||
title: '初始化',
|
title: '初始化',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '连接',
|
title: '信息确认',
|
||||||
content: 'Second-content',
|
content: 'Second-content',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,24 +24,100 @@ const steps = [
|
||||||
const ClusterStep = ({
|
const ClusterStep = ({
|
||||||
current,
|
current,
|
||||||
changeStep,
|
changeStep,
|
||||||
|
dispatch,
|
||||||
|
history,
|
||||||
}) => {
|
}) => {
|
||||||
const initalFormRef = useRef();
|
const formRef = useRef();
|
||||||
|
const [clusterConfig, setClusterConfig] = useState({})
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
// const [clusterInfo, setClusterInfo] = useState({});
|
||||||
|
|
||||||
|
const handleConnect = async ()=>{
|
||||||
|
const result = await formRef.current.validateFields((errors, values) => {
|
||||||
|
if(errors){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
|
||||||
|
}).catch((err)=>{
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!result){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
setIsLoading(true)
|
||||||
|
const res = await dispatch({
|
||||||
|
type: 'clusterConfig/doTryConnect',
|
||||||
|
payload: {
|
||||||
|
basic_auth:{
|
||||||
|
username: result.username,
|
||||||
|
password: result.password,
|
||||||
|
},
|
||||||
|
host: result.host,
|
||||||
|
schema: result.isTLS === true ? 'https': 'http',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if(res && !res.error){
|
||||||
|
setClusterConfig({
|
||||||
|
...result,
|
||||||
|
...res,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
setIsLoading(false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCommit = async ()=>{
|
||||||
|
const result = await formRef.current.validateFields((errors, values) => {
|
||||||
|
if(errors){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// console.log(values);
|
||||||
|
return values
|
||||||
|
});
|
||||||
|
if(!result){
|
||||||
|
return fasle;
|
||||||
|
}
|
||||||
|
const newVals = {
|
||||||
|
name: result.name,
|
||||||
|
version: clusterConfig.version,
|
||||||
|
host: clusterConfig.host,
|
||||||
|
basic_auth: {
|
||||||
|
username: clusterConfig.username || '',
|
||||||
|
password: clusterConfig.password || '',
|
||||||
|
},
|
||||||
|
description: result.description,
|
||||||
|
enabled: true,
|
||||||
|
monitored: result.monitored,
|
||||||
|
schema: clusterConfig.isTLS ? 'https': 'http'
|
||||||
|
}
|
||||||
|
setIsLoading(true);
|
||||||
|
const res = await dispatch({
|
||||||
|
type: 'clusterConfig/addCluster',
|
||||||
|
payload: newVals,
|
||||||
|
});
|
||||||
|
if(res && !res.error){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
setIsLoading(false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const next = async () => {
|
const next = async () => {
|
||||||
let result
|
let result
|
||||||
if(current === 0){
|
if(current === 0){
|
||||||
result = await initalFormRef.current.validateFields((errors, values) => {
|
result = await handleConnect();
|
||||||
if(errors){
|
}else if(current === 1){
|
||||||
return false;
|
result = await handleCommit();
|
||||||
}
|
|
||||||
console.log(values)
|
|
||||||
}).catch((err)=>{
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if(!result){
|
if(!result){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
setIsLoading(false)
|
||||||
changeStep(current + 1)
|
changeStep(current + 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,48 +125,97 @@ const ClusterStep = ({
|
||||||
changeStep(current - 1)
|
changeStep(current - 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const oneMoreClick = ()=>{
|
||||||
|
setClusterConfig({});
|
||||||
|
changeStep(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToClusterList = ()=>{
|
||||||
|
history.push('/system/cluster');
|
||||||
|
}
|
||||||
|
|
||||||
const renderContent = (current)=>{
|
const renderContent = (current)=>{
|
||||||
if(current===0){
|
if(current===0){
|
||||||
return <InitialStep ref={initalFormRef} />
|
return <InitialStep ref={formRef} initialValue={clusterConfig} />
|
||||||
}else if(current === 1){
|
}else if(current === 1){
|
||||||
return <></>
|
return <ExtraStep initialValue={clusterConfig} ref={formRef}/>
|
||||||
}else{
|
}else if(current === 2){
|
||||||
return null
|
return <ResultStep clusterConfig={clusterConfig} oneMoreClick={oneMoreClick}
|
||||||
|
goToClusterList={goToClusterList}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
const content = (
|
||||||
<Steps current={current}>
|
<div className={styles.pageHeaderContent}>
|
||||||
{steps.map(item => (
|
<p>
|
||||||
<Step key={item.title} title={item.title} />
|
输入集群地址和身份验证信息分步创建集群。
|
||||||
))}
|
</p>
|
||||||
</Steps>
|
<div className={styles.contentLink}>
|
||||||
<div className="steps-content">{renderContent(current)}</div>
|
<a>
|
||||||
<div className="steps-action" style={{textAlign:'center'}}>
|
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg" />{' '}
|
||||||
{current < steps.length - 1 && (
|
快速开始
|
||||||
<Button type="primary" onClick={() => next()}>
|
</a>
|
||||||
下一步
|
<a>
|
||||||
</Button>
|
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" />{' '}
|
||||||
)}
|
产品简介
|
||||||
{current === steps.length - 1 && (
|
</a>
|
||||||
<Button type="primary" onClick={() => message.success('Processing complete!')}>
|
<a>
|
||||||
完成
|
<img alt="" src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg" />{' '}
|
||||||
</Button>
|
产品文档
|
||||||
)}
|
</a>
|
||||||
{current > 0 && (
|
|
||||||
<Button style={{ margin: '0 8px' }} onClick={() => prev()}>
|
|
||||||
上一步
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const extraContent = (
|
||||||
|
<div className={styles.extraImg}>
|
||||||
|
<img
|
||||||
|
alt="这是一个标题"
|
||||||
|
src="https://gw.alipayobjects.com/zos/rmsportal/RzwpdLnhmvDJToTdfDPe.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageHeaderWrapper title="集群注册" content={content} extraContent={extraContent}>
|
||||||
|
<Card>
|
||||||
|
<Spin spinning={isLoading}>
|
||||||
|
<div style={{maxWidth:720, margin:'0 auto'}}>
|
||||||
|
<Steps current={current} style={{marginBottom:24}}>
|
||||||
|
{steps.map(item => (
|
||||||
|
<Step key={item.title} title={item.title} />
|
||||||
|
))}
|
||||||
|
</Steps>
|
||||||
|
<div className="steps-content">{renderContent(current)}</div>
|
||||||
|
<div className="steps-action" style={{textAlign:'center'}}>
|
||||||
|
{current === 1 && (
|
||||||
|
<Button style={{ margin: '0 8px' }} onClick={() => prev()}>
|
||||||
|
上一步
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{current < steps.length - 1 && (
|
||||||
|
<Button type="primary" onClick={() => next()}>
|
||||||
|
下一步
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</Card>
|
||||||
|
</PageHeaderWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const NewCluster = ()=>{
|
const NewCluster = (props)=>{
|
||||||
|
const {dispatch, history} = props;
|
||||||
const [current, setCurrent] = useState(0);
|
const [current, setCurrent] = useState(0);
|
||||||
return <ClusterStep current={current} changeStep={setCurrent} />
|
return <ClusterStep current={current} changeStep={setCurrent}
|
||||||
|
history={history}
|
||||||
|
dispatch={dispatch} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(({
|
export default connect(({
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {createClusterConfig, searchClusterConfig, updateClusterConfig,deleteClusterConfig, getClusterStatus} from "@/services/cluster";
|
import {createClusterConfig, searchClusterConfig, updateClusterConfig,deleteClusterConfig,
|
||||||
|
getClusterStatus, tryConnect} from "@/services/cluster";
|
||||||
import {message} from "antd";
|
import {message} from "antd";
|
||||||
import {formatESSearchResult} from '@/lib/elasticsearch/util';
|
import {formatESSearchResult} from '@/lib/elasticsearch/util';
|
||||||
|
|
||||||
|
@ -45,6 +46,9 @@ export default {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let {data, total} = yield select(state => state.clusterConfig);
|
let {data, total} = yield select(state => state.clusterConfig);
|
||||||
|
if(!data){
|
||||||
|
return
|
||||||
|
}
|
||||||
data.unshift({
|
data.unshift({
|
||||||
...res._source,
|
...res._source,
|
||||||
id: res._id,
|
id: res._id,
|
||||||
|
@ -147,6 +151,21 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res;
|
return res;
|
||||||
|
},
|
||||||
|
*doTryConnect({payload}, {call, put, select}) {
|
||||||
|
let res = yield call(tryConnect, payload)
|
||||||
|
if(res.error){
|
||||||
|
message.error(res.error)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put({
|
||||||
|
type: 'saveData',
|
||||||
|
payload: {
|
||||||
|
tempClusterInfo: res,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reducers:{
|
reducers:{
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
.extraImg {
|
||||||
|
margin-top: -60px;
|
||||||
|
text-align: center;
|
||||||
|
width: 195px;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pageHeaderContent {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentLink {
|
||||||
|
margin-top: 16px;
|
||||||
|
a {
|
||||||
|
margin-right: 32px;
|
||||||
|
img {
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
import {Form, Input, Switch, Icon, InputNumber, Divider, Descriptions} from 'antd';
|
||||||
|
|
||||||
|
@Form.create()
|
||||||
|
export class ExtraStep extends React.Component {
|
||||||
|
state = {
|
||||||
|
}
|
||||||
|
render(){
|
||||||
|
const {form:{getFieldDecorator}, initialValue} = this.props;
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 6 },
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 16 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Descriptions column={2} size="small" bordered>
|
||||||
|
<Descriptions.Item label="集群版本" >
|
||||||
|
{initialValue?.version}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="健康状态" >
|
||||||
|
{initialValue?.status}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="节点数" >
|
||||||
|
{initialValue?.number_of_nodes}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="数据节点数" >
|
||||||
|
{initialValue?.number_of_data_nodes}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="分片数" >
|
||||||
|
{initialValue?.active_shards}
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
<Divider/>
|
||||||
|
<Form {...formItemLayout} style={{marginTop:15}} form={this.props.formRef}>
|
||||||
|
<Form.Item label="集群名称" >
|
||||||
|
{getFieldDecorator('name', {
|
||||||
|
initialValue: initialValue?.cluster_name || '',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'Please input cluster name!',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})(<Input autoComplete='off' placeholder="cluster-name" />)}
|
||||||
|
</Form.Item>
|
||||||
|
{/* <Form.Item label="Elasticsearch 版本">
|
||||||
|
{getFieldDecorator('version', {
|
||||||
|
initialValue: initialValue?.version || '',
|
||||||
|
})(<Input readOnly={true} />)}
|
||||||
|
</Form.Item> */}
|
||||||
|
{/* <Form.Item label="排序权重">
|
||||||
|
{getFieldDecorator('order', {
|
||||||
|
initialValue: 0,
|
||||||
|
})(<InputNumber />)}
|
||||||
|
</Form.Item> */}
|
||||||
|
<Form.Item label="描述">
|
||||||
|
{getFieldDecorator('description', {
|
||||||
|
initialValue: '',
|
||||||
|
})(<Input.TextArea placeholder="集群应用描述" />)}
|
||||||
|
</Form.Item>
|
||||||
|
{/* <Form.Item label="是否启用">
|
||||||
|
{getFieldDecorator('enabled', {
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: true,
|
||||||
|
})(<Switch
|
||||||
|
checkedChildren={<Icon type="check" />}
|
||||||
|
unCheckedChildren={<Icon type="close" />}
|
||||||
|
/>)}
|
||||||
|
</Form.Item> */}
|
||||||
|
<Form.Item label="启用监控">
|
||||||
|
{getFieldDecorator('monitored', {
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: true,
|
||||||
|
})(<Switch
|
||||||
|
checkedChildren={<Icon type="check" />}
|
||||||
|
unCheckedChildren={<Icon type="close" />}
|
||||||
|
/>)}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export * from './initial_step';
|
||||||
|
export * from './extra_step';
|
||||||
|
export * from './result_step';
|
|
@ -1,10 +1,12 @@
|
||||||
import {Form, Input, Switch, Icon} from 'antd';
|
import {Form, Input, Switch, Icon} from 'antd';
|
||||||
import {useState} from 'react';
|
|
||||||
|
|
||||||
@Form.create()
|
@Form.create()
|
||||||
class InitialStep extends React.Component {
|
export class InitialStep extends React.Component {
|
||||||
state = {
|
constructor(props){
|
||||||
needAuth: false,
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
needAuth: props.initialValue?.username !== undefined,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handleAuthChange = (val) => {
|
handleAuthChange = (val) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -12,7 +14,7 @@ class InitialStep extends React.Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
render(){
|
render(){
|
||||||
const {form:{getFieldDecorator}} = this.props;
|
const {form:{getFieldDecorator}, initialValue} = this.props;
|
||||||
const formItemLayout = {
|
const formItemLayout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
xs: { span: 24 },
|
xs: { span: 24 },
|
||||||
|
@ -24,34 +26,33 @@ class InitialStep extends React.Component {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Form {...formItemLayout} style={{marginTop:15}} form={this.props.formRef}>
|
<Form {...formItemLayout} form={this.props.formRef}>
|
||||||
<Form.Item label="集群名称" >
|
<Form.Item label="集群地址">
|
||||||
{getFieldDecorator('name', {
|
{getFieldDecorator('host', {
|
||||||
initialValue: '',
|
initialValue: initialValue?.host || '',
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
type: 'string',
|
||||||
message: 'Please input cluster name!',
|
pattern: /^[\w\.]+\:\d+$/, //(https?:\/\/)?
|
||||||
},
|
message: '请输入域名或 IP 地址和端口号',
|
||||||
],
|
|
||||||
})(<Input autoComplete='off' placeholder="cluster-name" />)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label="集群 URL">
|
|
||||||
{getFieldDecorator('endpoint', {
|
|
||||||
initialValue: '',
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
type: 'url',
|
|
||||||
message: 'The input is not valid url!',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: 'Please input cluster endpoint!',
|
message: '请输入集群地址!',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})(<Input placeholder="http://127.0.0.1:9200" />)}
|
})(<Input placeholder="127.0.0.1:9200" />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="是否需要身份验证">
|
<Form.Item label="TLS">
|
||||||
|
{getFieldDecorator('isTLS', {
|
||||||
|
initialValue: initialValue?.isTLS || false,
|
||||||
|
})(
|
||||||
|
<Switch
|
||||||
|
checkedChildren={<Icon type="check" />}
|
||||||
|
unCheckedChildren={<Icon type="close" />}
|
||||||
|
/>)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="身份验证">
|
||||||
<Switch
|
<Switch
|
||||||
defaultChecked={this.state.needAuth}
|
defaultChecked={this.state.needAuth}
|
||||||
onChange={this.handleAuthChange}
|
onChange={this.handleAuthChange}
|
||||||
|
@ -62,7 +63,7 @@ class InitialStep extends React.Component {
|
||||||
{this.state.needAuth === true ? (<div>
|
{this.state.needAuth === true ? (<div>
|
||||||
<Form.Item label="用户名">
|
<Form.Item label="用户名">
|
||||||
{getFieldDecorator('username', {
|
{getFieldDecorator('username', {
|
||||||
initialValue: '',
|
initialValue: initialValue?.username || '',
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -73,7 +74,7 @@ class InitialStep extends React.Component {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="密码" hasFeedback>
|
<Form.Item label="密码" hasFeedback>
|
||||||
{getFieldDecorator('password', {
|
{getFieldDecorator('password', {
|
||||||
initialValue: '',
|
initialValue: initialValue?.password || '',
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -86,6 +87,4 @@ class InitialStep extends React.Component {
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default InitialStep;
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import Result from '@/components/Result';
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import { Button, Row, Col } from 'antd';
|
||||||
|
import styles from './styles.less';
|
||||||
|
|
||||||
|
export const ResultStep = (props)=>{
|
||||||
|
const {clusterConfig, oneMoreClick, goToClusterList} = props;
|
||||||
|
const information = (
|
||||||
|
<div className={styles.information}>
|
||||||
|
<Row>
|
||||||
|
<Col xs={24} sm={8} className={styles.label}>
|
||||||
|
集群名称:
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={16}>
|
||||||
|
{clusterConfig?.cluster_name}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col xs={24} sm={8} className={styles.label}>
|
||||||
|
集群版本:
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={16}>
|
||||||
|
{clusterConfig?.version}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col xs={24} sm={8} className={styles.label}>
|
||||||
|
集群地址:
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={16}>
|
||||||
|
{clusterConfig?.host}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col xs={24} sm={8} className={styles.label}>
|
||||||
|
TLS:
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={16}>
|
||||||
|
{clusterConfig?.isTLS ? '是': '否'}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
const actions = (
|
||||||
|
<Fragment>
|
||||||
|
<Button type="primary" onClick={oneMoreClick}>
|
||||||
|
再创建一个集群
|
||||||
|
</Button>
|
||||||
|
<Button onClick={goToClusterList}>查看集群列表</Button>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
type="success"
|
||||||
|
title="创建成功"
|
||||||
|
description=""
|
||||||
|
extra={information}
|
||||||
|
actions={actions}
|
||||||
|
className={styles.result}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
@import '~antd/lib/style/themes/default.less';
|
||||||
|
.result {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 560px;
|
||||||
|
padding: 24px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
padding: 0 56px;
|
||||||
|
// color: @text-color-secondary;
|
||||||
|
h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
// color: @text-color-secondary;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
// color: @text-color-secondary;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: @screen-md) {
|
||||||
|
.desc {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.information {
|
||||||
|
line-height: 22px;
|
||||||
|
:global {
|
||||||
|
.ant-row:not(:last-child) {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
// color: @heading-color;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 8px;
|
||||||
|
@media screen and (max-width: @screen-sm) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.money {
|
||||||
|
font-family: 'Helvetica Neue', sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uppercase {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ export async function getClusterMetrics(params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createClusterConfig(params) {
|
export async function createClusterConfig(params) {
|
||||||
return request(`/elasticsearch`, {
|
return request(`/elasticsearch/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: params,
|
body: params,
|
||||||
});
|
});
|
||||||
|
@ -57,4 +57,12 @@ export async function getClusterStatus(params) {
|
||||||
return request(url, {
|
return request(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function tryConnect(params) {
|
||||||
|
let url = `/elasticsearch/try_connect`;
|
||||||
|
return request(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: params,
|
||||||
|
});
|
||||||
}
|
}
|
Loading…
Reference in New Issue