mirror of https://github.com/openspug/spug
U 发布配置克隆已支持跨应用克隆并新增查看配置功能
parent
488bc3d7bf
commit
d539544fa6
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||||
|
* Copyright (c) <spug.dev@gmail.com>
|
||||||
|
* Released under the AGPL-3.0 License.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { Cascader, Form } from 'antd';
|
||||||
|
import envStore from 'pages/config/environment/store';
|
||||||
|
import store from './store';
|
||||||
|
import lds from 'lodash';
|
||||||
|
import { toJS } from "mobx";
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class CloneConfirm extends React.Component {
|
||||||
|
handleLoadData = (selectedOptions) => {
|
||||||
|
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||||||
|
if (targetOption.deploys === undefined) {
|
||||||
|
targetOption.loading = true;
|
||||||
|
store.loadDeploys(targetOption.value).then(() => targetOption.loading = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleData = records => {
|
||||||
|
return records.map(x => {
|
||||||
|
const option = {
|
||||||
|
label: x.name,
|
||||||
|
value: x.id,
|
||||||
|
deploys: x.deploys,
|
||||||
|
isLeaf: false
|
||||||
|
}
|
||||||
|
if (x.children) {
|
||||||
|
option.children = x.children
|
||||||
|
} else if (x.deploys) {
|
||||||
|
option.children = x.deploys.map(item => ({
|
||||||
|
label: lds.get(envStore.idMap, `${item.env_id}.name`),
|
||||||
|
value: JSON.stringify(item),
|
||||||
|
id: `${x.id},${item.env_id}`,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return option
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const options = this.handleData(Object.values(toJS(store.records)));
|
||||||
|
return (
|
||||||
|
<Form>
|
||||||
|
<Form.Item required label="应用及环境" help="克隆配置,将基于选择对象的配置来创建新的发布配置。">
|
||||||
|
<Cascader
|
||||||
|
options={options}
|
||||||
|
loadData={this.handleLoadData}
|
||||||
|
onChange={this.props.onChange}/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CloneConfirm
|
|
@ -13,12 +13,19 @@ import store from './store';
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
|
|
||||||
export default observer(function Ext1From() {
|
export default observer(function Ext1From() {
|
||||||
|
const appName = store.records[store.app_id].name;
|
||||||
|
let title = `常规发布 - ${appName}`;
|
||||||
|
if (store.deploy.id) {
|
||||||
|
store.isReadOnly ? title = '查看' + title : title = '编辑' + title;
|
||||||
|
} else {
|
||||||
|
title = '新建' + title
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible
|
visible
|
||||||
width={900}
|
width={900}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
title={store.deploy.id ? '编辑常规发布' : '新建常规发布'}
|
title={title}
|
||||||
onCancel={() => store.ext1Visible = false}
|
onCancel={() => store.ext1Visible = false}
|
||||||
footer={null}>
|
footer={null}>
|
||||||
<Steps current={store.page} className={styles.steps}>
|
<Steps current={store.page} className={styles.steps}>
|
||||||
|
|
|
@ -16,21 +16,23 @@ export default observer(function Ext2Setup1() {
|
||||||
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
||||||
<Form.Item required label="发布环境">
|
<Form.Item required label="发布环境">
|
||||||
<Col span={16}>
|
<Col span={16}>
|
||||||
<Select value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
|
<Select disabled={store.isReadOnly} value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
|
||||||
{envStore.records.map(item => (
|
{envStore.records.map(item => (
|
||||||
<Select.Option value={item.id} key={item.id}>{item.name}</Select.Option>
|
<Select.Option value={item.id} key={item.id}>{item.name}</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6} offset={2}>
|
<Col span={6} offset={2}>
|
||||||
<Link to="/config/environment">新建环境</Link>
|
<Link disabled={store.isReadOnly} to="/config/environment">新建环境</Link>
|
||||||
</Col>
|
</Col>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="Git仓库地址">
|
<Form.Item required label="Git仓库地址">
|
||||||
<Input value={info['git_repo']} onChange={e => info['git_repo'] = e.target.value} placeholder="请输入Git仓库地址"/>
|
<Input disabled={store.isReadOnly} value={info['git_repo']} onChange={e => info['git_repo'] = e.target.value}
|
||||||
|
placeholder="请输入Git仓库地址"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="发布审核">
|
<Form.Item label="发布审核">
|
||||||
<Switch
|
<Switch
|
||||||
|
disabled={store.isReadOnly}
|
||||||
checkedChildren="开启"
|
checkedChildren="开启"
|
||||||
unCheckedChildren="关闭"
|
unCheckedChildren="关闭"
|
||||||
checked={info['is_audit']}
|
checked={info['is_audit']}
|
||||||
|
@ -42,7 +44,7 @@ export default observer(function Ext2Setup1() {
|
||||||
href="https://spug.dev/docs/install-error/#%E9%92%89%E9%92%89%E6%94%B6%E4%B8%8D%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%9F">钉钉收不到通知?</a>
|
href="https://spug.dev/docs/install-error/#%E9%92%89%E9%92%89%E6%94%B6%E4%B8%8D%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%9F">钉钉收不到通知?</a>
|
||||||
</span>}>
|
</span>}>
|
||||||
<Input addonBefore={(
|
<Input addonBefore={(
|
||||||
<Select
|
<Select disabled={store.isReadOnly}
|
||||||
value={info['rst_notify']['mode']} style={{width: 100}} onChange={v => info['rst_notify']['mode'] = v}>
|
value={info['rst_notify']['mode']} style={{width: 100}} onChange={v => info['rst_notify']['mode'] = v}>
|
||||||
<Select.Option value="0">关闭</Select.Option>
|
<Select.Option value="0">关闭</Select.Option>
|
||||||
<Select.Option value="1">钉钉</Select.Option>
|
<Select.Option value="1">钉钉</Select.Option>
|
||||||
|
@ -50,7 +52,7 @@ export default observer(function Ext2Setup1() {
|
||||||
<Select.Option value="2">Webhook</Select.Option>
|
<Select.Option value="2">Webhook</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
disabled={info['rst_notify']['mode'] === '0'}
|
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
|
||||||
value={info['rst_notify']['value']}
|
value={info['rst_notify']['value']}
|
||||||
onChange={e => info['rst_notify']['value'] = e.target.value}
|
onChange={e => info['rst_notify']['value'] = e.target.value}
|
||||||
placeholder="请输入"/>
|
placeholder="请输入"/>
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Ext1Setup2 extends React.Component {
|
||||||
if (dst_repo.includes(dst_dir.replace(/\/*$/, '/'))) {
|
if (dst_repo.includes(dst_dir.replace(/\/*$/, '/'))) {
|
||||||
message.error('仓库目录不能位于发布部署目录内')
|
message.error('仓库目录不能位于发布部署目录内')
|
||||||
} else {
|
} else {
|
||||||
store.page += 1
|
store.page += 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,13 +37,14 @@ class Ext1Setup2 extends React.Component {
|
||||||
return (
|
return (
|
||||||
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
||||||
<Form.Item required label="目标主机部署路径" help="目标主机的应用根目录,例如:/var/www/html">
|
<Form.Item required label="目标主机部署路径" help="目标主机的应用根目录,例如:/var/www/html">
|
||||||
<Input value={info['dst_dir']} onChange={e => info['dst_dir'] = e.target.value} placeholder="请输入目标主机部署路径"/>
|
<Input disabled={store.isReadOnly} value={info['dst_dir']} onChange={e => info['dst_dir'] = e.target.value}
|
||||||
|
placeholder="请输入目标主机部署路径"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="目标主机仓库路径" help="此目录用于存储应用的历史版本,例如:/data/spug/repos">
|
<Form.Item required label="目标主机仓库路径" help="此目录用于存储应用的历史版本,例如:/data/spug/repos">
|
||||||
<Input value={info['dst_repo']} onChange={e => info['dst_repo'] = e.target.value} placeholder="请输入目标主机仓库路径"/>
|
<Input disabled={store.isReadOnly} value={info['dst_repo']} onChange={e => info['dst_repo'] = e.target.value} placeholder="请输入目标主机仓库路径"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="保留历史版本数量" help="早于指定数量的历史版本会被删除,以释放空间">
|
<Form.Item required label="保留历史版本数量" help="早于指定数量的历史版本会被删除,以释放空间">
|
||||||
<Input value={info['versions']} onChange={e => info['versions'] = e.target.value} placeholder="请输入保留历史版本数量"/>
|
<Input disabled={store.isReadOnly} value={info['versions']} onChange={e => info['versions'] = e.target.value} placeholder="请输入保留历史版本数量"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="发布目标主机">
|
<Form.Item required label="发布目标主机">
|
||||||
{info['host_ids'].map((id, index) => (
|
{info['host_ids'].map((id, index) => (
|
||||||
|
@ -52,6 +53,7 @@ class Ext1Setup2 extends React.Component {
|
||||||
value={id}
|
value={id}
|
||||||
showSearch
|
showSearch
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
|
disabled={store.isReadOnly}
|
||||||
style={{width: '80%', marginRight: 10}}
|
style={{width: '80%', marginRight: 10}}
|
||||||
optionFilterProp="children"
|
optionFilterProp="children"
|
||||||
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
|
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
|
||||||
|
@ -62,14 +64,14 @@ class Ext1Setup2 extends React.Component {
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
{info['host_ids'].length > 1 && (
|
{!store.isReadOnly && info['host_ids'].length > 1 && (
|
||||||
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
|
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</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={store.addHost}>
|
<Button disabled={store.isReadOnly} type="dashed" style={{width: '80%'}} onClick={store.addHost}>
|
||||||
<Icon type="plus"/>添加目标主机
|
<Icon type="plus"/>添加目标主机
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
|
@ -55,6 +55,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
<div style={{display: 'inline-block', height: 39, width: 390}}>
|
<div style={{display: 'inline-block', height: 39, width: 390}}>
|
||||||
<span style={{float: 'left'}}>文件过滤<span style={{margin: '0 8px 0 2px'}}>:</span></span>
|
<span style={{float: 'left'}}>文件过滤<span style={{margin: '0 8px 0 2px'}}>:</span></span>
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
|
disabled={store.isReadOnly}
|
||||||
style={{marginLeft: 20, float: 'left'}}
|
style={{marginLeft: 20, float: 'left'}}
|
||||||
value={props.type}
|
value={props.type}
|
||||||
onChange={e => store.deploy['filter_rule']['type'] = e.target.value}>
|
onChange={e => store.deploy['filter_rule']['type'] = e.target.value}>
|
||||||
|
@ -105,6 +106,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '1' ? styles.fullScreen : null}
|
className={full === '1' ? styles.fullScreen : null}
|
||||||
label={<this.FilterLabel type={info['filter_rule']['type']}/>}>
|
label={<this.FilterLabel type={info['filter_rule']['type']}/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="text"
|
mode="text"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -119,6 +121,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '3' ? styles.fullScreen : null}
|
className={full === '3' ? styles.fullScreen : null}
|
||||||
label={<this.NormalLabel title="代码检出前执行" id="3"/>}>
|
label={<this.NormalLabel title="代码检出前执行" id="3"/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -133,6 +136,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '5' ? styles.fullScreen : null}
|
className={full === '5' ? styles.fullScreen : null}
|
||||||
label={<this.NormalLabel title="应用发布前执行" id="5"/>}>
|
label={<this.NormalLabel title="应用发布前执行" id="5"/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -163,6 +167,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '2' ? styles.fullScreen : null}
|
className={full === '2' ? styles.fullScreen : null}
|
||||||
label={<this.NormalLabel title="自定义全局变量" id="2"/>}>
|
label={<this.NormalLabel title="自定义全局变量" id="2"/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="text"
|
mode="text"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -177,6 +182,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '4' ? styles.fullScreen : null}
|
className={full === '4' ? styles.fullScreen : null}
|
||||||
label={<this.NormalLabel title="代码检出后执行" id="4"/>}>
|
label={<this.NormalLabel title="代码检出后执行" id="4"/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -191,6 +197,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
className={full === '6' ? styles.fullScreen : null}
|
className={full === '6' ? styles.fullScreen : null}
|
||||||
label={<this.NormalLabel title="应用发布后执行" id="6"/>}>
|
label={<this.NormalLabel title="应用发布后执行" id="6"/>}>
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -203,7 +210,7 @@ class Ext1Setup3 extends React.Component {
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Button type="primary" onClick={this.handleSubmit}>提交</Button>
|
<Button disabled={store.isReadOnly} type="primary" onClick={this.handleSubmit}>提交</Button>
|
||||||
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -13,12 +13,19 @@ import Setup3 from './Ext2Setup3';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
export default observer(function Ext2From() {
|
export default observer(function Ext2From() {
|
||||||
|
const appName = store.records[store.app_id].name;
|
||||||
|
let title = `自定义发布 - ${appName}`;
|
||||||
|
if (store.deploy.id) {
|
||||||
|
store.isReadOnly ? title = '查看' + title : title = '编辑' + title;
|
||||||
|
} else {
|
||||||
|
title = '新建' + title
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible
|
visible
|
||||||
width={900}
|
width={900}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
title={store.deploy.id ? '编辑自定义发布' : '新建自定义发布'}
|
title={title}
|
||||||
onCancel={() => store.ext2Visible = false}
|
onCancel={() => store.ext2Visible = false}
|
||||||
footer={null}>
|
footer={null}>
|
||||||
<Steps current={store.page} className={styles.steps}>
|
<Steps current={store.page} className={styles.steps}>
|
||||||
|
|
|
@ -16,18 +16,19 @@ export default observer(function Ext2Setup1() {
|
||||||
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
|
||||||
<Form.Item required label="发布环境">
|
<Form.Item required label="发布环境">
|
||||||
<Col span={16}>
|
<Col span={16}>
|
||||||
<Select value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
|
<Select disabled={store.isReadOnly} value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
|
||||||
{envStore.records.map(item => (
|
{envStore.records.map(item => (
|
||||||
<Select.Option value={item.id} key={item.id}>{item.name}</Select.Option>
|
<Select.Option value={item.id} key={item.id}>{item.name}</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6} offset={2}>
|
<Col span={6} offset={2}>
|
||||||
<Link to="/config/environment">新建环境</Link>
|
<Link disabled={store.isReadOnly} to="/config/environment">新建环境</Link>
|
||||||
</Col>
|
</Col>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="发布审核">
|
<Form.Item label="发布审核">
|
||||||
<Switch
|
<Switch
|
||||||
|
disabled={store.isReadOnly}
|
||||||
checkedChildren="开启"
|
checkedChildren="开启"
|
||||||
unCheckedChildren="关闭"
|
unCheckedChildren="关闭"
|
||||||
checked={info['is_audit']}
|
checked={info['is_audit']}
|
||||||
|
@ -39,7 +40,7 @@ export default observer(function Ext2Setup1() {
|
||||||
href="https://spug.dev/docs/install-error/#%E9%92%89%E9%92%89%E6%94%B6%E4%B8%8D%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%9F">钉钉收不到通知?</a>
|
href="https://spug.dev/docs/install-error/#%E9%92%89%E9%92%89%E6%94%B6%E4%B8%8D%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%9F">钉钉收不到通知?</a>
|
||||||
</span>}>
|
</span>}>
|
||||||
<Input addonBefore={(
|
<Input addonBefore={(
|
||||||
<Select
|
<Select disabled={store.isReadOnly}
|
||||||
value={info['rst_notify']['mode']} style={{width: 100}} onChange={v => info['rst_notify']['mode'] = v}>
|
value={info['rst_notify']['mode']} style={{width: 100}} onChange={v => info['rst_notify']['mode'] = v}>
|
||||||
<Select.Option value="0">关闭</Select.Option>
|
<Select.Option value="0">关闭</Select.Option>
|
||||||
<Select.Option value="1">钉钉</Select.Option>
|
<Select.Option value="1">钉钉</Select.Option>
|
||||||
|
@ -47,7 +48,7 @@ export default observer(function Ext2Setup1() {
|
||||||
<Select.Option value="2">Webhook</Select.Option>
|
<Select.Option value="2">Webhook</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
disabled={info['rst_notify']['mode'] === '0'}
|
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
|
||||||
value={info['rst_notify']['value']}
|
value={info['rst_notify']['value']}
|
||||||
onChange={e => info['rst_notify']['value'] = e.target.value}
|
onChange={e => info['rst_notify']['value'] = e.target.value}
|
||||||
placeholder="请输入"/>
|
placeholder="请输入"/>
|
||||||
|
|
|
@ -28,6 +28,7 @@ class Ext2Setup2 extends React.Component {
|
||||||
<Select
|
<Select
|
||||||
value={id}
|
value={id}
|
||||||
showSearch
|
showSearch
|
||||||
|
disabled={store.isReadOnly}
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
optionFilterProp="children"
|
optionFilterProp="children"
|
||||||
style={{width: '80%', marginRight: 10}}
|
style={{width: '80%', marginRight: 10}}
|
||||||
|
@ -39,14 +40,14 @@ class Ext2Setup2 extends React.Component {
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
{info['host_ids'].length > 1 && (
|
{!store.isReadOnly && info['host_ids'].length > 1 && (
|
||||||
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
|
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</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={store.addHost}>
|
<Button disabled={store.isReadOnly} type="dashed" style={{width: '80%'}} onClick={store.addHost}>
|
||||||
<Icon type="plus"/>添加目标主机
|
<Icon type="plus"/>添加目标主机
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
|
@ -64,11 +64,13 @@ class Ext2Setup3 extends React.Component {
|
||||||
{server_actions.map((item, index) => (
|
{server_actions.map((item, index) => (
|
||||||
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
||||||
<Form.Item required label={`本地动作${index + 1}`}>
|
<Form.Item required label={`本地动作${index + 1}`}>
|
||||||
<Input value={item['title']} onChange={e => item['title'] = e.target.value} placeholder="请输入"/>
|
<Input disabled={store.isReadOnly} value={item['title']} onChange={e => item['title'] = e.target.value}
|
||||||
|
placeholder="请输入"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item required label="执行内容">
|
<Form.Item required label="执行内容">
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -77,21 +79,26 @@ class Ext2Setup3 extends React.Component {
|
||||||
onChange={v => item['data'] = cleanCommand(v)}
|
onChange={v => item['data'] = cleanCommand(v)}
|
||||||
placeholder="请输入要执行的动作"/>
|
placeholder="请输入要执行的动作"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<div className={styles.delAction} onClick={() => server_actions.splice(index, 1)}>
|
{!store.isReadOnly && (
|
||||||
<Icon type="minus-circle"/>移除
|
<div className={styles.delAction} onClick={() => server_actions.splice(index, 1)}>
|
||||||
</div>
|
<Icon type="minus-circle"/>移除
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
{!store.isReadOnly && (
|
||||||
<Button type="dashed" block onClick={() => server_actions.push({})}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Icon type="plus"/>添加本地执行动作(在服务端本地执行)
|
<Button type="dashed" block onClick={() => server_actions.push({})}>
|
||||||
</Button>
|
<Icon type="plus"/>添加本地执行动作(在服务端本地执行)
|
||||||
</Form.Item>
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
<Divider/>
|
<Divider/>
|
||||||
{host_actions.map((item, index) => (
|
{host_actions.map((item, index) => (
|
||||||
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
<div key={index} style={{marginBottom: 30, position: 'relative'}}>
|
||||||
<Form.Item required label={`目标主机动作${index + 1}`}>
|
<Form.Item required label={`目标主机动作${index + 1}`}>
|
||||||
<Input value={item['title']} onChange={e => item['title'] = e.target.value} placeholder="请输入"/>
|
<Input disabled={store.isReadOnly} value={item['title']} onChange={e => item['title'] = e.target.value}
|
||||||
|
placeholder="请输入"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{item['type'] === 'transfer' ? ([
|
{item['type'] === 'transfer' ? ([
|
||||||
<Form.Item key={0} label="过滤规则" help={this.helpMap[item['mode']]}>
|
<Form.Item key={0} label="过滤规则" help={this.helpMap[item['mode']]}>
|
||||||
|
@ -100,9 +107,10 @@ class Ext2Setup3 extends React.Component {
|
||||||
placeholder="请输入逗号分割的过滤规则"
|
placeholder="请输入逗号分割的过滤规则"
|
||||||
value={item['rule']}
|
value={item['rule']}
|
||||||
onChange={e => item['rule'] = e.target.value.replace(',', ',')}
|
onChange={e => item['rule'] = e.target.value.replace(',', ',')}
|
||||||
disabled={item['mode'] === '0'}
|
disabled={store.isReadOnly || item['mode'] === '0'}
|
||||||
addonBefore={(
|
addonBefore={(
|
||||||
<Select style={{width: 100}} value={item['mode']} onChange={v => item['mode'] = v}>
|
<Select disabled={store.isReadOnly} style={{width: 100}} value={item['mode']}
|
||||||
|
onChange={v => item['mode'] = v}>
|
||||||
<Select.Option value="0">关闭</Select.Option>
|
<Select.Option value="0">关闭</Select.Option>
|
||||||
<Select.Option value="1">包含</Select.Option>
|
<Select.Option value="1">包含</Select.Option>
|
||||||
<Select.Option value="2">排除</Select.Option>
|
<Select.Option value="2">排除</Select.Option>
|
||||||
|
@ -113,11 +121,13 @@ class Ext2Setup3 extends React.Component {
|
||||||
target="_blank" rel="noopener noreferrer"
|
target="_blank" rel="noopener noreferrer"
|
||||||
href="https://spug.dev/docs/deploy-config#%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93">使用前请务必阅读官方文档。</a>}>
|
href="https://spug.dev/docs/deploy-config#%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93">使用前请务必阅读官方文档。</a>}>
|
||||||
<Input
|
<Input
|
||||||
|
disabled={store.isReadOnly}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
value={item['src']}
|
value={item['src']}
|
||||||
placeholder="请输入本地路径(部署spug的容器或主机)"
|
placeholder="请输入本地路径(部署spug的容器或主机)"
|
||||||
onChange={e => item['src'] = e.target.value}/>
|
onChange={e => item['src'] = e.target.value}/>
|
||||||
<Input
|
<Input
|
||||||
|
disabled={store.isReadOnly}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
value={item['dst']}
|
value={item['dst']}
|
||||||
placeholder="请输入目标主机路径"
|
placeholder="请输入目标主机路径"
|
||||||
|
@ -126,6 +136,7 @@ class Ext2Setup3 extends React.Component {
|
||||||
]) : (
|
]) : (
|
||||||
<Form.Item required label="执行内容">
|
<Form.Item required label="执行内容">
|
||||||
<Editor
|
<Editor
|
||||||
|
readOnly={store.isReadOnly}
|
||||||
mode="sh"
|
mode="sh"
|
||||||
theme="tomorrow"
|
theme="tomorrow"
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -135,27 +146,31 @@ class Ext2Setup3 extends React.Component {
|
||||||
placeholder="请输入要执行的动作"/>
|
placeholder="请输入要执行的动作"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
<div className={styles.delAction} onClick={() => host_actions.splice(index, 1)}>
|
{!store.isReadOnly && (
|
||||||
<Icon type="minus-circle"/>移除
|
<div className={styles.delAction} onClick={() => host_actions.splice(index, 1)}>
|
||||||
</div>
|
<Icon type="minus-circle"/>移除
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
{!store.isReadOnly && (
|
||||||
<Button type="dashed" block onClick={() => host_actions.push({})}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Icon type="plus"/>添加目标主机执行动作(在部署目标主机执行)
|
<Button disabled={store.isReadOnly} type="dashed" block onClick={() => host_actions.push({})}>
|
||||||
</Button>
|
<Icon type="plus"/>添加目标主机执行动作(在部署目标主机执行)
|
||||||
<Button
|
</Button>
|
||||||
block
|
<Button
|
||||||
type="dashed"
|
block
|
||||||
disabled={lds.findIndex(host_actions, x => x.type === 'transfer') !== -1}
|
type="dashed"
|
||||||
onClick={() => host_actions.push({type: 'transfer', title: '数据传输', mode: '0'})}>
|
disabled={store.isReadOnly || lds.findIndex(host_actions, x => x.type === 'transfer') !== -1}
|
||||||
<Icon type="plus"/>添加数据传输动作(仅能添加一个)
|
onClick={() => host_actions.push({type: 'transfer', title: '数据传输', mode: '0'})}>
|
||||||
</Button>
|
<Icon type="plus"/>添加数据传输动作(仅能添加一个)
|
||||||
</Form.Item>
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
<Form.Item wrapperCol={{span: 14, offset: 6}}>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
disabled={[...host_actions, ...server_actions].filter(x => x.title && x.data).length === 0}
|
disabled={store.isReadOnly || [...host_actions, ...server_actions].filter(x => x.title && x.data).length === 0}
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
onClick={this.handleSubmit}>提交</Button>
|
onClick={this.handleSubmit}>提交</Button>
|
||||||
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
<Button style={{marginLeft: 20}} onClick={() => store.page -= 1}>上一步</Button>
|
||||||
|
|
|
@ -10,11 +10,17 @@ import { Table, Divider, Modal, Tag, Icon, message } from 'antd';
|
||||||
import http from 'libs/http';
|
import http from 'libs/http';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
import { LinkButton } from "components";
|
import { LinkButton } from "components";
|
||||||
|
import CloneConfirm from './CloneConfirm';
|
||||||
import envStore from 'pages/config/environment/store';
|
import envStore from 'pages/config/environment/store';
|
||||||
import lds from 'lodash';
|
import lds from 'lodash';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class ComTable extends React.Component {
|
class ComTable extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.cloneObj = {};
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
store.fetchRecords();
|
store.fetchRecords();
|
||||||
if (envStore.records.length === 0) {
|
if (envStore.records.length === 0) {
|
||||||
|
@ -43,6 +49,8 @@ class ComTable extends React.Component {
|
||||||
<span>
|
<span>
|
||||||
<LinkButton auth="deploy.app.edit" onClick={e => store.showExtForm(e, info.id)}>新建发布</LinkButton>
|
<LinkButton auth="deploy.app.edit" onClick={e => store.showExtForm(e, info.id)}>新建发布</LinkButton>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
|
<LinkButton auth="deploy.app.edit" onClick={e => this.handleClone(e, info.id)}>克隆发布</LinkButton>
|
||||||
|
<Divider type="vertical"/>
|
||||||
<LinkButton auth="deploy.app.edit" onClick={e => store.showForm(e, info)}>编辑</LinkButton>
|
<LinkButton auth="deploy.app.edit" onClick={e => store.showForm(e, info)}>编辑</LinkButton>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
<LinkButton auth="deploy.app.del" onClick={e => this.handleDelete(e, info)}>删除</LinkButton>
|
<LinkButton auth="deploy.app.del" onClick={e => this.handleDelete(e, info)}>删除</LinkButton>
|
||||||
|
@ -50,6 +58,19 @@ class ComTable extends React.Component {
|
||||||
)
|
)
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
handleClone = (e, id) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Modal.confirm({
|
||||||
|
icon: 'exclamation-circle',
|
||||||
|
title: '选择克隆对象',
|
||||||
|
content: <CloneConfirm onChange={v => this.cloneObj = v[1]}/>,
|
||||||
|
onOk: () => {
|
||||||
|
const info = JSON.parse(this.cloneObj);
|
||||||
|
store.showExtForm(null, id, info, true)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
handleDelete = (e, text) => {
|
handleDelete = (e, text) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
|
@ -102,12 +123,13 @@ class ComTable extends React.Component {
|
||||||
title: '操作',
|
title: '操作',
|
||||||
render: info => (
|
render: info => (
|
||||||
<span>
|
<span>
|
||||||
<LinkButton auth="deploy.app.edit" onClick={e => store.showExtForm(e, record.id, info)}>编辑</LinkButton>
|
<LinkButton auth="deploy.app.edit"
|
||||||
<Divider type="vertical"/>
|
onClick={e => store.showExtForm(e, record.id, info, false, true)}>查看</LinkButton>
|
||||||
<LinkButton auth="deploy.app.edit" onClick={e => store.showExtForm(e, record.id, info, true)}>克隆配置</LinkButton>
|
<Divider type="vertical"/>
|
||||||
<Divider type="vertical"/>
|
<LinkButton auth="deploy.app.edit" onClick={e => store.showExtForm(e, record.id, info)}>编辑</LinkButton>
|
||||||
<LinkButton auth="deploy.app.edit" onClick={() => this.handleDeployDelete(info)}>删除</LinkButton>
|
<Divider type="vertical"/>
|
||||||
</span>
|
<LinkButton auth="deploy.app.edit" onClick={() => this.handleDeployDelete(info)}>删除</LinkButton>
|
||||||
|
</span>
|
||||||
)
|
)
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ class Store {
|
||||||
@observable deploy = {};
|
@observable deploy = {};
|
||||||
@observable page = 0;
|
@observable page = 0;
|
||||||
@observable loading = {};
|
@observable loading = {};
|
||||||
|
@observable isReadOnly = false;
|
||||||
@observable isFetching = false;
|
@observable isFetching = false;
|
||||||
@observable formVisible = false;
|
@observable formVisible = false;
|
||||||
@observable addVisible = false;
|
@observable addVisible = false;
|
||||||
|
@ -35,7 +36,7 @@ class Store {
|
||||||
};
|
};
|
||||||
|
|
||||||
loadDeploys = (app_id) => {
|
loadDeploys = (app_id) => {
|
||||||
http.get('/api/app/deploy/', {params: {app_id}})
|
return http.get('/api/app/deploy/', {params: {app_id}})
|
||||||
.then(res => this.records[app_id]['deploys'] = res)
|
.then(res => this.records[app_id]['deploys'] = res)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,10 +46,11 @@ class Store {
|
||||||
this.formVisible = true;
|
this.formVisible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
showExtForm = (e, app_id, info, isClone) => {
|
showExtForm = (e, app_id, info, isClone, isReadOnly = false) => {
|
||||||
if (e) e.stopPropagation();
|
if (e) e.stopPropagation();
|
||||||
this.page = 0;
|
this.page = 0;
|
||||||
this.app_id = app_id;
|
this.app_id = app_id;
|
||||||
|
this.isReadOnly = isReadOnly
|
||||||
if (info) {
|
if (info) {
|
||||||
if (info.extend === '1') {
|
if (info.extend === '1') {
|
||||||
this.ext1Visible = true
|
this.ext1Visible = true
|
||||||
|
|
Loading…
Reference in New Issue