mirror of https://github.com/openspug/spug
优化HostSelector组件
parent
4cb86923d6
commit
06479a8e45
|
@ -9,7 +9,7 @@ import { Link } from 'react-router-dom';
|
||||||
import { Switch, Form, Input, Select, Button, Radio } from 'antd';
|
import { Switch, Form, Input, Select, Button, Radio } from 'antd';
|
||||||
import Repo from './Repo';
|
import Repo from './Repo';
|
||||||
import envStore from 'pages/config/environment/store';
|
import envStore from 'pages/config/environment/store';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
export default observer(function Ext1Setup1() {
|
export default observer(function Ext1Setup1() {
|
||||||
|
@ -62,8 +62,7 @@ export default observer(function Ext1Setup1() {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="目标主机" tooltip="该发布配置作用于哪些目标主机。">
|
<Form.Item required label="目标主机" tooltip="该发布配置作用于哪些目标主机。">
|
||||||
{info.host_ids.length > 0 && <span style={{marginRight: 16}}>已选择 {info.host_ids.length} 台</span>}
|
<HostSelector value={info.host_ids} onChange={(_, ids) => info.host_ids = ids}/>
|
||||||
<Button type="link" style={{padding: 0}} onClick={() => store.selectorVisible = true}>选择主机</Button>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="Git仓库地址" extra={<span className="btn" onClick={() => setVisible(true)}>私有仓库?</span>}>
|
<Form.Item required label="Git仓库地址" extra={<span className="btn" onClick={() => setVisible(true)}>私有仓库?</span>}>
|
||||||
<Input disabled={store.isReadOnly} value={info['git_repo']} onChange={e => info['git_repo'] = e.target.value}
|
<Input disabled={store.isReadOnly} value={info['git_repo']} onChange={e => info['git_repo'] = e.target.value}
|
||||||
|
@ -116,11 +115,6 @@ export default observer(function Ext1Setup1() {
|
||||||
disabled={!(info.env_id && info.git_repo && info.host_ids.length)}
|
disabled={!(info.env_id && info.git_repo && info.host_ids.length)}
|
||||||
onClick={() => store.page += 1}>下一步</Button>
|
onClick={() => store.page += 1}>下一步</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Selector
|
|
||||||
visible={store.selectorVisible}
|
|
||||||
selectedRowKeys={[...info.host_ids]}
|
|
||||||
onCancel={() => store.selectorVisible = false}
|
|
||||||
onOk={(_, ids) => info.host_ids = ids}/>
|
|
||||||
{visible && <Repo url={info['git_repo']} onOk={v => info['git_repo'] = v} onCancel={() => setVisible(false)}/>}
|
{visible && <Repo url={info['git_repo']} onOk={v => info['git_repo'] = v} onCancel={() => setVisible(false)}/>}
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,12 +8,11 @@ import { observer } from 'mobx-react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Form, Switch, Select, Button, Input, Radio } from 'antd';
|
import { Form, Switch, Select, Button, Input, Radio } from 'antd';
|
||||||
import envStore from 'pages/config/environment/store';
|
import envStore from 'pages/config/environment/store';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
export default observer(function Ext2Setup1() {
|
export default observer(function Ext2Setup1() {
|
||||||
const [envs, setEnvs] = useState([]);
|
const [envs, setEnvs] = useState([]);
|
||||||
const [selectorVisible, setSelectorVisible] = useState(false);
|
|
||||||
|
|
||||||
function updateEnvs() {
|
function updateEnvs() {
|
||||||
const ids = store.currentRecord['deploys'].map(x => x.env_id);
|
const ids = store.currentRecord['deploys'].map(x => x.env_id);
|
||||||
|
@ -61,8 +60,7 @@ export default observer(function Ext2Setup1() {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="目标主机" tooltip="该发布配置作用于哪些目标主机。">
|
<Form.Item required label="目标主机" tooltip="该发布配置作用于哪些目标主机。">
|
||||||
{info.host_ids.length > 0 && <span style={{marginRight: 16}}>已选择 {info.host_ids.length} 台</span>}
|
<HostSelector value={info.host_ids} onChange={(_, ids) => info.host_ids = ids}/>
|
||||||
<Button type="link" style={{padding: 0}} onClick={() => setSelectorVisible(true)}>选择主机</Button>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="发布模式" tooltip="串行即发布时一台完成后再发布下一台,期间出现异常则终止发布。并行则每个主机相互独立发布同时进行。">
|
<Form.Item label="发布模式" tooltip="串行即发布时一台完成后再发布下一台,期间出现异常则终止发布。并行则每个主机相互独立发布同时进行。">
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
|
@ -110,11 +108,6 @@ export default observer(function Ext2Setup1() {
|
||||||
disabled={!(info.env_id && info.host_ids.length)}
|
disabled={!(info.env_id && info.host_ids.length)}
|
||||||
onClick={() => store.page += 1}>下一步</Button>
|
onClick={() => store.page += 1}>下一步</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Selector
|
|
||||||
visible={selectorVisible}
|
|
||||||
selectedRowKeys={[...info.host_ids]}
|
|
||||||
onCancel={() => setSelectorVisible(false)}
|
|
||||||
onOk={(_, ids) => info.host_ids = ids}/>
|
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,6 @@ class Store {
|
||||||
@observable ext1Visible = false;
|
@observable ext1Visible = false;
|
||||||
@observable ext2Visible = false;
|
@observable ext2Visible = false;
|
||||||
@observable autoVisible = false;
|
@observable autoVisible = false;
|
||||||
@observable selectorVisible = false;
|
|
||||||
|
|
||||||
@observable f_name;
|
@observable f_name;
|
||||||
@observable f_desc;
|
@observable f_desc;
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { PlusOutlined, ThunderboltOutlined, BulbOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
import { PlusOutlined, ThunderboltOutlined, BulbOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
import { Form, Button, Alert, Radio, Tooltip } from 'antd';
|
import { Form, Button, Radio, Tooltip } from 'antd';
|
||||||
import { ACEditor, AuthDiv, Breadcrumb } from 'components';
|
import { ACEditor, AuthDiv, Breadcrumb } from 'components';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import TemplateSelector from './TemplateSelector';
|
import TemplateSelector from './TemplateSelector';
|
||||||
import Parameter from './Parameter';
|
import Parameter from './Parameter';
|
||||||
import Output from './Output';
|
import Output from './Output';
|
||||||
|
@ -87,17 +87,7 @@ function TaskIndex() {
|
||||||
<div className={style.index} hidden={store.showConsole}>
|
<div className={style.index} hidden={store.showConsole}>
|
||||||
<Form layout="vertical" className={style.left}>
|
<Form layout="vertical" className={style.left}>
|
||||||
<Form.Item required label="目标主机">
|
<Form.Item required label="目标主机">
|
||||||
{store.host_ids.length > 0 ? (
|
<HostSelector type="button" value={store.host_ids} onChange={(_, ids) => store.host_ids = ids}/>
|
||||||
<Alert
|
|
||||||
type="info"
|
|
||||||
className={style.area}
|
|
||||||
message={<div>已选择 <b style={{fontSize: 18, color: '#1890ff'}}>{store.host_ids.length}</b> 台主机</div>}
|
|
||||||
onClick={() => store.showHost = true}/>
|
|
||||||
) : (
|
|
||||||
<Button icon={<PlusOutlined/>} onClick={() => store.showHost = true}>
|
|
||||||
添加目标主机
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item required label="执行命令" style={{position: 'relative'}}>
|
<Form.Item required label="执行命令" style={{position: 'relative'}}>
|
||||||
|
@ -144,12 +134,6 @@ function TaskIndex() {
|
||||||
{store.showTemplate && <TemplateSelector onCancel={store.switchTemplate} onOk={handleTemplate}/>}
|
{store.showTemplate && <TemplateSelector onCancel={store.switchTemplate} onOk={handleTemplate}/>}
|
||||||
{store.showConsole && <Output onBack={store.switchConsole}/>}
|
{store.showConsole && <Output onBack={store.switchConsole}/>}
|
||||||
{visible && <Parameter parameters={parameters} onCancel={() => setVisible(false)} onOk={v => handleSubmit(v)}/>}
|
{visible && <Parameter parameters={parameters} onCancel={() => setVisible(false)} onOk={v => handleSubmit(v)}/>}
|
||||||
<Selector
|
|
||||||
visible={store.showHost}
|
|
||||||
selectedRowKeys={[...store.host_ids]}
|
|
||||||
onCancel={() => store.showHost = false}
|
|
||||||
onOk={(_, ids) => store.host_ids = ids}/>
|
|
||||||
|
|
||||||
</AuthDiv>
|
</AuthDiv>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,6 @@
|
||||||
width: 60%;
|
width: 60%;
|
||||||
border-right: 1px solid #dfdfdf;
|
border-right: 1px solid #dfdfdf;
|
||||||
|
|
||||||
.area {
|
|
||||||
cursor: pointer;
|
|
||||||
width: 200px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tips {
|
.tips {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
|
|
@ -11,7 +11,6 @@ class Store {
|
||||||
@observable tag = '';
|
@observable tag = '';
|
||||||
@observable host_ids = [];
|
@observable host_ids = [];
|
||||||
@observable token = null;
|
@observable token = null;
|
||||||
@observable showHost = false;
|
|
||||||
@observable showConsole = false;
|
@observable showConsole = false;
|
||||||
@observable showTemplate = false;
|
@observable showTemplate = false;
|
||||||
|
|
||||||
|
@ -50,10 +49,6 @@ class Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchHost = () => {
|
|
||||||
this.showHost = !this.showHost;
|
|
||||||
};
|
|
||||||
|
|
||||||
switchTemplate = () => {
|
switchTemplate = () => {
|
||||||
this.showTemplate = !this.showTemplate
|
this.showTemplate = !this.showTemplate
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { observer } from 'mobx-react';
|
||||||
import { ExclamationCircleOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
import { Modal, Form, Input, Select, Button, Radio, Table, Tooltip, message } from 'antd';
|
import { Modal, Form, Input, Select, Button, Radio, Table, Tooltip, message } from 'antd';
|
||||||
import { ACEditor } from 'components';
|
import { ACEditor } from 'components';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import Parameter from './Parameter';
|
import Parameter from './Parameter';
|
||||||
import { http, cleanCommand } from 'libs';
|
import { http, cleanCommand } from 'libs';
|
||||||
import lds from 'lodash';
|
import lds from 'lodash';
|
||||||
|
@ -20,7 +20,6 @@ export default observer(function () {
|
||||||
const [body, setBody] = useState(S.record.body);
|
const [body, setBody] = useState(S.record.body);
|
||||||
const [parameter, setParameter] = useState();
|
const [parameter, setParameter] = useState();
|
||||||
const [parameters, setParameters] = useState([]);
|
const [parameters, setParameters] = useState([]);
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setParameters(S.record.parameters)
|
setParameters(S.record.parameters)
|
||||||
|
@ -136,18 +135,12 @@ export default observer(function () {
|
||||||
<Button type="link" style={{padding: 0}} onClick={() => setParameter({})}>添加参数</Button>
|
<Button type="link" style={{padding: 0}} onClick={() => setParameter({})}>添加参数</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="目标主机">
|
<Form.Item label="目标主机">
|
||||||
{info.host_ids.length > 0 && <span style={{marginRight: 16}}>已选择 {info.host_ids.length} 台</span>}
|
<HostSelector value={info.host_ids} onChange={(_, ids) => info.host_ids = ids}/>
|
||||||
<Button type="link" style={{padding: 0}} onClick={() => setVisible(true)}>选择主机</Button>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="desc" label="备注信息">
|
<Form.Item name="desc" label="备注信息">
|
||||||
<Input.TextArea placeholder="请输入模板备注信息"/>
|
<Input.TextArea placeholder="请输入模板备注信息"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
<Selector
|
|
||||||
visible={visible}
|
|
||||||
selectedRowKeys={[...info.host_ids]}
|
|
||||||
onCancel={() => setVisible(false)}
|
|
||||||
onOk={(_, ids) => info.host_ids = ids}/>
|
|
||||||
{parameter ? (
|
{parameter ? (
|
||||||
<Parameter
|
<Parameter
|
||||||
parameter={parameter}
|
parameter={parameter}
|
||||||
|
|
|
@ -6,16 +6,15 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
|
||||||
ThunderboltOutlined,
|
ThunderboltOutlined,
|
||||||
QuestionCircleOutlined,
|
QuestionCircleOutlined,
|
||||||
UploadOutlined,
|
UploadOutlined,
|
||||||
CloudServerOutlined,
|
CloudServerOutlined,
|
||||||
BulbOutlined,
|
BulbOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Form, Button, Alert, Tooltip, Space, Card, Table, Input, Upload, message } from 'antd';
|
import { Form, Button, Tooltip, Space, Card, Table, Input, Upload, message } from 'antd';
|
||||||
import { AuthDiv, Breadcrumb } from 'components';
|
import { AuthDiv, Breadcrumb } from 'components';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import Output from './Output';
|
import Output from './Output';
|
||||||
import { http, uniqueId } from 'libs';
|
import { http, uniqueId } from 'libs';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -27,7 +26,6 @@ function TransferIndex() {
|
||||||
const [files, setFiles] = useState([])
|
const [files, setFiles] = useState([])
|
||||||
const [dir, setDir] = useState('')
|
const [dir, setDir] = useState('')
|
||||||
const [hosts, setHosts] = useState([])
|
const [hosts, setHosts] = useState([])
|
||||||
const [sProps, setSProps] = useState({visible: false})
|
|
||||||
const [percent, setPercent] = useState()
|
const [percent, setPercent] = useState()
|
||||||
const [token, setToken] = useState()
|
const [token, setToken] = useState()
|
||||||
const [histories, setHistories] = useState([])
|
const [histories, setHistories] = useState([])
|
||||||
|
@ -80,23 +78,14 @@ function TransferIndex() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddHostFile() {
|
function makeFile(row) {
|
||||||
setSProps({
|
setFiles([{
|
||||||
visible: true,
|
id: uniqueId(),
|
||||||
onlyOne: true,
|
type: 'host',
|
||||||
selectedRowKeys: [],
|
name: row.name,
|
||||||
onCancel: () => setSProps({visible: false}),
|
path: '',
|
||||||
onOk: (_, __, row) => setFiles([{id: uniqueId(), type: 'host', name: row.name, path: '', host_id: row.id}]),
|
host_id: row.id
|
||||||
})
|
}])
|
||||||
}
|
|
||||||
|
|
||||||
function handleAddHost() {
|
|
||||||
setSProps({
|
|
||||||
visible: true,
|
|
||||||
selectedRowKeys: hosts.map(x => x.id),
|
|
||||||
onCancel: () => setSProps({visible: false}),
|
|
||||||
onOk: (_, __, rows) => setHosts(rows),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpload(_, fileList) {
|
function handleUpload(_, fileList) {
|
||||||
|
@ -131,7 +120,9 @@ function TransferIndex() {
|
||||||
<Card type="inner" title={`数据源${files.length ? `(${files.length})` : ''}`} extra={(<Space size={24}>
|
<Card type="inner" title={`数据源${files.length ? `(${files.length})` : ''}`} extra={(<Space size={24}>
|
||||||
<Upload multiple beforeUpload={handleUpload}><Space
|
<Upload multiple beforeUpload={handleUpload}><Space
|
||||||
className="btn"><UploadOutlined/>上传本地文件</Space></Upload>
|
className="btn"><UploadOutlined/>上传本地文件</Space></Upload>
|
||||||
<Space className="btn" onClick={handleAddHostFile}><CloudServerOutlined/>添加主机文件</Space>
|
<HostSelector onlyOne onChange={(_, __, row) => makeFile(row)}>
|
||||||
|
<Space className="btn"><CloudServerOutlined/>添加主机文件</Space>
|
||||||
|
</HostSelector>
|
||||||
</Space>)}>
|
</Space>)}>
|
||||||
<Table rowKey="id" className={style.table} showHeader={false} pagination={false} size="small"
|
<Table rowKey="id" className={style.table} showHeader={false} pagination={false} size="small"
|
||||||
dataSource={files}>
|
dataSource={files}>
|
||||||
|
@ -153,13 +144,7 @@ function TransferIndex() {
|
||||||
<Input value={dir} onChange={e => setDir(e.target.value)} placeholder="请输入目标路径"/>
|
<Input value={dir} onChange={e => setDir(e.target.value)} placeholder="请输入目标路径"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="目标主机">
|
<Form.Item required label="目标主机">
|
||||||
{hosts.length > 0 ? (<Alert
|
<HostSelector type="button" value={hosts.map(x => x.id)} onChange={(_, __, rows) => setHosts(rows)}/>
|
||||||
type="info"
|
|
||||||
className={style.area}
|
|
||||||
message={<div>已选择 <b style={{fontSize: 18, color: '#1890ff'}}>{hosts.length}</b> 台主机</div>}
|
|
||||||
onClick={handleAddHost}/>) : (<Button icon={<PlusOutlined/>} onClick={handleAddHost}>
|
|
||||||
添加目标主机
|
|
||||||
</Button>)}
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -191,7 +176,6 @@ function TransferIndex() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Selector {...sProps}/>
|
|
||||||
{token ? <Output token={token} onBack={handleCloseOutput}/> : null}
|
{token ? <Output token={token} onBack={handleCloseOutput}/> : null}
|
||||||
</AuthDiv>)
|
</AuthDiv>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
*/
|
*/
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { Modal, Row, Col, Tree, Table, Button, Space, Input } from 'antd';
|
import { Modal, Row, Col, Tree, Table, Button, Space, Input, Alert } from 'antd';
|
||||||
import { FolderOpenOutlined, FolderOutlined } from '@ant-design/icons';
|
import { FolderOpenOutlined, FolderOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import IPAddress from './IPAddress';
|
import IPAddress from './IPAddress';
|
||||||
import hStore from './store';
|
import hStore from './store';
|
||||||
import store from './store2';
|
import store from './store2';
|
||||||
import styles from './index.module.less';
|
import styles from './selector.module.less';
|
||||||
|
|
||||||
|
function HostSelector(props) {
|
||||||
export default observer(function (props) {
|
const [visible, setVisible] = useState(false)
|
||||||
const [isReady, setIsReady] = useState(false)
|
const [isReady, setIsReady] = useState(false)
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
|
@ -42,8 +42,8 @@ export default observer(function (props) {
|
||||||
}, [store.treeData])
|
}, [store.treeData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedRowKeys(props.selectedRowKeys || [])
|
setSelectedRowKeys([...props.value])
|
||||||
}, [props.selectedRowKeys])
|
}, [props.value])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.onlySelf) {
|
if (props.onlySelf) {
|
||||||
|
@ -62,20 +62,19 @@ export default observer(function (props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
if (props.onOk) {
|
if (props.onChange) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let res
|
let res
|
||||||
const selectedRows = store.rawRecords.filter(x => selectedRowKeys.includes(x.id))
|
const selectedRows = store.rawRecords.filter(x => selectedRowKeys.includes(x.id))
|
||||||
if (props.onlyOne) {
|
if (props.onlyOne) {
|
||||||
res = props.onOk(store.group, selectedRowKeys[0], selectedRows[0])
|
res = props.onChange(store.group, selectedRowKeys[0], selectedRows[0])
|
||||||
} else {
|
} else {
|
||||||
res = props.onOk(store.group, selectedRowKeys, selectedRows);
|
res = props.onChange(store.group, selectedRowKeys, selectedRows);
|
||||||
}
|
}
|
||||||
if (res && res.then) {
|
if (res && res.then) {
|
||||||
res.then(props.onCancel, () => setLoading(false))
|
res.then(handleClose, () => setLoading(false))
|
||||||
} else {
|
} else {
|
||||||
props.onCancel();
|
handleClose()
|
||||||
setLoading(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,67 +108,104 @@ export default observer(function (props) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleClose() {
|
||||||
|
setSelectedRowKeys([])
|
||||||
|
setLoading(false)
|
||||||
|
setVisible(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<div className={styles.selector}>
|
||||||
visible={[undefined, true].includes(props.visible)}
|
{props.children ? (
|
||||||
width={1000}
|
<div onClick={() => setVisible(true)}>{props.children}</div>
|
||||||
className={styles.selector}
|
) : (
|
||||||
title={props.title || '主机列表'}
|
props.type === 'button' ? (
|
||||||
onOk={handleSubmit}
|
props.value.length > 0 ? (
|
||||||
okButtonProps={{disabled: selectedRowKeys.length === 0}}
|
<Alert
|
||||||
confirmLoading={loading}
|
type="info"
|
||||||
onCancel={props.onCancel}>
|
className={styles.area}
|
||||||
<Row>
|
message={<div>已选择 <b style={{fontSize: 18, color: '#1890ff'}}>{props.value.length}</b> 台主机</div>}
|
||||||
<Col span={6} style={{borderRight: '8px solid #f0f0f0', paddingRight: 12}}>
|
onClick={() => setVisible(true)}/>
|
||||||
<div className={styles.gTitle}>分组列表</div>
|
) : (
|
||||||
<Tree.DirectoryTree
|
<Button icon={<PlusOutlined/>} onClick={() => setVisible(true)}>
|
||||||
showIcon={false}
|
添加目标主机
|
||||||
autoExpandParent
|
</Button>
|
||||||
expandAction="doubleClick"
|
)) : (
|
||||||
selectedKeys={[store.group.key]}
|
<div style={{display: 'flex', alignItems: 'center'}}>
|
||||||
expandedKeys={expands}
|
{props.value.length > 0 && <span style={{marginRight: 16}}>已选择 {props.value.length} 台</span>}
|
||||||
treeData={store.treeData}
|
<Button type="link" style={{padding: 0}} onClick={() => setVisible(true)}>选择主机</Button>
|
||||||
titleRender={treeRender}
|
|
||||||
onExpand={handleExpand}
|
|
||||||
onSelect={(_, {node}) => store.group = node}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span={18} style={{paddingLeft: 12}}>
|
|
||||||
<div style={{display: 'flex', justifyContent: 'space-between', marginBottom: 12}}>
|
|
||||||
<Input allowClear style={{width: 260}} placeholder="输入名称/IP检索"
|
|
||||||
onChange={e => store.f_word = e.target.value}/>
|
|
||||||
<Space hidden={selectedRowKeys.length === 0}>
|
|
||||||
<div>已选择 {selectedRowKeys.length} 台主机</div>
|
|
||||||
<Button type="link" style={{paddingRight: 0}} onClick={() => setSelectedRowKeys([])}>取消选择</Button>
|
|
||||||
</Space>
|
|
||||||
</div>
|
</div>
|
||||||
<Table
|
)
|
||||||
rowKey="id"
|
)}
|
||||||
dataSource={store.dataSource}
|
|
||||||
pagination={false}
|
<Modal
|
||||||
scroll={{y: 480}}
|
visible={visible}
|
||||||
onRow={record => {
|
width={1000}
|
||||||
return {
|
className={styles.modal}
|
||||||
onClick: () => handleClickRow(record)
|
title={props.title || '主机列表'}
|
||||||
}
|
onOk={handleSubmit}
|
||||||
}}
|
okButtonProps={{disabled: selectedRowKeys.length === 0}}
|
||||||
rowSelection={{
|
confirmLoading={loading}
|
||||||
selectedRowKeys,
|
onCancel={handleClose}>
|
||||||
hideSelectAll: props.onlyOne,
|
<Row>
|
||||||
onSelect: handleClickRow,
|
<Col span={6} style={{borderRight: '8px solid #f0f0f0', paddingRight: 12}}>
|
||||||
onSelectAll: handleSelectAll
|
<div className={styles.gTitle}>分组列表</div>
|
||||||
}}>
|
<Tree.DirectoryTree
|
||||||
<Table.Column ellipsis width={170} title="主机名称" dataIndex="name"/>
|
showIcon={false}
|
||||||
<Table.Column width={320} title="IP地址" render={info => (
|
autoExpandParent
|
||||||
<Space>
|
expandAction="doubleClick"
|
||||||
<IPAddress ip={info.public_ip_address} isPublic/>
|
selectedKeys={[store.group.key]}
|
||||||
<IPAddress ip={info.private_ip_address}/>
|
expandedKeys={expands}
|
||||||
|
treeData={store.treeData}
|
||||||
|
titleRender={treeRender}
|
||||||
|
onExpand={handleExpand}
|
||||||
|
onSelect={(_, {node}) => store.group = node}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={18} style={{paddingLeft: 12}}>
|
||||||
|
<div style={{display: 'flex', justifyContent: 'space-between', marginBottom: 12}}>
|
||||||
|
<Input allowClear style={{width: 260}} placeholder="输入名称/IP检索"
|
||||||
|
onChange={e => store.f_word = e.target.value}/>
|
||||||
|
<Space hidden={selectedRowKeys.length === 0}>
|
||||||
|
<div>已选择 {selectedRowKeys.length} 台主机</div>
|
||||||
|
<Button type="link" style={{paddingRight: 0}} onClick={() => setSelectedRowKeys([])}>取消选择</Button>
|
||||||
</Space>
|
</Space>
|
||||||
)}/>
|
</div>
|
||||||
<Table.Column title="备注信息" dataIndex="desc"/>
|
<Table
|
||||||
</Table>
|
rowKey="id"
|
||||||
</Col>
|
dataSource={store.dataSource}
|
||||||
</Row>
|
pagination={false}
|
||||||
</Modal>
|
scroll={{y: 480}}
|
||||||
|
onRow={record => {
|
||||||
|
return {
|
||||||
|
onClick: () => handleClickRow(record)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
rowSelection={{
|
||||||
|
selectedRowKeys,
|
||||||
|
hideSelectAll: props.onlyOne,
|
||||||
|
onSelect: handleClickRow,
|
||||||
|
onSelectAll: handleSelectAll
|
||||||
|
}}>
|
||||||
|
<Table.Column ellipsis width={170} title="主机名称" dataIndex="name"/>
|
||||||
|
<Table.Column width={320} title="IP地址" render={info => (
|
||||||
|
<Space>
|
||||||
|
<IPAddress ip={info.public_ip_address} isPublic/>
|
||||||
|
<IPAddress ip={info.private_ip_address}/>
|
||||||
|
</Space>
|
||||||
|
)}/>
|
||||||
|
<Table.Column title="备注信息" dataIndex="desc"/>
|
||||||
|
</Table>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
|
HostSelector.defaultProps = {
|
||||||
|
value: [],
|
||||||
|
type: 'text'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default observer(HostSelector)
|
|
@ -26,21 +26,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector {
|
|
||||||
:global(.ant-modal-footer) {
|
|
||||||
border-top: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.gTitle {
|
|
||||||
height: 44px;
|
|
||||||
line-height: 44px;
|
|
||||||
padding-left: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.formAddress1 {
|
.formAddress1 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
.modal {
|
||||||
|
:global(.ant-modal-footer) {
|
||||||
|
border-top: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.gTitle {
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
padding-left: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.area {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 200px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeNode {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number {
|
||||||
|
width: 30px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { observer } from 'mobx-react';
|
||||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
import { Modal, Form, Input, Select, Button, message } from 'antd';
|
import { Modal, Form, Input, Select, Button, message } from 'antd';
|
||||||
import TemplateSelector from '../exec/task/TemplateSelector';
|
import TemplateSelector from '../exec/task/TemplateSelector';
|
||||||
import Selector from 'pages/host/Selector';
|
import HostSelector from 'pages/host/Selector';
|
||||||
import { LinkButton, ACEditor } from 'components';
|
import { LinkButton, ACEditor } from 'components';
|
||||||
import { http, cleanCommand } from 'libs';
|
import { http, cleanCommand } from 'libs';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
@ -22,7 +22,6 @@ const helpMap = {
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [showTmp, setShowTmp] = useState(false);
|
const [showTmp, setShowTmp] = useState(false);
|
||||||
const [showSelector, setShowSelector] = useState(false);
|
|
||||||
|
|
||||||
function handleTest() {
|
function handleTest() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
@ -131,10 +130,7 @@ export default observer(function () {
|
||||||
notFoundContent={null}/>
|
notFoundContent={null}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="监控主机" style={getStyle(['3', '4'])}>
|
<Form.Item required label="监控主机" style={getStyle(['3', '4'])}>
|
||||||
{store.record.targets?.length > 0 && (
|
<HostSelector value={targets} onChange={(_, ids) => store.record.targets = ids}/>
|
||||||
<span style={{marginRight: 16}}>已选择 {store.record.targets.length} 台</span>
|
|
||||||
)}
|
|
||||||
<Button type="link" style={{padding: 0}} onClick={() => setShowSelector(true)}>选择主机</Button>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="响应时间" style={getStyle(['1'])}>
|
<Form.Item label="响应时间" style={getStyle(['1'])}>
|
||||||
<Input suffix="ms" value={extra} placeholder="最长响应时间(毫秒),不设置则默认10秒超时"
|
<Input suffix="ms" value={extra} placeholder="最长响应时间(毫秒),不设置则默认10秒超时"
|
||||||
|
@ -168,11 +164,6 @@ export default observer(function () {
|
||||||
<span style={{color: '#888', fontSize: 12}}>Tips: 仅测试第一个监控地址</span>
|
<span style={{color: '#888', fontSize: 12}}>Tips: 仅测试第一个监控地址</span>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{showTmp && <TemplateSelector onOk={({body}) => store.record.extra = body} onCancel={() => setShowTmp(false)}/>}
|
{showTmp && <TemplateSelector onOk={({body}) => store.record.extra = body} onCancel={() => setShowTmp(false)}/>}
|
||||||
<Selector
|
|
||||||
visible={showSelector}
|
|
||||||
selectedRowKeys={[...store.record.targets]}
|
|
||||||
onCancel={() => setShowSelector(false)}
|
|
||||||
onOk={(_, ids) => store.record.targets = ids}/>
|
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
})
|
})
|
|
@ -3,7 +3,7 @@
|
||||||
* Copyright (c) <spug.dev@gmail.com>
|
* Copyright (c) <spug.dev@gmail.com>
|
||||||
* Released under the AGPL-3.0 License.
|
* Released under the AGPL-3.0 License.
|
||||||
*/
|
*/
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { Form, Select, Button } from 'antd';
|
import { Form, Select, Button } from 'antd';
|
||||||
|
@ -13,7 +13,12 @@ import hostStore from 'pages/host/store';
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
|
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
const [visible, setVisible] = useState(false)
|
function handleChange(_, ids) {
|
||||||
|
if (store.targets.includes('local')) {
|
||||||
|
ids.unshift('local')
|
||||||
|
}
|
||||||
|
store.targets = ids
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -43,15 +48,10 @@ export default observer(function () {
|
||||||
))}
|
))}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Button type="dashed" style={{width: '80%'}} onClick={() => setVisible(true)}>
|
<HostSelector value={store.targets.filter(x => x !== 'local')} onChange={handleChange}>
|
||||||
<PlusOutlined/>添加执行对象
|
<Button type="dashed" style={{width: '80%'}}><PlusOutlined/>添加执行对象</Button>
|
||||||
</Button>
|
</HostSelector>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<HostSelector
|
|
||||||
visible={visible}
|
|
||||||
selectedRowKeys={[...store.targets]}
|
|
||||||
onCancel={() => setVisible(false)}
|
|
||||||
onOk={(_, ids) => store.targets = ids}/>
|
|
||||||
</Form>
|
</Form>
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Button disabled={store.targets.filter(x => x).length === 0} type="primary"
|
<Button disabled={store.targets.filter(x => x).length === 0} type="primary"
|
||||||
|
|
Loading…
Reference in New Issue