style migrate v3

pull/289/head
vapao 2020-11-26 12:16:08 +08:00
parent a1a9792f1d
commit 97bbe7ddf0
12 changed files with 221 additions and 223 deletions

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Modal, Card, Icon } from 'antd';
import { BuildOutlined, OrderedListOutlined } from '@ant-design/icons';
import { Modal, Card } from 'antd';
import store from './store';
import styles from './index.module.css';
@ -58,7 +59,7 @@ class AddSelect extends React.Component {
bodyStyle={{display: 'flex'}}
onClick={this.switchExt1}>
<div style={{marginRight: 16}}>
<Icon type="ordered-list" style={{fontSize: 36, color: '#1890ff'}}/>
<OrderedListOutlined style={{fontSize: 36, color: '#1890ff'}} />
</div>
<div>
<div className={styles.cardTitle}>常规发布</div>
@ -72,7 +73,7 @@ class AddSelect extends React.Component {
bodyStyle={{display: 'flex'}}
onClick={this.switchExt2}>
<div style={{marginRight: 16}}>
<Icon type="build" style={{fontSize: 36, color: '#1890ff'}}/>
<BuildOutlined style={{fontSize: 36, color: '#1890ff'}} />
</div>
<div>
<div className={styles.cardTitle}>自定义发布</div>

View File

@ -49,7 +49,7 @@ class CloneConfirm extends React.Component {
render() {
const options = this.handleData(Object.values(toJS(store.records)));
return (
<Form>
<Form layout="vertical" style={{marginTop: 24}}>
<Form.Item
required
label="应用及环境"

View File

@ -6,7 +6,7 @@
import React, { useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { Link } from 'react-router-dom';
import { Switch, Col, Form, Input, Select, Button } from "antd";
import { Switch, Form, Input, Select, Button } from 'antd';
import envStore from 'pages/config/environment/store';
import store from './store';
@ -29,17 +29,17 @@ export default observer(function Ext1Setup1() {
const info = store.deploy;
return (
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
<Form.Item required label="发布环境">
<Col span={16}>
<Form.Item required label="发布环境" style={{marginBottom: 0}}>
<Form.Item style={{display: 'inline-block', width: '80%'}}>
<Select disabled={store.isReadOnly} value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
{envStore.records.map(item => (
<Select.Option disabled={envs.includes(item.id)} value={item.id} key={item.id}>{item.name}</Select.Option>
))}
</Select>
</Col>
<Col span={6} offset={2}>
</Form.Item>
<Form.Item style={{display: 'inline-block', width: '20%', textAlign: 'right'}}>
<Link disabled={store.isReadOnly} to="/config/environment">新建环境</Link>
</Col>
</Form.Item>
</Form.Item>
<Form.Item required label="Git仓库地址">
<Input disabled={store.isReadOnly} value={info['git_repo']} onChange={e => info['git_repo'] = e.target.value}
@ -58,20 +58,21 @@ export default observer(function Ext1Setup1() {
<a target="_blank" rel="noopener noreferrer"
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>}>
<Input addonBefore={(
<Select disabled={store.isReadOnly}
value={info['rst_notify']['mode']} style={{width: 100}}
onChange={v => info['rst_notify']['mode'] = v}>
<Select.Option value="0">关闭</Select.Option>
<Select.Option value="1">钉钉</Select.Option>
<Select.Option value="3">企业微信</Select.Option>
<Select.Option value="2">Webhook</Select.Option>
</Select>
)}
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
value={info['rst_notify']['value']}
onChange={e => info['rst_notify']['value'] = e.target.value}
placeholder="请输入"/>
<Input
addonBefore={(
<Select disabled={store.isReadOnly}
value={info['rst_notify']['mode']} style={{width: 100}}
onChange={v => info['rst_notify']['mode'] = v}>
<Select.Option value="0">关闭</Select.Option>
<Select.Option value="1">钉钉</Select.Option>
<Select.Option value="3">企业微信</Select.Option>
<Select.Option value="2">Webhook</Select.Option>
</Select>
)}
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
value={info['rst_notify']['value']}
onChange={e => info['rst_notify']['value'] = e.target.value}
placeholder="请输入"/>
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Input, Select, Button, Icon, message } from "antd";
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Form, Input, Select, Button, message } from "antd";
import { hasHostPermission } from 'libs';
import store from './store';
import hostStore from 'pages/host/store';
@ -55,7 +56,7 @@ class Ext1Setup2 extends React.Component {
showSearch
placeholder="请选择"
disabled={store.isReadOnly}
style={{width: '80%', marginRight: 10}}
style={{width: '80%', marginRight: 10, marginBottom: 12}}
optionFilterProp="children"
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
onChange={v => store.editHost(index, v)}>
@ -66,14 +67,14 @@ class Ext1Setup2 extends React.Component {
))}
</Select>
{!store.isReadOnly && info['host_ids'].length > 1 && (
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
<MinusCircleOutlined className={styles.delIcon} onClick={() => store.delHost(index)} />
)}
</React.Fragment>
))}
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button disabled={store.isReadOnly} type="dashed" style={{width: '80%'}} onClick={store.addHost}>
<Icon type="plus"/>添加目标主机
<PlusOutlined />添加目标主机
</Button>
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Row, Col, Button, Radio, Icon, Tooltip, message } from "antd";
import { GitlabOutlined, InfoCircleOutlined, SettingOutlined, SwapOutlined } from '@ant-design/icons';
import { Form, Row, Col, Button, Radio, Tooltip, message } from 'antd';
import { LinkButton } from 'components';
import Editor from 'react-ace';
import 'ace-builds/src-noconflict/mode-text';
@ -51,9 +52,17 @@ class Ext1Setup3 extends React.Component {
}, () => this.setState({loading: false}))
};
handleFullscreen = (id) => {
if (this.state.full) {
this.setState({full: ''})
} else {
this.setState({full: id})
}
}
FilterLabel = (props) => (
<div style={{display: 'inline-block', height: 39, width: 390}}>
<span style={{float: 'left'}}>文件过滤<span style={{margin: '0 8px 0 2px'}}>:</span></span>
<div style={{display: 'flex', alignItems: 'center', height: 40}}>
<div>文件过滤 :</div>
<Radio.Group
disabled={store.isReadOnly}
style={{marginLeft: 20, float: 'left'}}
@ -61,36 +70,30 @@ class Ext1Setup3 extends React.Component {
onChange={e => store.deploy['filter_rule']['type'] = e.target.value}>
<Radio value="contain">包含
<Tooltip title="请输入相对于项目根目录的文件路径,仅将匹配到文件传输至要发布的目标主机。">
<Icon type="info-circle" style={{color: '#515151', marginLeft: 8}}/>
<InfoCircleOutlined style={{color: '#515151', marginLeft: 8}}/>
</Tooltip>
</Radio>
<Radio value="exclude">排除
<Tooltip title="支持模糊匹配,如果路径以 / 开头则基于项目根目录匹配,匹配到文件将不会被传输。">
<Icon type="info-circle" style={{color: '#515151', marginLeft: 8}}/>
<InfoCircleOutlined style={{color: '#515151', marginLeft: 8}}/>
</Tooltip>
</Radio>
</Radio.Group>
{this.state.full === '1' ? (
<LinkButton onClick={() => this.setState({full: ''})}>退出全屏</LinkButton>
) : (
<LinkButton onClick={() => this.setState({full: '1'})}>全屏</LinkButton>
)}
<div style={{flex: 1, textAlign: 'right'}}>
<LinkButton onClick={() => this.handleFullscreen('1')}>{this.state.full ? '退出全屏' : '全屏'}</LinkButton>
</div>
</div>
);
NormalLabel = (props) => (
<div style={{display: 'inline-block', height: 39, width: 390}}>
<span style={{float: 'left'}}>
{props.title}<span style={{margin: '0 8px 0 2px'}}>:</span>
<Tooltip title={this.helpMap[props.id]}>
<Icon type="info-circle" style={{color: '#515151'}}/>
</Tooltip>
</span>
{this.state.full ? (
<span style={{color: '#1890ff', cursor: 'pointer'}} onClick={() => this.setState({full: ''})}>退出全屏</span>
) : (
<span style={{color: '#1890ff', cursor: 'pointer'}} onClick={() => this.setState({full: props.id})}>全屏</span>
)}
<div style={{display: 'flex', alignItems: 'center', height: 40}}>
<div style={{marginRight: 8}}>{props.title} :</div>
<Tooltip title={this.helpMap[props.id]}>
<InfoCircleOutlined style={{color: '#515151'}}/>
</Tooltip>
<div style={{flex: 1, textAlign: 'right'}}>
<LinkButton onClick={() => this.handleFullscreen(props.id)}>{this.state.full ? '退出全屏' : '全屏'}</LinkButton>
</div>
</div>
);
@ -101,10 +104,8 @@ class Ext1Setup3 extends React.Component {
<React.Fragment>
<Row>
<Col span={11}>
<Form.Item
colon={false}
className={full === '1' ? styles.fullScreen : null}
label={<this.FilterLabel type={info['filter_rule']['type']}/>}>
<div className={full === '1' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.FilterLabel type={info['filter_rule']['type']}/>
<Editor
readOnly={store.isReadOnly}
mode="text"
@ -115,11 +116,9 @@ class Ext1Setup3 extends React.Component {
value={info['filter_rule']['data']}
onChange={v => info['filter_rule']['data'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
<Form.Item
colon={false}
className={full === '3' ? styles.fullScreen : null}
label={<this.NormalLabel title="代码检出前执行" id="3"/>}>
</div>
<div className={full === '3' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.NormalLabel title="代码检出前执行" id="3"/>
<Editor
readOnly={store.isReadOnly}
mode="sh"
@ -130,11 +129,9 @@ class Ext1Setup3 extends React.Component {
value={info['hook_pre_server']}
onChange={v => info['hook_pre_server'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
<Form.Item
colon={false}
className={full === '5' ? styles.fullScreen : null}
label={<this.NormalLabel title="应用发布前执行" id="5"/>}>
</div>
<div className={full === '5' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.NormalLabel title="应用发布前执行" id="5"/>
<Editor
readOnly={store.isReadOnly}
mode="sh"
@ -145,27 +142,25 @@ class Ext1Setup3 extends React.Component {
value={info['hook_pre_host']}
onChange={v => info['hook_pre_host'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
</div>
</Col>
<Col span={2}>
<div className={styles.deployBlock} style={{marginTop: 39}}>
<Icon type="setting" style={{fontSize: 32}}/>
<SettingOutlined style={{fontSize: 32}}/>
<span style={{fontSize: 12, marginTop: 5}}>基础设置</span>
</div>
<div className={styles.deployBlock}>
<Icon type="gitlab" style={{fontSize: 32}}/>
<GitlabOutlined style={{fontSize: 32}}/>
<span style={{fontSize: 12, marginTop: 5}}>检出代码</span>
</div>
<div className={styles.deployBlock}>
<Icon type="swap" style={{fontSize: 32}}/>
<SwapOutlined style={{fontSize: 32}}/>
<span style={{fontSize: 12, marginTop: 5}}>版本切换</span>
</div>
</Col>
<Col span={11}>
<Form.Item
colon={false}
className={full === '2' ? styles.fullScreen : null}
label={<this.NormalLabel title="自定义全局变量" id="2"/>}>
<div className={full === '2' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.NormalLabel title="自定义全局变量" id="2"/>
<Editor
readOnly={store.isReadOnly}
mode="text"
@ -176,11 +171,9 @@ class Ext1Setup3 extends React.Component {
value={info['custom_envs']}
onChange={v => info['custom_envs'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
<Form.Item
colon={false}
className={full === '4' ? styles.fullScreen : null}
label={<this.NormalLabel title="代码检出后执行" id="4"/>}>
</div>
<div className={full === '4' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.NormalLabel title="代码检出后执行" id="4"/>
<Editor
readOnly={store.isReadOnly}
mode="sh"
@ -191,11 +184,9 @@ class Ext1Setup3 extends React.Component {
value={info['hook_post_server']}
onChange={v => info['hook_post_server'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
<Form.Item
colon={false}
className={full === '6' ? styles.fullScreen : null}
label={<this.NormalLabel title="应用发布后执行" id="6"/>}>
</div>
<div className={full === '6' ? styles.fullScreen : null} style={{marginBottom: 24}}>
<this.NormalLabel title="应用发布后执行" id="6"/>
<Editor
readOnly={store.isReadOnly}
mode="sh"
@ -206,7 +197,7 @@ class Ext1Setup3 extends React.Component {
value={info['hook_post_host']}
onChange={v => info['hook_post_host'] = cleanCommand(v)}
style={{border: '1px solid #e8e8e8'}}/>
</Form.Item>
</div>
</Col>
</Row>
<Form.Item wrapperCol={{span: 14, offset: 6}}>

View File

@ -6,7 +6,7 @@
import React, { useState, useEffect } from 'react';
import { observer } from 'mobx-react';
import { Link } from 'react-router-dom';
import { Switch, Col, Form, Select, Button, Input } from "antd";
import { Form, Switch, Select, Button, Input } from "antd";
import envStore from 'pages/config/environment/store';
import store from './store';
@ -29,17 +29,17 @@ export default observer(function Ext2Setup1() {
const info = store.deploy;
return (
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
<Form.Item required label="发布环境">
<Col span={16}>
<Form.Item required label="发布环境" style={{marginBottom: 0}}>
<Form.Item style={{display: 'inline-block', width: '80%'}}>
<Select disabled={store.isReadOnly} value={info.env_id} onChange={v => info.env_id = v} placeholder="请选择发布环境">
{envStore.records.map(item => (
<Select.Option disabled={envs.includes(item.id)} value={item.id} key={item.id}>{item.name}</Select.Option>
))}
</Select>
</Col>
<Col span={6} offset={2}>
</Form.Item>
<Form.Item style={{display: 'inline-block', width: '20%', textAlign: 'right'}}>
<Link disabled={store.isReadOnly} to="/config/environment">新建环境</Link>
</Col>
</Form.Item>
</Form.Item>
<Form.Item label="发布审核">
<Switch
@ -54,20 +54,21 @@ export default observer(function Ext2Setup1() {
<a target="_blank" rel="noopener noreferrer"
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>}>
<Input addonBefore={(
<Select disabled={store.isReadOnly}
value={info['rst_notify']['mode']} style={{width: 100}}
onChange={v => info['rst_notify']['mode'] = v}>
<Select.Option value="0">关闭</Select.Option>
<Select.Option value="1">钉钉</Select.Option>
<Select.Option value="3">企业微信</Select.Option>
<Select.Option value="2">Webhook</Select.Option>
</Select>
)}
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
value={info['rst_notify']['value']}
onChange={e => info['rst_notify']['value'] = e.target.value}
placeholder="请输入"/>
<Input
addonBefore={(
<Select disabled={store.isReadOnly}
value={info['rst_notify']['mode']} style={{width: 100}}
onChange={v => info['rst_notify']['mode'] = v}>
<Select.Option value="0">关闭</Select.Option>
<Select.Option value="1">钉钉</Select.Option>
<Select.Option value="3">企业微信</Select.Option>
<Select.Option value="2">Webhook</Select.Option>
</Select>
)}
disabled={store.isReadOnly || info['rst_notify']['mode'] === '0'}
value={info['rst_notify']['value']}
onChange={e => info['rst_notify']['value'] = e.target.value}
placeholder="请输入"/>
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Select, Button, Icon } from "antd";
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Form, Select, Button } from 'antd';
import { hasHostPermission } from 'libs';
import store from './store';
import hostStore from 'pages/host/store';
@ -32,7 +33,7 @@ class Ext2Setup2 extends React.Component {
disabled={store.isReadOnly}
placeholder="请选择"
optionFilterProp="children"
style={{width: '80%', marginRight: 10}}
style={{width: '80%', marginRight: 10, marginBottom: 12}}
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
onChange={v => store.editHost(index, v)}>
{hostStore.records.filter(x => hasHostPermission(x.id)).map(item => (
@ -42,14 +43,14 @@ class Ext2Setup2 extends React.Component {
))}
</Select>
{!store.isReadOnly && info['host_ids'].length > 1 && (
<Icon className={styles.delIcon} type="minus-circle-o" onClick={() => store.delHost(index)}/>
<MinusCircleOutlined className={styles.delIcon} onClick={() => store.delHost(index)} />
)}
</React.Fragment>
))}
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button disabled={store.isReadOnly} type="dashed" style={{width: '80%'}} onClick={store.addHost}>
<Icon type="plus"/>添加目标主机
<PlusOutlined />添加目标主机
</Button>
</Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}>

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Input, Button, message, Divider, Alert, Icon, Select } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Form, Input, Button, message, Divider, Alert, Select } from 'antd';
import Editor from 'react-ace';
import 'ace-builds/src-noconflict/mode-sh';
import 'ace-builds/src-noconflict/theme-tomorrow';
@ -81,7 +82,7 @@ class Ext2Setup3 extends React.Component {
</Form.Item>
{!store.isReadOnly && (
<div className={styles.delAction} onClick={() => server_actions.splice(index, 1)}>
<Icon type="minus-circle"/>移除
<MinusCircleOutlined />移除
</div>
)}
</div>
@ -89,7 +90,7 @@ class Ext2Setup3 extends React.Component {
{!store.isReadOnly && (
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button type="dashed" block onClick={() => server_actions.push({})}>
<Icon type="plus"/>添加本地执行动作在服务端本地执行
<PlusOutlined />添加本地执行动作在服务端本地执行
</Button>
</Form.Item>
)}
@ -159,7 +160,7 @@ class Ext2Setup3 extends React.Component {
)}
{!store.isReadOnly && (
<div className={styles.delAction} onClick={() => host_actions.splice(index, 1)}>
<Icon type="minus-circle"/>移除
<MinusCircleOutlined />移除
</div>
)}
</div>
@ -167,14 +168,15 @@ class Ext2Setup3 extends React.Component {
{!store.isReadOnly && (
<Form.Item wrapperCol={{span: 14, offset: 6}}>
<Button disabled={store.isReadOnly} type="dashed" block onClick={() => host_actions.push({})}>
<Icon type="plus"/>添加目标主机执行动作在部署目标主机执行
<PlusOutlined />添加目标主机执行动作在部署目标主机执行
</Button>
<Button
block
type="dashed"
style={{marginTop: 8}}
disabled={store.isReadOnly || lds.findIndex(host_actions, x => x.type === 'transfer') !== -1}
onClick={() => host_actions.push({type: 'transfer', title: '数据传输', mode: '0', src_mode: '0'})}>
<Icon type="plus"/>添加数据传输动作仅能添加一个
<PlusOutlined />添加数据传输动作仅能添加一个
</Button>
</Form.Item>
)}

View File

@ -3,65 +3,48 @@
* Copyright (c) <spug.dev@gmail.com>
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import React, { useState } from 'react';
import { observer } from 'mobx-react';
import { Modal, Form, Input, message } from 'antd';
import http from 'libs/http';
import store from './store';
@observer
class ComForm extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
}
}
export default observer(function () {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
handleSubmit = () => {
this.setState({loading: true});
const formData = this.props.form.getFieldsValue();
function handleSubmit() {
setLoading(true);
const formData = form.getFieldsValue();
formData['id'] = store.record.id;
http.post('/api/app/', formData)
.then(res => {
message.success('操作成功');
store.formVisible = false;
store.fetchRecords()
}, () => this.setState({loading: false}))
};
render() {
const info = store.record;
const {getFieldDecorator} = this.props.form;
return (
<Modal
visible
width={800}
maskClosable={false}
title={store.record.id ? '编辑应用' : '新建应用'}
onCancel={() => store.formVisible = false}
confirmLoading={this.state.loading}
onOk={this.handleSubmit}>
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
<Form.Item required label="应用名称">
{getFieldDecorator('name', {initialValue: info['name']})(
<Input placeholder="请输入应用名称,例如:订单服务"/>
)}
</Form.Item>
<Form.Item required label="唯一标识符">
{getFieldDecorator('key', {initialValue: info['key']})(
<Input placeholder="请输入唯一标识符例如api_order"/>
)}
</Form.Item>
<Form.Item label="备注信息">
{getFieldDecorator('desc', {initialValue: info['desc']})(
<Input.TextArea placeholder="请输入备注信息"/>
)}
</Form.Item>
</Form>
</Modal>
)
}, () => setLoading(false))
}
}
export default Form.create()(ComForm)
return (
<Modal
visible
width={800}
maskClosable={false}
title={store.record.id ? '编辑应用' : '新建应用'}
onCancel={() => store.formVisible = false}
confirmLoading={loading}
onOk={handleSubmit}>
<Form form={form} initialValues={store.record} labelCol={{span: 6}} wrapperCol={{span: 14}}>
<Form.Item required name="name" label="应用名称">
<Input placeholder="请输入应用名称,例如:订单服务"/>
</Form.Item>
<Form.Item required name="key" label="唯一标识符">
<Input placeholder="请输入唯一标识符例如api_order"/>
</Form.Item>
<Form.Item name="desc" label="备注信息">
<Input.TextArea placeholder="请输入备注信息"/>
</Form.Item>
</Form>
</Modal>
)
})

View File

@ -4,12 +4,19 @@
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import { toJS } from 'mobx';
import { observer } from 'mobx-react';
import { Table, Modal, Tag, Icon, Divider, message } from 'antd';
import {
BuildOutlined,
DownSquareOutlined,
ExclamationCircleOutlined,
OrderedListOutlined,
UpSquareOutlined,
PlusOutlined
} from '@ant-design/icons';
import { Table, Modal, Tag, Divider, message } from 'antd';
import { http, hasPermission } from 'libs';
import store from './store';
import { Action } from "components";
import { Action, TableCard, AuthButton } from "components";
import CloneConfirm from './CloneConfirm';
import envStore from 'pages/config/environment/store';
import lds from 'lodash';
@ -32,7 +39,7 @@ class ComTable extends React.Component {
e.stopPropagation();
this.cloneObj = null;
Modal.confirm({
icon: 'exclamation-circle',
icon: <ExclamationCircleOutlined/>,
title: '选择克隆对象',
content: <CloneConfirm onChange={v => this.cloneObj = v[1]}/>,
onOk: () => {
@ -88,49 +95,51 @@ class ComTable extends React.Component {
store.loadDeploys(record.id)
}
return <Table
rowKey="id"
loading={record['deploys'] === undefined}
dataSource={record['deploys']}
pagination={false}>
<Table.Column width={80} title="模式" dataIndex="extend" render={value => value === '1' ?
<Icon style={{fontSize: 20, color: '#1890ff'}} type="ordered-list"/> :
<Icon style={{fontSize: 20, color: '#1890ff'}} type="build"/>}/>
<Table.Column title="发布环境" dataIndex="env_id" render={value => lds.get(envStore.idMap, `${value}.name`)}/>
<Table.Column title="关联主机" dataIndex="host_ids" render={value => `${value.length}`}/>
<Table.Column title="发布审核" dataIndex="is_audit"
render={value => value ? <Tag color="green">开启</Tag> : <Tag color="red"></Tag>}/>
{hasPermission('deploy.app.config|deploy.app.edit') && (
<Table.Column title="操作" render={info => (
<Action>
<Action.Button
auth="deploy.app.config"
onClick={e => store.showExtForm(e, record.id, info, false, true)}>查看</Action.Button>
<Action.Button auth="deploy.app.edit"
onClick={e => store.showExtForm(e, record.id, info)}>编辑</Action.Button>
<Action.Button auth="deploy.app.edit" onClick={() => this.handleDeployDelete(info)}>删除</Action.Button>
</Action>
)}/>
)}
</Table>
};
render() {
let data = Object.values(toJS(store.records));
if (store.f_name) {
data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase()))
}
if (store.f_desc) {
data = data.filter(item => item['desc'] && item['desc'].toLowerCase().includes(store.f_desc.toLowerCase()))
}
return (
<Table
rowKey="id"
expandRowByClick
loading={record['deploys'] === undefined}
dataSource={record['deploys']}
pagination={false}>
<Table.Column width={80} title="模式" dataIndex="extend" render={value => value === '1' ?
<OrderedListOutlined style={{fontSize: 20, color: '#1890ff'}}/> :
<BuildOutlined style={{fontSize: 20, color: '#1890ff'}}/>}/>
<Table.Column title="发布环境" dataIndex="env_id" render={value => lds.get(envStore.idMap, `${value}.name`)}/>
<Table.Column title="关联主机" dataIndex="host_ids" render={value => `${value.length}`}/>
<Table.Column title="发布审核" dataIndex="is_audit"
render={value => value ? <Tag color="green">开启</Tag> : <Tag color="red"></Tag>}/>
{hasPermission('deploy.app.config|deploy.app.edit') && (
<Table.Column title="操作" render={info => (
<Action>
<Action.Button
auth="deploy.app.config"
onClick={e => store.showExtForm(e, record.id, info, false, true)}>查看</Action.Button>
<Action.Button auth="deploy.app.edit"
onClick={e => store.showExtForm(e, record.id, info)}>编辑</Action.Button>
<Action.Button auth="deploy.app.edit" onClick={() => this.handleDeployDelete(info)}>删除</Action.Button>
</Action>
)}/>
)}
</Table>
)
};
render() {
return (
<TableCard
title="应用列表"
rowKey="id"
loading={store.isFetching}
dataSource={data}
expandedRowRender={this.expandedRowRender}
dataSource={store.dataSource}
expandable={{expandRowByClick: true, expandedRowRender: this.expandedRowRender}}
onReload={store.fetchRecords}
actions={[
<AuthButton
auth="deploy.app.add"
type="primary"
icon={<PlusOutlined/>}
onClick={() => store.showForm()}>新建</AuthButton>
]}
pagination={{
showSizeChanger: true,
showLessItems: true,
@ -140,11 +149,13 @@ class ComTable extends React.Component {
}}>
<Table.Column width={80} title="排序" key="series" render={(info) => (
<div>
<Icon onClick={e => this.handleSort(e, info, 'up')} type="up-square"
style={{cursor: 'pointer', color: '#1890ff'}}/>
<UpSquareOutlined
onClick={e => this.handleSort(e, info, 'up')}
style={{cursor: 'pointer', color: '#1890ff'}}/>
<Divider type="vertical"/>
<Icon onClick={e => this.handleSort(e, info, 'down')} type="down-square"
style={{cursor: 'pointer', color: '#1890ff'}}/>
<DownSquareOutlined
onClick={e => this.handleSort(e, info, 'down')}
style={{cursor: 'pointer', color: '#1890ff'}}/>
</div>
)}/>
<Table.Column title="应用名称" dataIndex="name"/>
@ -160,7 +171,7 @@ class ComTable extends React.Component {
</Action>
)}/>
)}
</Table>
</TableCard>
)
}
}

View File

@ -5,8 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Input, Button } from 'antd';
import { SearchForm, AuthDiv, AuthCard } from 'components';
import { Input } from 'antd';
import { SearchForm, AuthDiv, Breadcrumb } from 'components';
import ComTable from './Table';
import ComForm from './Form';
import Ext1Form from './Ext1Form';
@ -16,26 +16,25 @@ import store from './store';
export default observer(function () {
return (
<AuthCard auth="deploy.app.view">
<AuthDiv auth="deploy.app.view">
<Breadcrumb>
<Breadcrumb.Item>首页</Breadcrumb.Item>
<Breadcrumb.Item>应用发布</Breadcrumb.Item>
<Breadcrumb.Item>应用管理</Breadcrumb.Item>
</Breadcrumb>
<SearchForm>
<SearchForm.Item span={6} title="应用名称">
<SearchForm.Item span={7} title="应用名称">
<Input allowClear value={store.f_name} onChange={e => store.f_name = e.target.value} placeholder="请输入"/>
</SearchForm.Item>
<SearchForm.Item span={6} title="描述信息">
<SearchForm.Item span={7} title="描述信息">
<Input allowClear value={store.f_desc} onChange={e => store.f_desc = e.target.value} placeholder="请输入"/>
</SearchForm.Item>
<SearchForm.Item span={8}>
<Button type="primary" icon="sync" onClick={store.fetchRecords}>刷新</Button>
</SearchForm.Item>
</SearchForm>
<AuthDiv auth="deploy.app.add" style={{marginBottom: 16}}>
<Button type="primary" icon="plus" onClick={() => store.showForm()}>新建</Button>
</AuthDiv>
<ComTable/>
{store.formVisible && <ComForm />}
{store.addVisible && <AddSelect />}
{store.ext1Visible && <Ext1Form />}
{store.ext2Visible && <Ext2Form />}
</AuthCard>
)
</AuthDiv>
);
})

View File

@ -3,7 +3,7 @@
* Copyright (c) <spug.dev@gmail.com>
* Released under the AGPL-3.0 License.
*/
import { observable, computed } from "mobx";
import { observable, computed, toJS } from 'mobx';
import http from 'libs/http';
class Store {
@ -22,6 +22,13 @@ class Store {
@observable f_name;
@observable f_desc;
@computed get dataSource() {
let records = Object.values(toJS(this.records));
if (this.f_name) records = records.filter(x => x.name.toLowerCase().includes(this.f_name.toLowerCase()));
if (this.f_desc) records = records.filter(x => x.desc && x.desc.toLowerCase().includes(this.f_desc.toLowerCase()));
return records
}
@computed get currentRecord() {
return this.records[`a${this.app_id}`]
}