mirror of https://github.com/openspug/spug
A 角色管理新增主机权限控制功能
parent
4fdafabbed
commit
0c1336aa88
|
@ -51,6 +51,15 @@ class User(models.Model, ModelMixin):
|
||||||
perms.setdefault('envs', [])
|
perms.setdefault('envs', [])
|
||||||
return perms
|
return perms
|
||||||
|
|
||||||
|
@property
|
||||||
|
def host_perms(self):
|
||||||
|
return json.loads(self.role.host_perms) if self.role.host_perms else []
|
||||||
|
|
||||||
|
def has_host_perm(self, host_id):
|
||||||
|
if isinstance(host_id, (list, set, tuple)):
|
||||||
|
return self.is_supper or set(host_id).issubset(set(self.host_perms))
|
||||||
|
return self.is_supper or int(host_id) in self.host_perms
|
||||||
|
|
||||||
def has_perms(self, codes):
|
def has_perms(self, codes):
|
||||||
# return self.is_supper or self.role in codes
|
# return self.is_supper or self.role in codes
|
||||||
return self.is_supper
|
return self.is_supper
|
||||||
|
@ -68,6 +77,7 @@ class Role(models.Model, ModelMixin):
|
||||||
desc = models.CharField(max_length=255, null=True)
|
desc = models.CharField(max_length=255, null=True)
|
||||||
page_perms = models.TextField(null=True)
|
page_perms = models.TextField(null=True)
|
||||||
deploy_perms = models.TextField(null=True)
|
deploy_perms = models.TextField(null=True)
|
||||||
|
host_perms = models.TextField(null=True)
|
||||||
|
|
||||||
created_at = models.CharField(max_length=20, default=human_datetime)
|
created_at = models.CharField(max_length=20, default=human_datetime)
|
||||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='+')
|
created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='+')
|
||||||
|
@ -76,6 +86,7 @@ class Role(models.Model, ModelMixin):
|
||||||
tmp = super().to_dict(*args, **kwargs)
|
tmp = super().to_dict(*args, **kwargs)
|
||||||
tmp['page_perms'] = json.loads(self.page_perms) if self.page_perms else None
|
tmp['page_perms'] = json.loads(self.page_perms) if self.page_perms else None
|
||||||
tmp['deploy_perms'] = json.loads(self.deploy_perms) if self.deploy_perms else None
|
tmp['deploy_perms'] = json.loads(self.deploy_perms) if self.deploy_perms else None
|
||||||
|
tmp['host_perms'] = json.loads(self.host_perms) if self.host_perms else None
|
||||||
tmp['used'] = self.user_set.count()
|
tmp['used'] = self.user_set.count()
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
@ -85,6 +96,12 @@ class Role(models.Model, ModelMixin):
|
||||||
self.deploy_perms = json.dumps(perms)
|
self.deploy_perms = json.dumps(perms)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def add_host_perm(self, value):
|
||||||
|
perms = json.loads(self.host_perms) if self.host_perms else []
|
||||||
|
perms.append(value)
|
||||||
|
self.host_perms = json.dumps(perms)
|
||||||
|
self.save()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Role name=%r>' % self.name
|
return '<Role name=%r>' % self.name
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@ class RoleView(View):
|
||||||
form, error = JsonParser(
|
form, error = JsonParser(
|
||||||
Argument('id', type=int, help='参数错误'),
|
Argument('id', type=int, help='参数错误'),
|
||||||
Argument('page_perms', type=dict, required=False),
|
Argument('page_perms', type=dict, required=False),
|
||||||
Argument('deploy_perms', type=dict, required=False)
|
Argument('deploy_perms', type=dict, required=False),
|
||||||
|
Argument('host_perms', type=list, required=False)
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
role = Role.objects.filter(pk=form.pop('id')).first()
|
role = Role.objects.filter(pk=form.pop('id')).first()
|
||||||
|
@ -101,6 +102,8 @@ class RoleView(View):
|
||||||
role.page_perms = json.dumps(form.page_perms)
|
role.page_perms = json.dumps(form.page_perms)
|
||||||
if form.deploy_perms is not None:
|
if form.deploy_perms is not None:
|
||||||
role.deploy_perms = json.dumps(form.deploy_perms)
|
role.deploy_perms = json.dumps(form.deploy_perms)
|
||||||
|
if form.host_perms is not None:
|
||||||
|
role.host_perms = json.dumps(form.host_perms)
|
||||||
role.user_set.update(token_expired=0)
|
role.user_set.update(token_expired=0)
|
||||||
role.save()
|
role.save()
|
||||||
return json_response(error=error)
|
return json_response(error=error)
|
||||||
|
|
|
@ -47,6 +47,8 @@ def do_task(request):
|
||||||
Argument('command', help='请输入执行命令内容')
|
Argument('command', help='请输入执行命令内容')
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
if not request.user.has_host_perm(form.host_ids):
|
||||||
|
return json_response(error='无权访问主机,请联系管理员')
|
||||||
token = Channel.get_token()
|
token = Channel.get_token()
|
||||||
for host in Host.objects.filter(id__in=form.host_ids):
|
for host in Host.objects.filter(id__in=form.host_ids):
|
||||||
Channel.send_ssh_executor(
|
Channel.send_ssh_executor(
|
||||||
|
|
|
@ -17,6 +17,8 @@ class FileView(View):
|
||||||
Argument('path', help='参数错误')
|
Argument('path', help='参数错误')
|
||||||
).parse(request.GET)
|
).parse(request.GET)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
if not request.user.has_host_perm(form.id):
|
||||||
|
return json_response(error='无权访问主机,请联系管理员')
|
||||||
host = Host.objects.get(pk=form.id)
|
host = Host.objects.get(pk=form.id)
|
||||||
if not host:
|
if not host:
|
||||||
return json_response(error='未找到指定主机')
|
return json_response(error='未找到指定主机')
|
||||||
|
@ -33,6 +35,8 @@ class ObjectView(View):
|
||||||
Argument('file', help='请输入文件路径')
|
Argument('file', help='请输入文件路径')
|
||||||
).parse(request.GET)
|
).parse(request.GET)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
if not request.user.has_host_perm(form.id):
|
||||||
|
return json_response(error='无权访问主机,请联系管理员')
|
||||||
host = Host.objects.filter(pk=form.id).first()
|
host = Host.objects.filter(pk=form.id).first()
|
||||||
if not host:
|
if not host:
|
||||||
return json_response(error='未找到指定主机')
|
return json_response(error='未找到指定主机')
|
||||||
|
@ -50,6 +54,8 @@ class ObjectView(View):
|
||||||
Argument('path', help='参数错误'),
|
Argument('path', help='参数错误'),
|
||||||
).parse(request.POST)
|
).parse(request.POST)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
if not request.user.has_host_perm(form.id):
|
||||||
|
return json_response(error='无权访问主机,请联系管理员')
|
||||||
file = request.FILES.get('file')
|
file = request.FILES.get('file')
|
||||||
if not file:
|
if not file:
|
||||||
return json_response(error='请选择要上传的文件')
|
return json_response(error='请选择要上传的文件')
|
||||||
|
@ -68,6 +74,8 @@ class ObjectView(View):
|
||||||
Argument('file', help='请输入文件路径')
|
Argument('file', help='请输入文件路径')
|
||||||
).parse(request.GET)
|
).parse(request.GET)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
if not request.user.has_host_perm(form.id):
|
||||||
|
return json_response(error='无权访问主机,请联系管理员')
|
||||||
host = Host.objects.get(pk=form.id)
|
host = Host.objects.get(pk=form.id)
|
||||||
if not host:
|
if not host:
|
||||||
return json_response(error='未找到指定主机')
|
return json_response(error='未找到指定主机')
|
||||||
|
|
|
@ -9,6 +9,7 @@ from apps.host.models import Host
|
||||||
from apps.app.models import Deploy
|
from apps.app.models import Deploy
|
||||||
from apps.schedule.models import Task
|
from apps.schedule.models import Task
|
||||||
from apps.monitor.models import Detection
|
from apps.monitor.models import Detection
|
||||||
|
from apps.account.models import Role
|
||||||
from libs.ssh import SSH, AuthenticationException
|
from libs.ssh import SSH, AuthenticationException
|
||||||
from libs import human_datetime, AttrDict
|
from libs import human_datetime, AttrDict
|
||||||
from openpyxl import load_workbook
|
from openpyxl import load_workbook
|
||||||
|
@ -18,10 +19,13 @@ class HostView(View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
host_id = request.GET.get('id')
|
host_id = request.GET.get('id')
|
||||||
if host_id:
|
if host_id:
|
||||||
|
if int(host_id) not in request.user.host_perms:
|
||||||
|
return json_response(error='无权访问该主机,请联系管理员')
|
||||||
return json_response(Host.objects.get(pk=host_id))
|
return json_response(Host.objects.get(pk=host_id))
|
||||||
hosts = Host.objects.filter(deleted_by_id__isnull=True)
|
hosts = Host.objects.filter(deleted_by_id__isnull=True)
|
||||||
zones = [x['zone'] for x in hosts.order_by('zone').values('zone').distinct()]
|
zones = [x['zone'] for x in hosts.order_by('zone').values('zone').distinct()]
|
||||||
return json_response({'zones': zones, 'hosts': [x.to_dict() for x in hosts]})
|
perms = [x.id for x in hosts] if request.user.is_supper else request.user.host_perms
|
||||||
|
return json_response({'zones': zones, 'hosts': [x.to_dict() for x in hosts], 'perms': perms})
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
form, error = JsonParser(
|
form, error = JsonParser(
|
||||||
|
@ -43,7 +47,9 @@ class HostView(View):
|
||||||
elif Host.objects.filter(name=form.name, deleted_by_id__isnull=True).exists():
|
elif Host.objects.filter(name=form.name, deleted_by_id__isnull=True).exists():
|
||||||
return json_response(error=f'已存在的主机名称【{form.name}】')
|
return json_response(error=f'已存在的主机名称【{form.name}】')
|
||||||
else:
|
else:
|
||||||
Host.objects.create(created_by=request.user, **form)
|
host = Host.objects.create(created_by=request.user, **form)
|
||||||
|
if request.user.role:
|
||||||
|
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):
|
||||||
|
@ -76,6 +82,9 @@ class HostView(View):
|
||||||
detection = Detection.objects.filter(type__in=('3', '4'), addr=form.id).first()
|
detection = Detection.objects.filter(type__in=('3', '4'), addr=form.id).first()
|
||||||
if detection:
|
if detection:
|
||||||
return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
||||||
|
role = Role.objects.filter(host_perms__regex=fr'\D{form.id}\D').first()
|
||||||
|
if role:
|
||||||
|
return json_response(error=f'角色【{role.name}】的主机权限关联了该主机,请解除关联后再尝试删除该主机')
|
||||||
Host.objects.filter(pk=form.id).update(
|
Host.objects.filter(pk=form.id).update(
|
||||||
deleted_at=human_datetime(),
|
deleted_at=human_datetime(),
|
||||||
deleted_by=request.user,
|
deleted_by=request.user,
|
||||||
|
@ -110,7 +119,9 @@ def post_import(request):
|
||||||
if valid_ssh(data.hostname, data.port, data.username, data.pop('password') or password) is False:
|
if valid_ssh(data.hostname, data.port, data.username, data.pop('password') or password) is False:
|
||||||
summary['fail'].append(i)
|
summary['fail'].append(i)
|
||||||
continue
|
continue
|
||||||
Host.objects.create(created_by=request.user, **data)
|
host = Host.objects.create(created_by=request.user, **data)
|
||||||
|
if request.user.role:
|
||||||
|
request.user.role.add_host_perm(host.id)
|
||||||
summary['success'].append(i)
|
summary['success'].append(i)
|
||||||
return json_response(summary)
|
return json_response(summary)
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ class SSHConsumer(WebsocketConsumer):
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
user = User.objects.filter(access_token=self.token).first()
|
user = User.objects.filter(access_token=self.token).first()
|
||||||
if user and user.token_expired >= time.time() and user.is_active:
|
if user and user.token_expired >= time.time() and user.is_active and user.has_host_perm(self.id):
|
||||||
self.accept()
|
self.accept()
|
||||||
self._init()
|
self._init()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -76,7 +76,7 @@ class HostSelector extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {selectedRows} = this.state;
|
const {selectedRows} = this.state;
|
||||||
let data = store.records;
|
let data = store.permRecords;
|
||||||
if (store.f_name) {
|
if (store.f_name) {
|
||||||
data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase()))
|
data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class ComTable extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let data = store.records;
|
let data = store.permRecords;
|
||||||
if (store.f_name) {
|
if (store.f_name) {
|
||||||
data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase()))
|
data = data.filter(item => item['name'].toLowerCase().includes(store.f_name.toLowerCase()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import http from 'libs/http';
|
||||||
class Store {
|
class Store {
|
||||||
@observable records = [];
|
@observable records = [];
|
||||||
@observable zones = [];
|
@observable zones = [];
|
||||||
|
@observable permRecords = [];
|
||||||
@observable record = {};
|
@observable record = {};
|
||||||
@observable idMap = {};
|
@observable idMap = {};
|
||||||
@observable isFetching = false;
|
@observable isFetching = false;
|
||||||
|
@ -22,9 +23,10 @@ class Store {
|
||||||
fetchRecords = () => {
|
fetchRecords = () => {
|
||||||
this.isFetching = true;
|
this.isFetching = true;
|
||||||
return http.get('/api/host/')
|
return http.get('/api/host/')
|
||||||
.then(({hosts, zones}) => {
|
.then(({hosts, zones, perms}) => {
|
||||||
this.records = hosts;
|
this.records = hosts;
|
||||||
this.zones = zones;
|
this.zones = zones;
|
||||||
|
this.permRecords = hosts.filter(item => perms.includes(item.id));
|
||||||
for (let item of hosts) {
|
for (let item of hosts) {
|
||||||
this.idMap[item.id] = item
|
this.idMap[item.id] = item
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import logo from 'layout/logo-spug-txt.png';
|
||||||
import envStore from 'pages/config/environment/store';
|
import envStore from 'pages/config/environment/store';
|
||||||
import appStore from 'pages/config/app/store';
|
import appStore from 'pages/config/app/store';
|
||||||
import requestStore from 'pages/deploy/request/store';
|
import requestStore from 'pages/deploy/request/store';
|
||||||
|
import hostStore from 'pages/host/store';
|
||||||
|
|
||||||
class LoginIndex extends React.Component {
|
class LoginIndex extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -26,7 +27,8 @@ class LoginIndex extends React.Component {
|
||||||
envStore.records = [];
|
envStore.records = [];
|
||||||
appStore.records = [];
|
appStore.records = [];
|
||||||
requestStore.records = [];
|
requestStore.records = [];
|
||||||
requestStore.deploys = []
|
requestStore.deploys = [];
|
||||||
|
hostStore.records = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = () => {
|
handleSubmit = () => {
|
||||||
|
|
|
@ -25,6 +25,7 @@ class WebSSH extends React.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
visible: false,
|
visible: false,
|
||||||
uploading: false,
|
uploading: false,
|
||||||
|
managerDisabled: true,
|
||||||
host: {},
|
host: {},
|
||||||
percent: 0
|
percent: 0
|
||||||
}
|
}
|
||||||
|
@ -71,17 +72,17 @@ class WebSSH extends React.Component {
|
||||||
http.get(`/api/host/?id=${this.id}`)
|
http.get(`/api/host/?id=${this.id}`)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
document.title = res.name;
|
document.title = res.name;
|
||||||
this.setState({host: res})
|
this.setState({host: res, managerDisabled: false})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {host, visible} = this.state;
|
const {host, visible, managerDisabled} = this.state;
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div>{host.name} | {host.username}@{host.hostname}:{host.port}</div>
|
<div>{host.name} | {host.username}@{host.hostname}:{host.port}</div>
|
||||||
<Button type="primary" icon="folder-open" onClick={this.handleShow}>文件管理器</Button>
|
<Button disabled={managerDisabled} type="primary" icon="folder-open" onClick={this.handleShow}>文件管理器</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.terminal}>
|
<div className={styles.terminal}>
|
||||||
<div ref={ref => this.container = ref}/>
|
<div ref={ref => this.container = ref}/>
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||||
|
* Copyright (c) <spug.dev@gmail.com>
|
||||||
|
* Released under the MIT License.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { Modal, Form, Transfer, message, Alert } from 'antd';
|
||||||
|
import http from 'libs/http';
|
||||||
|
import hostStore from 'pages/host/store';
|
||||||
|
import store from './store';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class HostPerm extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: false,
|
||||||
|
hosts: [],
|
||||||
|
apps: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (hostStore.records.length === 0) {
|
||||||
|
hostStore.fetchRecords().then(
|
||||||
|
() => this._updateRecords(hostStore.records)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._updateRecords(hostStore.records)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateRecords = (records) => {
|
||||||
|
const hosts = records.map(x => {
|
||||||
|
return {...x, key: x.id}
|
||||||
|
});
|
||||||
|
this.setState({hosts})
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSubmit = () => {
|
||||||
|
this.setState({loading: true});
|
||||||
|
http.patch('/api/account/role/', {id: store.record.id, host_perms: store.hostPerms})
|
||||||
|
.then(res => {
|
||||||
|
message.success('操作成功');
|
||||||
|
store.hostPermVisible = false;
|
||||||
|
store.fetchRecords()
|
||||||
|
}, () => this.setState({loading: false}))
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible
|
||||||
|
width={800}
|
||||||
|
maskClosable={false}
|
||||||
|
title="主机权限设置"
|
||||||
|
onCancel={() => store.hostPermVisible = false}
|
||||||
|
confirmLoading={this.state.loading}
|
||||||
|
onOk={this.handleSubmit}>
|
||||||
|
<Alert
|
||||||
|
closable
|
||||||
|
showIcon
|
||||||
|
type="info"
|
||||||
|
message="小提示"
|
||||||
|
style={{width: 600, margin: '0 auto 20px', color: '#31708f !important'}}
|
||||||
|
description="主机权限将全局影响属于该角色的用户能够看到的主机。"/>
|
||||||
|
<Form.Item label="设置可访问的主机" style={{padding: '0 20px'}}>
|
||||||
|
<Transfer
|
||||||
|
listStyle={{width: 325, minHeight: 300}}
|
||||||
|
titles={['所有主机', '已选主机']}
|
||||||
|
dataSource={this.state.hosts}
|
||||||
|
targetKeys={store.hostPerms}
|
||||||
|
onChange={keys => store.hostPerms = keys}
|
||||||
|
render={item => `${item.zone} - ${item.name}`}/>
|
||||||
|
</Form.Item>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HostPerm
|
|
@ -28,7 +28,7 @@ class ComTable extends React.Component {
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
}, {
|
}, {
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 300,
|
width: 400,
|
||||||
render: info => (
|
render: info => (
|
||||||
<span>
|
<span>
|
||||||
<LinkButton onClick={() => store.showForm(info)}>编辑</LinkButton>
|
<LinkButton onClick={() => store.showForm(info)}>编辑</LinkButton>
|
||||||
|
@ -37,6 +37,8 @@ class ComTable extends React.Component {
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
<LinkButton onClick={() => store.showDeployPerm(info)}>发布权限</LinkButton>
|
<LinkButton onClick={() => store.showDeployPerm(info)}>发布权限</LinkButton>
|
||||||
<Divider type="vertical"/>
|
<Divider type="vertical"/>
|
||||||
|
<LinkButton onClick={() => store.showHostPerm(info)}>主机权限</LinkButton>
|
||||||
|
<Divider type="vertical"/>
|
||||||
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
<LinkButton onClick={() => this.handleDelete(info)}>删除</LinkButton>
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ComTable from './Table';
|
||||||
import ComForm from './Form';
|
import ComForm from './Form';
|
||||||
import PagePerm from './PagePerm';
|
import PagePerm from './PagePerm';
|
||||||
import DeployPerm from './DeployPerm';
|
import DeployPerm from './DeployPerm';
|
||||||
|
import HostPerm from './HostPerm';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
|
@ -31,6 +32,7 @@ export default observer(function () {
|
||||||
{store.formVisible && <ComForm/>}
|
{store.formVisible && <ComForm/>}
|
||||||
{store.pagePermVisible && <PagePerm/>}
|
{store.pagePermVisible && <PagePerm/>}
|
||||||
{store.deployPermVisible && <DeployPerm/>}
|
{store.deployPermVisible && <DeployPerm/>}
|
||||||
|
{store.hostPermVisible && <HostPerm/>}
|
||||||
</AuthCard>
|
</AuthCard>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,10 +15,12 @@ class Store {
|
||||||
@observable record = {};
|
@observable record = {};
|
||||||
@observable permissions = lds.cloneDeep(codes);
|
@observable permissions = lds.cloneDeep(codes);
|
||||||
@observable deployRel = {};
|
@observable deployRel = {};
|
||||||
|
@observable hostPerms = [];
|
||||||
@observable isFetching = false;
|
@observable isFetching = false;
|
||||||
@observable formVisible = false;
|
@observable formVisible = false;
|
||||||
@observable pagePermVisible = false;
|
@observable pagePermVisible = false;
|
||||||
@observable deployPermVisible = false;
|
@observable deployPermVisible = false;
|
||||||
|
@observable hostPermVisible = false;
|
||||||
|
|
||||||
@observable f_name;
|
@observable f_name;
|
||||||
|
|
||||||
|
@ -58,6 +60,12 @@ class Store {
|
||||||
this.record = info;
|
this.record = info;
|
||||||
this.deployPermVisible = true;
|
this.deployPermVisible = true;
|
||||||
this.deployRel = info.deploy_perms || {}
|
this.deployRel = info.deploy_perms || {}
|
||||||
|
};
|
||||||
|
|
||||||
|
showHostPerm = (info) => {
|
||||||
|
this.record = info;
|
||||||
|
this.hostPermVisible = true;
|
||||||
|
this.hostPerms = info['host_perms'] || []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue