diff --git a/spug_web/src/pages/deploy/app/index.js b/spug_web/src/pages/deploy/app/index.js index 65e4e45..3c66ebc 100644 --- a/spug_web/src/pages/deploy/app/index.js +++ b/spug_web/src/pages/deploy/app/index.js @@ -18,10 +18,10 @@ export default observer(function () { return ( - 首页 - 应用发布 - 应用管理 - + 首页 + 应用发布 + 应用管理 + store.f_name = e.target.value} placeholder="请输入"/> @@ -31,10 +31,10 @@ export default observer(function () { - {store.formVisible && } - {store.addVisible && } - {store.ext1Visible && } - {store.ext2Visible && } + {store.formVisible && } + {store.addVisible && } + {store.ext1Visible && } + {store.ext2Visible && } ); }) diff --git a/spug_web/src/pages/deploy/do/Ext1Index.js b/spug_web/src/pages/deploy/do/Ext1Index.js index e997a98..2ba051b 100644 --- a/spug_web/src/pages/deploy/do/Ext1Index.js +++ b/spug_web/src/pages/deploy/do/Ext1Index.js @@ -5,7 +5,8 @@ */ import React from 'react'; import { observer } from 'mobx-react'; -import { Steps, Collapse, PageHeader, Spin, Tag, Button, Icon } from 'antd'; +import { CaretRightOutlined, LoadingOutlined, PlayCircleOutlined, SyncOutlined } from '@ant-design/icons'; +import { Steps, Collapse, PageHeader, Spin, Tag, Button } from 'antd'; import { http, history, X_TOKEN } from 'libs'; import { AuthDiv } from 'components'; import OutView from './OutView'; @@ -96,7 +97,7 @@ class Ext1Index extends React.Component { getStatus = (key, n) => { const step = lds.get(store.outputs, `${key}.step`, -1); const isError = lds.get(store.outputs, `${key}.status`) === 'error'; - const icon = ; + const icon = ; if (n > step) { return {key: n, status: 'wait'} } else if (n === step) { @@ -112,12 +113,12 @@ class Ext1Index extends React.Component { if (lds.get(store.outputs, `${item.id}.status`) === 'error') { return 发布异常 } else if (lds.get(store.outputs, `${item.id}.step`, -1) < 5) { - return 发布中 + return 发布中 } } return 发布成功 } else { - return {store.request['status_alias'] || '...'} + return {store.request['status_alias'] || '...'} } }; @@ -132,9 +133,9 @@ class Ext1Index extends React.Component { style={{padding: 0}} tags={this.getStatusAlias()} extra={this.log ? ( - + ) : ( - )} @@ -156,7 +157,7 @@ class Ext1Index extends React.Component { }> + expandIcon={({isActive}) => }> {store.request.targets.map((item, index) => ( diff --git a/spug_web/src/pages/deploy/do/Ext2Index.js b/spug_web/src/pages/deploy/do/Ext2Index.js index cf984fd..481d634 100644 --- a/spug_web/src/pages/deploy/do/Ext2Index.js +++ b/spug_web/src/pages/deploy/do/Ext2Index.js @@ -5,7 +5,8 @@ */ import React from 'react'; import { observer } from 'mobx-react'; -import { Steps, Collapse, PageHeader, Spin, Tag, Button, Icon } from 'antd'; +import { CaretRightOutlined, LoadingOutlined, PlayCircleOutlined, SyncOutlined } from '@ant-design/icons'; +import { Steps, Collapse, PageHeader, Spin, Tag, Button } from 'antd'; import { http, history, X_TOKEN } from 'libs'; import { AuthDiv } from 'components'; import OutView from './OutView'; @@ -97,7 +98,7 @@ class Ext1Index extends React.Component { getStatus = (key, n) => { const step = lds.get(store.outputs, `${key}.step`, -1); const isError = lds.get(store.outputs, `${key}.status`) === 'error'; - const icon = ; + const icon = ; if (n > step) { return {key: n, status: 'wait'} } else if (n === step) { @@ -114,12 +115,12 @@ class Ext1Index extends React.Component { if (lds.get(store.outputs, `${item.id}.status`) === 'error') { return 发布异常 } else if (lds.get(store.outputs, `${item.id}.step`, -1) < 100) { - return 发布中 + return 发布中 } } return 发布成功 } else { - return {store.request['status_alias'] || '...'} + return {store.request['status_alias'] || '...'} } }; @@ -134,9 +135,9 @@ class Ext1Index extends React.Component { style={{padding: 0}} tags={this.getStatusAlias()} extra={this.log ? ( - + ) : ( - )} @@ -158,7 +159,7 @@ class Ext1Index extends React.Component { }> + expandIcon={({isActive}) => }> {store.request.targets.map((item, index) => ( diff --git a/spug_web/src/pages/deploy/request/Approve.js b/spug_web/src/pages/deploy/request/Approve.js index b106a62..57d773e 100644 --- a/spug_web/src/pages/deploy/request/Approve.js +++ b/spug_web/src/pages/deploy/request/Approve.js @@ -3,58 +3,50 @@ * Copyright (c) * 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, Switch, message } from 'antd'; import http from 'libs/http'; import store from './store'; -@observer -class Approve extends React.Component { - constructor(props) { - super(props); - this.state = { - loading: false, - } - } +export default observer(function () { + const [form] = Form.useForm(); + const [isPass, setIsPass] = useState(true); + const [loading, setLoading] = useState(false); - handleSubmit = () => { - this.setState({loading: true}); - const formData = this.props.form.getFieldsValue(); + function handleSubmit() { + setLoading(true); + const formData = form.getFieldsValue(); http.patch(`/api/deploy/request/${store.record.id}/`, formData) .then(res => { message.success('操作成功'); store.approveVisible = false; store.fetchRecords() - }, () => this.setState({loading: false})) - }; - - render() { - const {getFieldDecorator, getFieldValue} = this.props.form; - return ( - store.approveVisible = false} - confirmLoading={this.state.loading} - onOk={this.handleSubmit}> -
- - {getFieldDecorator('is_pass', {initialValue: true, valuePropName: "checked"})( - - )} - - - {getFieldDecorator('reason')( - - )} - -
-
- ) + }, () => setLoading(false)) } -} -export default Form.create()(Approve) + function handleChange(val) { + if (val.is_pass !== undefined) { + setIsPass(val.is_pass) + } + } + return ( + store.approveVisible = false} + confirmLoading={loading} + onOk={handleSubmit}> +
+ + + + + + +
+
+ ) +}) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/Ext1Form.js b/spug_web/src/pages/deploy/request/Ext1Form.js index 0fc0cdd..ce4071c 100644 --- a/spug_web/src/pages/deploy/request/Ext1Form.js +++ b/spug_web/src/pages/deploy/request/Ext1Form.js @@ -3,47 +3,59 @@ * Copyright (c) * Released under the AGPL-3.0 License. */ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { observer } from 'mobx-react'; -import { Modal, Form, Input, Select, Col, Button, Tag, Icon, message } from 'antd'; +import { LoadingOutlined, SyncOutlined } from '@ant-design/icons'; +import { Modal, Form, Input, Select, Button, Tag, message } from 'antd'; import hostStore from 'pages/host/store'; import http from 'libs/http'; import store from './store'; import lds from 'lodash'; -@observer -class Ext1Form extends React.Component { - constructor(props) { - super(props); - this.isReady = false; - this.state = { - loading: false, - fetching: true, - git_type: lds.get(store.record, 'extra.0', 'branch'), - extra1: lds.get(store.record, 'extra.1'), - extra2: lds.get(store.record, 'extra.2'), - versions: {}, - host_ids: store.record['app_host_ids'].concat() - } - } +export default observer(function () { + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [fetching, setFetching] = useState(true); + const [git_type, setGitType] = useState(lds.get(store.record, 'extra.0', 'branch')); + const [extra1, setExtra1] = useState(lds.get(store.record, 'extra.1')); + const [extra2, setExtra2] = useState(lds.get(store.record, 'extra.2')); + const [versions, setVersions] = useState({}); + const [host_ids, setHostIds] = useState(lds.clone(store.record.app_host_ids)); - componentDidMount() { - this.fetchVersions(); + useEffect(() => { + fetchVersions(); if (hostStore.records.length === 0) { hostStore.fetchRecords() } + }, []) + + useEffect(() => { + if (extra1 === undefined) { + const {branches, tags} = versions; + let [extra1, extra2] = [undefined, undefined]; + if (git_type === 'branch') { + if (branches) { + extra1 = _getDefaultBranch(branches); + extra2 = lds.get(branches[extra1], '0.id') + } + } else { + if (tags) { + extra1 = lds.get(Object.keys(tags), 0) + } + } + setExtra1(extra1) + setExtra2(extra2) + } + }, [versions, git_type, extra1]) + + function fetchVersions() { + setFetching(true); + http.get(`/api/app/deploy/${store.record.deploy_id}/versions/`, {timeout: 120000}) + .then(res => setVersions(res)) + .finally(() => setFetching(false)) } - fetchVersions = () => { - this.setState({fetching: true}); - http.get(`/api/app/deploy/${store.record.deploy_id}/versions/`, {timeout: 120000}) - .then(res => { - this.setState({versions: res}, this._initExtra1); - }) - .finally(() => this.setState({fetching: false})) - }; - - _getDefaultBranch = (branches) => { + function _getDefaultBranch(branches) { branches = Object.keys(branches); let branch = branches[0]; for (let item of store.records) { @@ -56,149 +68,117 @@ class Ext1Form extends React.Component { } } return branch - }; + } - _initExtra1 = () => { - if (this.isReady === true || this.state.extra1 === undefined) { - const {git_type, versions: {branches, tags}} = this.state; - let [extra1, extra2] = [undefined, undefined]; - if (git_type === 'branch') { - if (branches) { - extra1 = this._getDefaultBranch(branches); - extra2 = lds.get(branches[extra1], '0.id') - } - } else { - if (tags) { - extra1 = lds.get(Object.keys(tags), 0) - } - } - this.setState({extra1, extra2}) - } else { - this.isReady = true - } - }; + function switchType(v) { + setExtra1(undefined); + setGitType(v) + } - switchType = (v) => { - this.setState({git_type: v, extra1: undefined}, this._initExtra1) - }; - - switchExtra1 = (v) => { - let {git_type, extra2, versions: {branches}} = this.state; + function switchExtra1(v) { + setExtra1(v) if (git_type === 'branch') { - extra2 = lds.get(branches[v], '0.id') + setExtra2(lds.get(versions.branches[v], '0.id')) } - this.setState({extra1: v, extra2}) - }; + } - handleSubmit = () => { - if (this.state.host_ids.length === 0) { + function handleSubmit() { + if (host_ids.length === 0) { return message.error('请至少选择一个要发布的目标主机') } - this.setState({loading: true}); - const {git_type, extra1, extra2} = this.state; - const formData = this.props.form.getFieldsValue(); + setLoading(true); + const formData = form.getFieldsValue(); formData['id'] = store.record.id; formData['deploy_id'] = store.record.deploy_id; - formData['host_ids'] = this.state.host_ids; + formData['host_ids'] = host_ids; formData['extra'] = [git_type, extra1, extra2]; http.post('/api/deploy/request/', formData) .then(res => { message.success('操作成功'); store.ext1Visible = false; store.fetchRecords() - }, () => this.setState({loading: false})) - }; + }, () => setLoading(false)) + } - handleChange = (id) => { - const host_ids = this.state.host_ids; + function handleChange(id) { const index = host_ids.indexOf(id); if (index === -1) { - this.setState({host_ids: [id, ...host_ids]}) + setHostIds([id, ...host_ids]) } else { host_ids.splice(index, 1); - this.setState({host_ids}) + setHostIds(host_ids) } - }; + } - render() { - const info = store.record; - const {host_ids, git_type, extra1, extra2, fetching, versions: {branches, tags}} = this.state; - const {getFieldDecorator} = this.props.form; - return ( - store.ext1Visible = false} - confirmLoading={this.state.loading} - onOk={this.handleSubmit}> -
- - {getFieldDecorator('name', {initialValue: info['name']})( - - )} - - + const {branches, tags} = versions; + return ( + store.ext1Visible = false} + confirmLoading={loading} + onOk={handleSubmit}> + + + + + 根据网络情况,首次刷新可能会很慢,请耐心等待。 clone 失败? }> - - - - - - - - {fetching ? : - - } - - - {git_type === 'branch' && ( - - + Branch + Tag - - )} - - {getFieldDecorator('desc', {initialValue: info['desc']})( - - )} + + - - {info['app_host_ids'].map(id => ( - this.handleChange(id)}> - {lds.get(hostStore.idMap, `${id}.name`)}({lds.get(hostStore.idMap, `${id}.hostname`)}:{lds.get(hostStore.idMap, `${id}.port`)}) - - ))} + + {fetching ? : + + } - - - ) - } -} - -export default Form.create()(Ext1Form) +
+ {git_type === 'branch' && ( + + + + )} + + + + + {store.record['app_host_ids'].map(id => ( + handleChange(id)}> + {lds.get(hostStore.idMap, `${id}.name`)}({lds.get(hostStore.idMap, `${id}.hostname`)}:{lds.get(hostStore.idMap, `${id}.port`)}) + + ))} + + +
+ ) +}) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/SelectApp.js b/spug_web/src/pages/deploy/request/SelectApp.js index 1534b0c..dfa95d6 100644 --- a/spug_web/src/pages/deploy/request/SelectApp.js +++ b/spug_web/src/pages/deploy/request/SelectApp.js @@ -6,7 +6,8 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { observer } from 'mobx-react'; -import { Modal, Button, Menu, Spin, Icon, Input, Tooltip } from 'antd'; +import { Modal, Button, Menu, Spin, Input, Tooltip } from 'antd'; +import { OrderedListOutlined, BuildOutlined } from '@ant-design/icons'; import store from './store'; import styles from './index.module.css'; import envStore from 'pages/config/environment/store'; @@ -100,8 +101,8 @@ class SelectApp extends React.Component { diff --git a/spug_web/src/pages/deploy/request/Table.js b/spug_web/src/pages/deploy/request/Table.js index 0d18619..1556b15 100644 --- a/spug_web/src/pages/deploy/request/Table.js +++ b/spug_web/src/pages/deploy/request/Table.js @@ -5,9 +5,10 @@ */ import React from 'react'; import { observer } from 'mobx-react'; -import { Table, Modal, Icon, Popover, Tag, message } from 'antd'; +import { BranchesOutlined, BuildOutlined, TagOutlined, PlusOutlined } from '@ant-design/icons'; +import { Radio, Modal, Popover, Tag, message } from 'antd'; import { http, hasPermission } from 'libs'; -import { Action } from "components"; +import { Action, AuthButton, TableCard } from 'components'; import store from './store'; @observer @@ -25,7 +26,12 @@ class ComTable extends React.Component { columns = [{ title: '申请标题', - dataIndex: 'name', + render: info => ( +
+ {info.type === '2' && R} + {info.name} +
+ ) }, { title: '应用', dataIndex: 'app_name', @@ -38,18 +44,24 @@ class ComTable extends React.Component { if (info['app_extend'] === '1') { const [type, ext1, ext2] = info.extra; if (type === 'branch') { - return - {ext1}#{ext2.substr(0, 6)} - + return ( + + {ext1}#{ext2.substr(0, 6)} + + ) } else { - return - {ext1} - + return ( + + {ext1} + + ) } } else { - return - {info.extra[0]} - + return ( + + {info.extra[0]} + + ) } } }, { @@ -64,13 +76,13 @@ class ComTable extends React.Component { {info['status_alias']} } else if (info.status === '2') { - return {info['status_alias']} + return {info['status_alias']} } else if (info.status === '3') { return {info['status_alias']} } else if (info.status === '-3') { return {info['status_alias']} } else { - return {info['status_alias']} + return {info['status_alias']} } } }, { @@ -80,6 +92,11 @@ class ComTable extends React.Component { title: '申请时间', dataIndex: 'created_at', sorter: (a, b) => a['created_at'].localeCompare(b['created_at']) + }, { + title: '备注', + dataIndex: 'desc', + ellipsis: true, + hide: true }, { title: '操作', className: hasPermission('deploy.request.do|deploy.request.edit|deploy.request.approve|deploy.request.del') ? null : 'none', @@ -191,10 +208,27 @@ class ComTable extends React.Component { } } return ( - } + onClick={() => store.addVisible = true}>新建申请, + store.f_status = e.target.value}> + 全部({store.counter['all'] || 0}) + 待审核({store.counter['0'] || 0}) + 待发布({store.counter['1'] || 0}) + 发布成功({store.counter['3'] || 0}) + 发布异常({store.counter['-3'] || 0}) + 其他({store.counter['99'] || 0}) + + ]} pagination={{ showSizeChanger: true, showLessItems: true, diff --git a/spug_web/src/pages/deploy/request/index.js b/spug_web/src/pages/deploy/request/index.js index 5e121ff..75d46ae 100644 --- a/spug_web/src/pages/deploy/request/index.js +++ b/spug_web/src/pages/deploy/request/index.js @@ -5,8 +5,9 @@ */ import React from 'react'; import { observer } from 'mobx-react'; -import { Button, Select, DatePicker, Radio, Row, Col, Modal, Form, Input, message } from 'antd'; -import { SearchForm, AuthFragment, AuthCard } from 'components'; +import { ExclamationCircleOutlined, DeleteOutlined } from '@ant-design/icons'; +import { Form, Select, DatePicker, Modal, Input, message } from 'antd'; +import { SearchForm, AuthDiv, AuthButton, Breadcrumb } from 'components'; import SelectApp from './SelectApp'; import Ext1Form from './Ext1Form'; import Ext2Form from './Ext2Form'; @@ -39,15 +40,15 @@ class Index extends React.Component { handleBatchDel = () => { Modal.confirm({ - icon: 'exclamation-circle', + icon: , title: '批量删除发布申请', content: ( -
- 将删除截止日期之前的所有发布申请记录。}> + + 将删除截止日期之前的所有发布申请记录。}> this.setState({expire: val.format('YYYY-MM-DD')})}/> - + this.setState({count: e.target.value})}/> @@ -66,7 +67,12 @@ class Index extends React.Component { render() { return ( - + + + 首页 + 应用发布 + 发布申请 + store.f_zone = v}> {store.zones.map(item => ( diff --git a/spug_web/src/routes.js b/spug_web/src/routes.js index 9b75b9f..43df8bb 100644 --- a/spug_web/src/routes.js +++ b/spug_web/src/routes.js @@ -16,19 +16,29 @@ import { SettingOutlined } from '@ant-design/icons'; import HomeIndex from './pages/home'; + import HostIndex from './pages/host'; + import ExecTask from './pages/exec/task'; import ExecTemplate from './pages/exec/template'; + import DeployApp from './pages/deploy/app'; import DeployRequest from './pages/deploy/request'; +import DoExt1Index from './pages/deploy/do/Ext1Index'; +import DoExt2Index from './pages/deploy/do/Ext2Index'; + import ScheduleIndex from './pages/schedule'; + import ConfigEnvironment from './pages/config/environment'; import ConfigService from './pages/config/service'; import ConfigApp from './pages/config/app'; + import MonitorIndex from './pages/monitor'; + import AlarmIndex from './pages/alarm/alarm'; import AlarmGroup from './pages/alarm/group'; import AlarmContact from './pages/alarm/contact'; + import SystemAccount from './pages/system/account'; import SystemRole from './pages/system/role'; import SystemSetting from './pages/system/setting'; @@ -49,6 +59,10 @@ export default [ icon: , title: '应用发布', auth: 'deploy.app.view|deploy.request.view', child: [ {title: '应用管理', auth: 'deploy.app.view', path: '/deploy/app', component: DeployApp}, {title: '发布申请', auth: 'deploy.request.view', path: '/deploy/request', component: DeployRequest}, + {path: '/deploy/do/ext1/:id', component: DoExt1Index}, + {path: '/deploy/do/ext2/:id', component: DoExt2Index}, + {path: '/deploy/do/ext1/:id/:log', component: DoExt1Index}, + {path: '/deploy/do/ext2/:id/:log', component: DoExt2Index}, ] }, {