update host edit

pull/289/head
vapao 2020-12-18 19:54:35 +08:00
parent 591a4d1659
commit 8917b1fe76
8 changed files with 53 additions and 18 deletions

View File

@ -20,6 +20,7 @@ def fetch_children(data):
def merge_children(data, prefix, childes): def merge_children(data, prefix, childes):
for item in childes: for item in childes:
name = f'{prefix}/{item["title"]}' name = f'{prefix}/{item["title"]}'
item['name'] = name
if item['children']: if item['children']:
merge_children(data, name, item['children']) merge_children(data, name, item['children'])
else: else:
@ -36,8 +37,9 @@ class GroupView(View):
grp = Group.objects.create(name='Default', sort_id=1) grp = Group.objects.create(name='Default', sort_id=1)
data[grp.id] = grp.to_view() data[grp.id] = grp.to_view()
merge_children(data2, '', data.values()) data = list(data.values())
return json_response({'treeData': list(data.values()), 'groups': data2}) merge_children(data2, '', data)
return json_response({'treeData': data, 'groups': data2})
def post(self, request): def post(self, request):
form, error = JsonParser( form, error = JsonParser(

View File

@ -10,7 +10,6 @@ from libs.ssh import SSH
class Host(models.Model, ModelMixin): class Host(models.Model, ModelMixin):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
zone = models.CharField(max_length=50)
hostname = models.CharField(max_length=50) hostname = models.CharField(max_length=50)
port = models.IntegerField() port = models.IntegerField()
username = models.CharField(max_length=50) username = models.CharField(max_length=50)
@ -52,6 +51,7 @@ class Group(models.Model, ModelMixin):
def to_view(self): def to_view(self):
return { return {
'key': self.id, 'key': self.id,
'value': self.id,
'title': self.name, 'title': self.name,
'children': [] 'children': []
} }

View File

@ -33,7 +33,7 @@ class HostView(View):
def post(self, request): def post(self, request):
form, error = JsonParser( form, error = JsonParser(
Argument('id', type=int, required=False), Argument('id', type=int, required=False),
Argument('zone', help='请输入主机类型'), Argument('group_ids', type=list, filter=lambda x: len(x), help='请选择主机分组'),
Argument('name', help='请输主机名称'), Argument('name', help='请输主机名称'),
Argument('username', handler=str.strip, help='请输入登录用户名'), Argument('username', handler=str.strip, help='请输入登录用户名'),
Argument('hostname', handler=str.strip, help='请输入主机名或IP'), Argument('hostname', handler=str.strip, help='请输入主机名或IP'),
@ -47,14 +47,16 @@ class HostView(View):
pkey=form.pkey) is False: pkey=form.pkey) is False:
return json_response('auth fail') return json_response('auth fail')
if form.id: group_ids = form.pop('group_ids')
Host.objects.filter(pk=form.pop('id')).update(**form) other = Host.objects.filter(name=form.name, deleted_by_id__isnull=True).first()
elif Host.objects.filter(name=form.name, deleted_by_id__isnull=True).exists(): if other and (not form.id or other.id != form.id):
return json_response(error=f'已存在的主机名称【{form.name}') return json_response(error=f'已存在的主机名称【{form.name}')
if form.id:
Host.objects.filter(pk=form.id).update(**form)
host = Host.objects.get(pk=form.id)
else: else:
host = Host.objects.create(created_by=request.user, **form) host = Host.objects.create(created_by=request.user, **form)
if request.user.role: host.groups.set(group_ids)
request.user.role.add_host_perm(host.id)
return json_response(error=error) return json_response(error=error)
def patch(self, request): def patch(self, request):

View File

@ -0,0 +1,17 @@
import React from 'react';
import { observer } from 'mobx-react';
import { Drawer} from 'antd';
import store from './store';
export default observer(function () {
return (
<Drawer
width={500}
title={store.record.name}
placement="right"
onClose={() => store.detailVisible = false}
visible={store.detailVisible}>
</Drawer>
)
})

View File

@ -6,7 +6,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { ExclamationCircleOutlined, UploadOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, UploadOutlined } from '@ant-design/icons';
import { Modal, Form, Input, Select, Button, Upload, message } from 'antd'; import { Modal, Form, Input, TreeSelect, Button, Upload, Alert, message } from 'antd';
import { http, X_TOKEN } from 'libs'; import { http, X_TOKEN } from 'libs';
import store from './store'; import store from './store';
@ -102,12 +102,13 @@ export default observer(function () {
confirmLoading={loading} confirmLoading={loading}
onOk={handleSubmit}> onOk={handleSubmit}>
<Form form={form} labelCol={{span: 6}} wrapperCol={{span: 14}} initialValues={info}> <Form form={form} labelCol={{span: 6}} wrapperCol={{span: 14}} initialValues={info}>
<Form.Item required name="zone" label="主机类别"> <Form.Item required name="group_ids" label="主机分组">
<Select placeholder="请选择主机类别/区域/分组"> <TreeSelect
{store.zones.map(item => ( multiple
<Select.Option value={item} key={item}>{item}</Select.Option> treeNodeLabelProp="name"
))} treeData={store.treeData}
</Select> showCheckedStrategy={TreeSelect.SHOW_CHILD}
placeholder="请选择分组"/>
</Form.Item> </Form.Item>
<Form.Item required name="name" label="主机名称"> <Form.Item required name="name" label="主机名称">
<Input placeholder="请输入主机名称"/> <Input placeholder="请输入主机名称"/>
@ -133,7 +134,7 @@ export default observer(function () {
<Input.TextArea placeholder="请输入主机备注信息"/> <Input.TextArea placeholder="请输入主机备注信息"/>
</Form.Item> </Form.Item>
<Form.Item wrapperCol={{span: 14, offset: 6}}> <Form.Item wrapperCol={{span: 14, offset: 6}}>
<span role="img" aria-label="notice"> 首次验证时需要输入登录用户名对应的密码但不会存储该密码</span> <Alert showIcon type="info" message="首次验证时需要输入登录用户名对应的密码,该密码会用于配置密钥连接,不会存储该密码。" />
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>

View File

@ -62,7 +62,11 @@ class ComTable extends React.Component {
showTotal: total => `${total}`, showTotal: total => `${total}`,
pageSizeOptions: ['10', '20', '50', '100'] pageSizeOptions: ['10', '20', '50', '100']
}}> }}>
<Table.Column showSorterTooltip={false} title="主机名称" dataIndex="name" sorter={(a, b) => a.name.localeCompare(b.name)}/> <Table.Column
showSorterTooltip={false}
title="主机名称"
render={info => <Action.Button onClick={() => store.showDetail(info)}>{info.name}</Action.Button>}
sorter={(a, b) => a.name.localeCompare(b.name)}/>
<Table.Column title="连接地址" dataIndex="hostname" sorter={(a, b) => a.name.localeCompare(b.name)}/> <Table.Column title="连接地址" dataIndex="hostname" sorter={(a, b) => a.name.localeCompare(b.name)}/>
<Table.Column hide width={100} title="端口" dataIndex="port"/> <Table.Column hide width={100} title="端口" dataIndex="port"/>
<Table.Column hide ellipsis title="备注信息" dataIndex="desc"/> <Table.Column hide ellipsis title="备注信息" dataIndex="desc"/>

View File

@ -11,6 +11,7 @@ import Group from './Group';
import ComTable from './Table'; import ComTable from './Table';
import ComForm from './Form'; import ComForm from './Form';
import ComImport from './Import'; import ComImport from './Import';
import Detail from './Detail';
import store from './store'; import store from './store';
export default observer(function () { export default observer(function () {
@ -30,6 +31,7 @@ export default observer(function () {
</Col> </Col>
</Row> </Row>
<Detail/>
{store.formVisible && <ComForm/>} {store.formVisible && <ComForm/>}
{store.importVisible && <ComImport/>} {store.importVisible && <ComImport/>}
</AuthDiv> </AuthDiv>

View File

@ -17,6 +17,7 @@ class Store {
@observable isFetching = false; @observable isFetching = false;
@observable formVisible = false; @observable formVisible = false;
@observable importVisible = false; @observable importVisible = false;
@observable detailVisible = false;
@observable f_name; @observable f_name;
@observable f_host; @observable f_host;
@ -59,6 +60,11 @@ class Store {
this.record = info this.record = info
} }
showDetail = (info) => {
this.record = info;
this.detailVisible = true;
}
_updateGroupCount = () => { _updateGroupCount = () => {
if (this.treeData.length && this.records.length) { if (this.treeData.length && this.records.length) {
const counter = {}; const counter = {};
@ -83,6 +89,7 @@ class Store {
host_ids = host_ids.concat(this._updateCount(counter, child)) host_ids = host_ids.concat(this._updateCount(counter, child))
} }
item.host_ids = Array.from(new Set(host_ids)); item.host_ids = Array.from(new Set(host_ids));
if (item.key === this.group.key) this.group = item;
return item.host_ids return item.host_ids
} }
} }