refactor: Refactor user group

1. Refactor group store
2. Refactor create group: add domain prop when create
3. Refactor edit group
4. Refactor user group manage user
5. Refactor group detail
6. Suppport actions in role detail
7. Refactor group list: add project/role column && domain dolumn; remove
user number column

Change-Id: If8f250da3ac27e5050c9fd4d31ad9954177ed0fe
This commit is contained in:
Jingwei.Zhang 2022-06-07 11:44:37 +08:00
parent 633fcdec63
commit b6999ea0a1
16 changed files with 544 additions and 894 deletions

View File

@ -34,6 +34,8 @@ import {
HddOutlined, HddOutlined,
CloudServerOutlined, CloudServerOutlined,
LoadingOutlined, LoadingOutlined,
TeamOutlined,
ProjectOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import styles from './index.less'; import styles from './index.less';
@ -66,6 +68,8 @@ const iconTypeMap = {
host: <CloudServerOutlined />, host: <CloudServerOutlined />,
security: SecurityIcon, security: SecurityIcon,
lb: LBIcon, lb: LBIcon,
group: <TeamOutlined />,
project: <ProjectOutlined />,
}; };
export default class index extends Component { export default class index extends Component {

View File

@ -1345,6 +1345,7 @@
"Manage User": "Manage User", "Manage User": "Manage User",
"Manage User Group": "Manage User Group", "Manage User Group": "Manage User Group",
"Manage host": "Manage host", "Manage host": "Manage host",
"Manage user": "Manage user",
"Manageable": "Manageable", "Manageable": "Manageable",
"Management": "Management", "Management": "Management",
"Management Reason": "Management Reason", "Management Reason": "Management Reason",
@ -1620,7 +1621,6 @@
"Pending Create": "Pending Create", "Pending Create": "Pending Create",
"Pending Delete": "Pending Delete", "Pending Delete": "Pending Delete",
"Pending Update": "Pending Update", "Pending Update": "Pending Update",
"People Num": "People Num",
"Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.": "Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.", "Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.": "Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.",
"Permanent": "Permanent", "Permanent": "Permanent",
"Persistent": "Persistent", "Persistent": "Persistent",
@ -1759,6 +1759,7 @@
"Project Range": "Project Range", "Project Range": "Project Range",
"Project Reader": "Project Reader", "Project Reader": "Project Reader",
"Project Scope": "Project Scope", "Project Scope": "Project Scope",
"Project Scope (Project Name: Role Names)": "Project Scope (Project Name: Role Names)",
"Project User": "Project User", "Project User": "Project User",
"Project User Group": "Project User Group", "Project User Group": "Project User Group",
"Projects": "Projects", "Projects": "Projects",
@ -1955,7 +1956,6 @@
"Select Project Role": "Select Project Role", "Select Project Role": "Select Project Role",
"Select Snapshot": "Select Snapshot", "Select Snapshot": "Select Snapshot",
"Select System Role": "Select System Role", "Select System Role": "Select System Role",
"Select User": "Select User",
"Select User Group": "Select User Group", "Select User Group": "Select User Group",
"Select a domain": "Select a domain", "Select a domain": "Select a domain",
"Select a region": "Select a region", "Select a region": "Select a region",
@ -2159,7 +2159,6 @@
"System Load": "System Load", "System Load": "System Load",
"System Reader": "System Reader", "System Reader": "System Reader",
"System Running Time": "System Running Time", "System Running Time": "System Running Time",
"System Scope": "System Scope",
"System is error, please try again later.": "System is error, please try again later.", "System is error, please try again later.": "System is error, please try again later.",
"TCP": "TCP", "TCP": "TCP",
"TCP Connections": "TCP Connections", "TCP Connections": "TCP Connections",
@ -2392,7 +2391,6 @@
"User Detail": "User Detail", "User Detail": "User Detail",
"User Edit": "User Edit", "User Edit": "User Edit",
"User Group Detail": "User Group Detail", "User Group Detail": "User Group Detail",
"User Group ID": "User Group ID",
"User Group ID/Name": "User Group ID/Name", "User Group ID/Name": "User Group ID/Name",
"User Group Name": "User Group Name", "User Group Name": "User Group Name",
"User Group Num": "User Group Num", "User Group Num": "User Group Num",

View File

@ -1345,6 +1345,7 @@
"Manage User": "管理用户", "Manage User": "管理用户",
"Manage User Group": "管理用户组", "Manage User Group": "管理用户组",
"Manage host": "管理主机", "Manage host": "管理主机",
"Manage user": "管理用户",
"Manageable": "可管理", "Manageable": "可管理",
"Management": "维护", "Management": "维护",
"Management Reason": "维护原因", "Management Reason": "维护原因",
@ -1620,7 +1621,6 @@
"Pending Create": "等待创建", "Pending Create": "等待创建",
"Pending Delete": "等待删除", "Pending Delete": "等待删除",
"Pending Update": "等待更新", "Pending Update": "等待更新",
"People Num": "",
"Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.": "将请求的源IP地址进行一致性Hash运算得到一个具体的数值同时对后端服务器进行编号按照运算结果将请求分发到对应编号的服务器上。这可以使得对不同源IP的访问进行负载分发同时使得同一个客户端IP的请求始终被派发至某特定的服务器。该方式适合负载均衡无cookie功能的TCP协议。", "Perform a consistent hash operation on the source IP address of the request to obtain a specific value. At the same time, the back-end server is numbered, and the request is distributed to the server with the corresponding number according to the calculation result. This can enable load distribution of visits from different source IPs, and at the same time enable requests from the same client IP to always be dispatched to a specific server. This method is suitable for load balancing TCP protocol without cookie function.": "将请求的源IP地址进行一致性Hash运算得到一个具体的数值同时对后端服务器进行编号按照运算结果将请求分发到对应编号的服务器上。这可以使得对不同源IP的访问进行负载分发同时使得同一个客户端IP的请求始终被派发至某特定的服务器。该方式适合负载均衡无cookie功能的TCP协议。",
"Permanent": "长期保留", "Permanent": "长期保留",
"Persistent": "持久性", "Persistent": "持久性",
@ -1759,6 +1759,7 @@
"Project Range": "项目范围", "Project Range": "项目范围",
"Project Reader": "项目只读权限", "Project Reader": "项目只读权限",
"Project Scope": "所属项目", "Project Scope": "所属项目",
"Project Scope (Project Name: Role Names)": "所属项目(项目名称:角色名称)",
"Project User": "项目用户", "Project User": "项目用户",
"Project User Group": "项目用户组", "Project User Group": "项目用户组",
"Projects": "项目", "Projects": "项目",
@ -1955,7 +1956,6 @@
"Select Project Role": "选择项目角色", "Select Project Role": "选择项目角色",
"Select Snapshot": "选择快照", "Select Snapshot": "选择快照",
"Select System Role": "选择系统角色", "Select System Role": "选择系统角色",
"Select User": "选择用户",
"Select User Group": "选择用户组", "Select User Group": "选择用户组",
"Select a domain": "请选择Domain", "Select a domain": "请选择Domain",
"Select a region": "请选择Region", "Select a region": "请选择Region",
@ -2159,7 +2159,6 @@
"System Load": "系统负载", "System Load": "系统负载",
"System Reader": "系统只读权限", "System Reader": "系统只读权限",
"System Running Time": "", "System Running Time": "",
"System Scope": "绑定系统范围",
"System is error, please try again later.": "系统出错,请稍后再试。", "System is error, please try again later.": "系统出错,请稍后再试。",
"TCP": "", "TCP": "",
"TCP Connections": "TCP连接数", "TCP Connections": "TCP连接数",
@ -2392,7 +2391,6 @@
"User Detail": "用户详情", "User Detail": "用户详情",
"User Edit": "编辑用户", "User Edit": "编辑用户",
"User Group Detail": "用户组详情", "User Group Detail": "用户组详情",
"User Group ID": "用户组ID",
"User Group ID/Name": "用户组ID/名称", "User Group ID/Name": "用户组ID/名称",
"User Group Name": "用户组名称", "User Group Name": "用户组名称",
"User Group Num": "用户组数", "User Group Num": "用户组数",

View File

@ -18,6 +18,7 @@ import Base from 'containers/TabDetail';
import User from '../../User'; import User from '../../User';
import Group from '../../UserGroup'; import Group from '../../UserGroup';
import impliedRole from './BaseDetail'; import impliedRole from './BaseDetail';
import actionConfigs from '../actions';
export class RoleDetail extends Base { export class RoleDetail extends Base {
get name() { get name() {
@ -32,6 +33,10 @@ export class RoleDetail extends Base {
return this.getRoutePath('role'); return this.getRoutePath('role');
} }
get actionConfigs() {
return actionConfigs;
}
init() { init() {
this.store = new RoleStore(); this.store = new RoleStore();
} }

View File

@ -12,16 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import React from 'react';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { Button, Divider } from 'antd';
import { UpOutlined, DownOutlined } from '@ant-design/icons';
import globalDomainStore from 'stores/keystone/domain';
import { GroupStore } from 'stores/keystone/user-group'; import { GroupStore } from 'stores/keystone/user-group';
import Base from 'containers/TabDetail'; import Base from 'containers/TabDetail';
import User from '../../User'; import User from '../../User';
import Project from '../../Project'; import Project from '../../Project';
import styles from './index.less';
import actionConfigs from '../actions'; import actionConfigs from '../actions';
export class Detail extends Base { export class Detail extends Base {
@ -43,17 +38,6 @@ export class Detail extends Base {
init() { init() {
this.store = new GroupStore(); this.store = new GroupStore();
this.domainStore = globalDomainStore;
this.getDomains();
}
getDomains() {
this.domainStore.fetchDomain();
}
get domainList() {
const { domains } = this.domainStore;
return domains || [];
} }
get detailInfos() { get detailInfos() {
@ -62,20 +46,14 @@ export class Detail extends Base {
title: t('User Group Name'), title: t('User Group Name'),
dataIndex: 'name', dataIndex: 'name',
}, },
// {
// title: t('People Num'),
// dataIndex: 'user_num',
// },
{ {
title: t('Affiliated Domain'), title: t('Affiliated Domain'),
dataIndex: 'domain_id', dataIndex: 'domain',
render: (domain_id) => { render: (value, record) => (value || {}).name || record.domain_id,
const domain = this.domainList.filter((it) => it.id === domain_id); },
if (domain[0]) { {
return domain[0].name; title: t('User Num'),
} dataIndex: 'userCount',
return domain_id;
},
}, },
{ {
title: t('Description'), title: t('Description'),
@ -99,37 +77,6 @@ export class Detail extends Base {
]; ];
return tabs; return tabs;
} }
goEdit = () => {
const {
params: { id },
} = this.props.match;
this.routing.push(`${this.listUrl}/edit/${id}`);
};
get detailTitle() {
const {
detail: { id },
} = this.store;
const { collapsed } = this.state;
const icon = collapsed ? <DownOutlined /> : <UpOutlined />;
return (
<div>
<span className={styles['title-label']}>{t('User Group ID')}:</span>
<span className={styles['header-title']}>{id}</span>
<Divider type="vertical" className={styles['header-divider']} />
<Button onClick={this.goBack} type="link">
{t('Back')}
</Button>
<Button
onClick={this.handleDetailInfo}
icon={icon}
type="link"
className={styles['header-button']}
/>
</div>
);
}
} }
export default inject('rootStore')(observer(Detail)); export default inject('rootStore')(observer(Detail));

View File

@ -12,62 +12,24 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import React from 'react';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import globalUserStore from 'stores/keystone/user';
import { has } from 'lodash';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import { Select } from 'antd';
import globalProjectStore from 'stores/keystone/project';
import globalRoleStore from 'stores/keystone/role';
import globalDomainStore from 'stores/keystone/domain'; import globalDomainStore from 'stores/keystone/domain';
import globalGroupStore from 'stores/keystone/user-group'; import globalGroupStore from 'stores/keystone/user-group';
import { getDomainFormItem } from 'resources/keystone/domain';
export class CreateForm extends ModalAction { export class Create extends ModalAction {
constructor(props) {
super(props);
this.state = {
domain: null,
more: false,
newProjectRoles: {},
};
}
init() { init() {
this.userStore = globalUserStore; this.store = globalGroupStore;
this.userGroupStore = globalGroupStore;
this.projectStore = globalProjectStore;
this.domainStore = globalDomainStore; this.domainStore = globalDomainStore;
this.roleStore = globalRoleStore;
this.getUser();
this.getProject();
this.getDomains();
this.getRole();
}
getUser() {
this.userStore.fetchList();
}
getProject() {
this.projectStore.fetchList();
}
getDomains() {
this.domainStore.fetchDomain(); this.domainStore.fetchDomain();
} }
getRole() {
this.roleStore.fetchList();
}
static id = 'user-group-create'; static id = 'user-group-create';
static title = t('Create User Group'); static title = t('Create User Group');
// static path = '/identity/user-group-admin/create'; static policy = 'identity:create_group';
static policy = ['identity:create_group', 'identity:add_user_to_group'];
static allowed() { static allowed() {
return Promise.resolve(true); return Promise.resolve(true);
@ -77,128 +39,20 @@ export class CreateForm extends ModalAction {
return t('Create User Group'); return t('Create User Group');
} }
get domainDefault() {
const { domains } = this.domainStore;
const domainDefault = domains.filter((it) => it.id === 'default');
return domainDefault[0];
}
get defaultValue() { get defaultValue() {
const data = { const data = {
more: false, domain_id: 'default',
}; };
return data; return data;
} }
get domainList() {
const { domains } = this.domainStore;
return (domains || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
get userList() {
return (this.userStore.list.data || []).map((it) => ({
...it,
key: it.id,
}));
}
get projects() {
return (this.projectStore.list.data || []).map((it) => ({
...it,
key: it.id,
}));
}
groupRolesList = (groupId) => {
return (this.roleStore.list.data || []).map((it) => ({
label: it.name,
value: it.id,
groupId,
}));
};
defaultRoles = () => {
return [this.roleStore.list.data[0].id];
};
groupRoleChange = (value, option) => {
const { newProjectRoles } = this.state;
const { groupId } = option[0];
newProjectRoles[groupId] = value;
this.setState({ newProjectRoles });
};
onValuesChange = (changedFields) => {
if (has(changedFields, 'more')) {
this.setState({
more: changedFields.more,
});
}
};
get leftProjectTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
get rightProjectTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
{
title: t('Select Project Role'),
dataIndex: 'id',
render: (id) => {
return (
<Select
size="small"
options={this.groupRolesList(id)}
defaultValue={this.defaultRoles()}
onChange={this.groupRoleChange}
mode="multiple"
/>
);
},
},
];
}
get leftUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
get rightUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
checkName = (rule, value) => { checkName = (rule, value) => {
if (!value) { if (!value) {
return Promise.reject(t('Please input')); return Promise.reject(t('Please input'));
} }
const { const { list: { data = [] } = {} } = this.store;
list: { data }, const nameUsed = data.find((it) => it.name === value);
} = this.userGroupStore; if (nameUsed) {
const nameUsed = data.filter((it) => it.name === value);
if (nameUsed[0]) {
return Promise.reject( return Promise.reject(
t('Invalid: User Group name can not be duplicated') t('Invalid: User Group name can not be duplicated')
); );
@ -207,6 +61,7 @@ export class CreateForm extends ModalAction {
}; };
get formItems() { get formItems() {
const domainFormItem = getDomainFormItem(this);
return [ return [
{ {
name: 'name', name: 'name',
@ -218,50 +73,18 @@ export class CreateForm extends ModalAction {
extra: t('User Groups') + t('Name can not be duplicated'), extra: t('User Groups') + t('Name can not be duplicated'),
maxLength: 30, maxLength: 30,
}, },
domainFormItem,
{ {
name: 'description', name: 'description',
label: t('Description'), label: t('Description'),
type: 'textarea', type: 'textarea',
}, },
// {
// type: 'divider',
// },
// {
// name: 'more',
// label: t('Advanced Options'),
// type: 'more',
// },
// {
// name: 'select_project',
// label: t('Select Project'),
// type: 'transfer',
// leftTableColumns: this.leftProjectTable,
// rightTableColumns: this.rightProjectTable,
// dataSource: domain ? this.projects.filter(it => it.domain_id === domain) : [],
// disabled: false,
// showSearch: true,
// hidden: !more || !domain,
// },
// {
// name: 'select_user',
// label: t('Select User'),
// type: 'transfer',
// leftTableColumns: this.leftUserTable,
// rightTableColumns: this.rightUserTable,
// dataSource: domain ? this.userList.filter(it => it.domain_id === domain) : [],
// disabled: false,
// showSearch: true,
// hidden: !more || !domain,
// },
]; ];
} }
onSubmit = (values) => { onSubmit = (values) => {
const defaultRole = this.roleStore.list.data[0].id; return this.store.create(values);
values.domain_id = this.domainDefault.id;
const { newProjectRoles } = this.state;
return this.userGroupStore.create(values, newProjectRoles, defaultRole);
}; };
} }
export default inject('rootStore')(observer(CreateForm)); export default inject('rootStore')(observer(Create));

View File

@ -103,17 +103,17 @@ export class DomainPermission extends ModalAction {
} = this.props; } = this.props;
const promiseList = []; const promiseList = [];
oldRoles.forEach((role) => { oldRoles.forEach((role) => {
const { id: role_id } = role; const { id: roleId } = role;
if (newRoles.indexOf(role_id) === -1) { if (newRoles.indexOf(roleId) === -1) {
promiseList.push( promiseList.push(
globalGroupStore.deleteDomainRole({ id, role_id, domain_id }) globalGroupStore.deleteDomainRole({ id, roleId, domain_id })
); );
} }
}); });
newRoles.forEach((role_id) => { newRoles.forEach((roleId) => {
if (oldRoles.indexOf(role_id) === -1) { if (oldRoles.indexOf(roleId) === -1) {
promiseList.push( promiseList.push(
globalGroupStore.assignDomainRole({ id, role_id, domain_id }) globalGroupStore.assignDomainRole({ id, roleId, domain_id })
); );
} }
}); });

View File

@ -14,13 +14,11 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import globalDomainStore from 'stores/keystone/domain';
import globalGroupStore from 'stores/keystone/user-group'; import globalGroupStore from 'stores/keystone/user-group';
export class EditForm extends ModalAction { export class EditForm extends ModalAction {
init() { init() {
this.store = globalGroupStore; this.store = globalGroupStore;
this.domainStore = globalDomainStore;
} }
static id = 'user-group-edit'; static id = 'user-group-edit';
@ -35,17 +33,10 @@ export class EditForm extends ModalAction {
get defaultValue() { get defaultValue() {
const { name, description } = this.item; const { name, description } = this.item;
if (name && this.formRef.current) { return {
this.formRef.current.setFieldsValue({
name,
description,
});
}
const data = {
name, name,
description, description,
}; };
return data;
} }
checkName = (rule, value) => { checkName = (rule, value) => {
@ -55,9 +46,9 @@ export class EditForm extends ModalAction {
const { const {
list: { data }, list: { data },
} = this.store; } = this.store;
const { name } = this.item; const { id } = this.item;
const nameUsed = data.filter((it) => it.name === value); const nameUsed = data.find((it) => it.name === value && it.id !== id);
if (nameUsed[0] && nameUsed[0].name !== name) { if (nameUsed) {
return Promise.reject( return Promise.reject(
t('Invalid: User Group name can not be duplicated') t('Invalid: User Group name can not be duplicated')
); );

View File

@ -0,0 +1,145 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { inject, observer } from 'mobx-react';
import { UserStore } from 'stores/keystone/user';
import { GroupStore } from 'stores/keystone/user-group';
import { ModalAction } from 'containers/Action';
import {
nameDomainColumns,
transferFilterOption,
} from 'resources/keystone/domain';
export class ManageUser extends ModalAction {
static id = 'manage-user';
static title = t('Manage User');
get name() {
return t('Manage user');
}
static get modalSize() {
return 'large';
}
getModalSize() {
return 'large';
}
async init() {
this.state.groupUsers = [];
this.store = new GroupStore();
this.userStore = new UserStore();
this.getGroupUsers();
this.getAllUser();
}
getAllUser() {
this.userStore.fetchAllWithDomain();
}
async getGroupUsers() {
await this.store.fetchGroupUsers(this.item);
this.setState({
groupUsers: this.groupUsers,
});
this.updateDefaultValue();
}
get userList() {
const users = this.userStore.list.data || [];
return users.map((it) => ({
...it,
key: it.id,
}));
}
get groupUsers() {
return (this.store.groupUsers || []).map((it) => it.id);
}
static policy = [
'identity:list_users_in_group',
'identity:list_users_in_group',
'identity:add_user_to_group',
];
static allowed = () => Promise.resolve(true);
get leftUserTable() {
return nameDomainColumns;
}
get rightUserTable() {
return nameDomainColumns;
}
get defaultValue() {
const { name, domainName } = this.item;
const data = {
name,
domain: domainName,
select_user: this.groupUsers,
};
return data;
}
get formItems() {
return [
{
name: 'name',
type: 'label',
label: t('Name'),
iconType: 'group',
},
{
name: 'domain',
type: 'label',
label: t('Domain'),
},
{
name: 'select_user',
type: 'transfer',
label: t('User'),
leftTableColumns: this.leftUserTable,
rightTableColumns: this.rightUserTable,
dataSource: this.userList,
disabled: false,
showSearch: true,
filterOption: transferFilterOption,
},
];
}
onSubmit = async (values) => {
const { select_user: newUsers } = values;
const { id } = this.item;
const promiseList = [];
this.groupUsers.forEach((userId) => {
if (newUsers.indexOf(userId) === -1) {
promiseList.push(this.store.deleteGroupUsers({ id, userId }));
}
});
newUsers.forEach((userId) => {
if (this.groupUsers.indexOf(userId) === -1) {
promiseList.push(this.store.addGroupUsers({ id, userId }));
}
});
const results = await Promise.all(promiseList);
return results;
};
}
export default inject('rootStore')(observer(ManageUser));

View File

@ -103,14 +103,14 @@ export class SystemPermission extends ModalAction {
} = this.props; } = this.props;
const promiseList = []; const promiseList = [];
oldRoles.forEach((role) => { oldRoles.forEach((role) => {
const { id: role_id } = role; const { id: roleId } = role;
if (newRoles.indexOf(role_id) === -1) { if (newRoles.indexOf(roleId) === -1) {
promiseList.push(globalGroupStore.deleteSystemRole({ id, role_id })); promiseList.push(globalGroupStore.deleteSystemRole({ id, roleId }));
} }
}); });
newRoles.forEach((role_id) => { newRoles.forEach((roleId) => {
if (oldRoles.indexOf(role_id) === -1) { if (oldRoles.indexOf(roleId) === -1) {
promiseList.push(globalGroupStore.assignSystemRole({ id, role_id })); promiseList.push(globalGroupStore.assignSystemRole({ id, roleId }));
} }
}); });
const results = await Promise.all(promiseList); const results = await Promise.all(promiseList);

View File

@ -1,182 +0,0 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { inject, observer } from 'mobx-react';
import { UserStore } from 'stores/keystone/user';
import globalGroupStore from 'stores/keystone/user-group';
import { ModalAction } from 'containers/Action';
import globalDomainStore from 'stores/keystone/domain';
export class UserManager extends ModalAction {
constructor(props) {
super(props);
this.state = {
domainDefault: this.item.domain_id,
userList: [],
};
}
init() {
// this.store = globalUserStore;
this.domainStore = globalDomainStore;
this.userStore = new UserStore();
this.getDomains();
this.getUser();
}
// componentDidMount() {
// globalUserStore.fetchList().then((res) => {
// const domainUsers = res.filter(it => it.domain_id === this.item.domain_id);
// const userList = domainUsers.map(it => ({
// ...it,
// key: it.id,
// }));
// this.setState({ userList });
// });
// }
static id = 'management-user';
static title = t('Manage User');
get name() {
return t('Manager user');
}
getDomains() {
this.domainStore.fetchDomain();
}
getUser() {
this.userStore.fetchList();
}
static get modalSize() {
return 'large';
}
getModalSize() {
return 'large';
}
get domainList() {
const { domains } = this.domainStore;
return (domains || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
get userList() {
return (this.userStore.list.data || []).map((it) => ({
...it,
key: it.id,
}));
}
static policy = [
'identity:list_users_in_group',
'identity:list_users_in_group',
'identity:add_user_to_group',
];
static allowed = () => Promise.resolve(true);
get leftUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
get rightUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
onSubChange = (value, option) => {
const { userRoles } = this.state;
userRoles[option.userId] = [value];
this.setState({
userRoles,
});
};
get defaultValue() {
const { domain_id: domain } = this.item;
const data = {
domain_id: domain || 'default',
};
return data;
}
get formItems() {
const { domainDefault } = this.state;
const { users: oldUsers } = this.item;
return [
{
name: 'domain_id',
label: t('Affiliated Domain'),
type: 'select',
options: this.domainList,
onChange: (e) => {
this.setState({
domainDefault: e,
});
},
required: true,
},
{
name: 'select_user',
type: 'transfer',
label: t('User'),
leftTableColumns: this.leftUserTable,
rightTableColumns: this.rightUserTable,
dataSource: this.userList
? this.userList.filter((it) => it.domain_id === domainDefault)
: [],
disabled: false,
showSearch: true,
oriTargetKeys: oldUsers,
},
];
}
onSubmit = async (values) => {
const { select_user: newUsers } = values;
const { users: oldUsers } = this.item;
const { id } = this.item;
const promiseList = [];
oldUsers.forEach((user_id) => {
if (newUsers.indexOf(user_id) === -1) {
promiseList.push(globalGroupStore.deleteGroupUsers({ id, user_id }));
}
});
newUsers.forEach((user_id) => {
if (oldUsers.indexOf(user_id) === -1) {
promiseList.push(globalGroupStore.addGroupUsers({ id, user_id }));
}
});
const results = await Promise.all(promiseList);
return results;
};
}
export default inject('rootStore')(observer(UserManager));

View File

@ -15,7 +15,7 @@
import Create from './Create'; import Create from './Create';
import Delete from './Delete'; import Delete from './Delete';
import Edit from './Edit'; import Edit from './Edit';
import UserManager from './UserManager'; import ManageUser from './ManageUser';
// import SystemPermission from './SystemPermission'; // import SystemPermission from './SystemPermission';
// import DomainPermission from './DomainPermission'; // import DomainPermission from './DomainPermission';
@ -30,7 +30,7 @@ const actionConfigs = {
// action: DomainPermission, // action: DomainPermission,
// }, // },
{ {
action: UserManager, action: ManageUser,
}, },
{ {
action: Delete, action: Delete,

View File

@ -15,18 +15,15 @@
import React from 'react'; import React from 'react';
import { observer, inject } from 'mobx-react'; import { observer, inject } from 'mobx-react';
import Base from 'containers/List'; import Base from 'containers/List';
import globalGroupStore from 'stores/keystone/user-group'; import globalGroupStore, { GroupStore } from 'stores/keystone/user-group';
import { Badge } from 'antd'; import { Typography } from 'antd';
import { emptyActionConfig } from 'utils/constants'; import { emptyActionConfig } from 'utils/constants';
import { isEmpty } from 'lodash';
import actionConfigs from './actions'; import actionConfigs from './actions';
export class UserGroups extends Base { export class UserGroups extends Base {
init() { init() {
this.store = globalGroupStore; this.store = this.inDetailPage ? new GroupStore() : globalGroupStore;
}
get tabs() {
return [];
} }
get policy() { get policy() {
@ -41,50 +38,143 @@ export class UserGroups extends Base {
return false; return false;
} }
getColumns() { get inUserDetail() {
const { const { pathname } = this.props.location;
match: { path }, return this.inDetailPage && pathname.includes('user-admin/detail');
} = this.props; }
const components = [
get inProjectDetail() {
const { pathname } = this.props.location;
return this.inDetailPage && pathname.includes('project-admin/detail');
}
get inRoleDetail() {
const { pathname } = this.props.location;
return this.inDetailPage && pathname.includes('role-admin/detail');
}
getBaseColumns() {
return [
{ {
title: t('User Group ID/Name'), title: t('User Group ID/Name'),
dataIndex: 'name', dataIndex: 'name',
routeName: 'userGroupDetailAdmin', routeName: 'userGroupDetailAdmin',
}, },
{ {
title: t('Project Scope'), title: t('Project Scope (Project Name: Role Names)'),
dataIndex: 'projectScope', dataIndex: 'projects',
isHideable: true, isHideable: true,
render: (projectScope) => { width: 500,
if (projectScope && projectScope[0]) { render: (value) => {
return projectScope.map((it, idx) => <div key={idx}>{it}</div>); if (isEmpty(value)) {
return '-';
} }
return Object.keys(value).map((projectId) => {
const { project, roles } = value[projectId];
const roleNames = roles
.map((role) => {
return role.name;
})
.join(', ');
const { id, name } = project;
const link = this.getLinkRender(
'projectDetail',
name,
{ id },
{ tab: 'userGroup' }
);
return (
<div key={projectId}>
<Typography.Text strong>{link}</Typography.Text>: {roleNames}
</div>
);
});
}, },
}, stringify: (value) => {
// { if (isEmpty(value)) {
// title: t('System Scope'), return '-';
// dataIndex: 'systemScope',
// isHideable: true,
// render: (systemScope) => {
// if (systemScope === true) {
// return 'All';
// }
// return '-';
// },
// },
{
title: t('Project Num'),
dataIndex: 'project_num',
render: (project_num) => {
if (project_num === 0) {
return <Badge color="red" text={project_num} />;
} }
return <Badge color="green" text={project_num} />; return Object.keys(value)
.map((projectId) => {
const { project, roles } = value[projectId];
const roleNames = roles.map((it) => it.name).join('|');
return `${project.name}: ${roleNames}`;
})
.join(';');
}, },
}, },
{ {
title: t('User Num'), title: t('Roles'),
dataIndex: 'user_num', dataIndex: 'rolesInProjectDetailPage',
isHideable: true,
render: (_, record) => {
const { projects = {} } = record;
if (isEmpty(projects)) {
return '-';
}
return Object.keys(projects).map((projectId) => {
const { roles } = projects[projectId];
return roles.map((role) => {
const { id, name } = role;
const link = this.getLinkRender(
'roleDetail',
name,
{ id },
{ tab: 'group' }
);
return <div key={id}>{link}</div>;
});
});
},
stringify: (_, record) => {
const { projects = {} } = record;
if (isEmpty(projects)) {
return '-';
}
return Object.keys(projects).map((projectId) => {
const { roles } = projects[projectId];
return roles.map((role) => role.name).join(';');
});
},
},
{
title: t('Project Scope'),
dataIndex: 'projectsInRoleDetailPage',
isHideable: true,
render: (_, record) => {
const { projects = {} } = record;
if (isEmpty(projects)) {
return '-';
}
return Object.keys(projects).map((projectId) => {
const { project } = projects[projectId];
const { id, name } = project;
const link = this.getLinkRender(
'projectDetail',
name,
{ id },
{ tab: 'userGroup' }
);
return <div key={id}>{link}</div>;
});
},
stringify: (_, record) => {
const { projects = {} } = record;
if (isEmpty(projects)) {
return '-';
}
return Object.keys(projects)
.map((projectId) => {
const { project } = projects[projectId];
return project.name;
})
.join(';');
},
},
{
title: t('Affiliated Domain'),
dataIndex: 'domainName',
isHideable: true,
}, },
{ {
title: t('Description'), title: t('Description'),
@ -92,21 +182,32 @@ export class UserGroups extends Base {
isHideable: true, isHideable: true,
}, },
]; ];
}
if (path.indexOf('role-admin/detail') === -1) { getColumns() {
components.splice(1, 1); const columns = this.getBaseColumns();
if (!this.inDetailPage || this.inUserDetail) {
return columns.filter((it) => !it.dataIndex.includes('DetailPage'));
} }
if (path.indexOf('user-group-admin') === -1) { if (this.inProjectDetail) {
components.splice(2, 1); return columns.filter(
(it) =>
it.dataIndex !== 'projects' &&
it.dataIndex !== 'projectsInRoleDetailPage'
);
} }
return components; if (this.inRoleDetail) {
return columns.filter(
(it) =>
it.dataIndex !== 'rolesInProjectDetailPage' &&
it.dataIndex !== 'projects'
);
}
return columns;
} }
get actionConfigs() { get actionConfigs() {
const { if (!this.inDetailPage) {
match: { path },
} = this.props;
if (path.indexOf('identity/user-group') >= 0) {
return actionConfigs; return actionConfigs;
} }
return emptyActionConfig; return emptyActionConfig;
@ -121,27 +222,19 @@ export class UserGroups extends Base {
]; ];
} }
async getData({ silent, ...params } = {}) { updateFetchParams = (params) => {
const { match } = this.props; const { match } = this.props;
const { path } = match; const { id } = match.params || {};
const newParams = { ...params }; const newParams = { ...params };
if (path.indexOf('project-admin/detail') >= 0) { if (this.inUserDetail) {
const { id } = match.params;
newParams.projectId = id;
await this.store.fetchListInProjectDetail(newParams);
} else if (path.indexOf('user-admin/detail') >= 0) {
const { id } = match.params;
newParams.userId = id; newParams.userId = id;
await this.store.fetchListInUserDetail(newParams); } else if (this.inProjectDetail) {
} else if (path.indexOf('role-admin/detail') >= 0) { newParams.projectId = id;
const { id } = match.params; } else if (this.inRoleDetail) {
newParams.roleId = id; newParams.roleId = id;
await this.store.fetchListInRoleDetail(newParams);
} else {
await this.store.fetchList(newParams);
} }
this.list.silent = false; return newParams;
} };
} }
export default inject('rootStore')(observer(UserGroups)); export default inject('rootStore')(observer(UserGroups));

View File

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { Badge } from 'antd'; import { Badge } from 'antd';
import globalDomainStore from 'stores/keystone/domain';
import globalRootStore from 'src/stores/root';
export const statusTypes = [ export const statusTypes = [
{ {
@ -12,6 +14,48 @@ export const statusTypes = [
}, },
]; ];
export const getDomainOptions = (self) => {
const { baseDomains } = globalRootStore;
const { domains } = globalDomainStore;
const domainList = (domains || []).filter(
(it) =>
baseDomains.indexOf(it.name) === -1 ||
it.id === (self.item || {}).domain_id
);
return domainList.map((it) => ({
label: it.name,
value: it.id,
key: it.id,
}));
};
export const getCheckedOptions = () => {
const { domains } = globalDomainStore;
return (domains || []).map((it) => ({
label: it.name,
value: it.id,
key: it.id,
}));
};
export const getDomainFormItem = (self) => {
return {
name: 'domain_id',
label: t('Affiliated Domain'),
type: 'select',
checkOptions: getCheckedOptions(),
checkBoxInfo: t('Show All Domain'),
options: getDomainOptions(self),
allowClear: false,
onChange: (e) => {
self.setState({
domain: e,
});
},
required: true,
};
};
export const enabledColumn = { export const enabledColumn = {
title: t('Enabled'), title: t('Enabled'),
dataIndex: 'enabled', dataIndex: 'enabled',
@ -24,3 +68,19 @@ export const enabledColumn = {
}, },
stringify: (val) => (val ? t('Yes') : t('No')), stringify: (val) => (val ? t('Yes') : t('No')),
}; };
export const nameDomainColumns = [
{
dataIndex: 'name',
title: t('Name'),
},
{
dataIndex: 'domainName',
title: t('Domain'),
},
];
export const transferFilterOption = (inputValue, record) => {
const { domainName, name } = record;
return name.includes(inputValue) || domainName.includes(inputValue);
};

View File

@ -13,15 +13,10 @@
// limitations under the License. // limitations under the License.
import { action, observable } from 'mobx'; import { action, observable } from 'mobx';
import { get } from 'lodash';
import client from 'client'; import client from 'client';
import Base from 'stores/base'; import Base from 'stores/base';
import globalProjectStore from 'stores/keystone/project';
export class GroupStore extends Base { export class GroupStore extends Base {
@observable
domains = [];
@observable @observable
systemRoles = []; systemRoles = [];
@ -59,68 +54,36 @@ export class GroupStore extends Base {
return client.keystone.projects; return client.keystone.projects;
} }
@action get paramsFunc() {
async create(data, newProjectRoles, defaultRole) { return (params) => {
const body = {}; const {
const { select_user, select_project, ...other } = data; id,
userId,
body[this.responseKey] = other; groupId,
this.isSubmitting = true; roleId,
const result = await this.client.create(body); projectId,
const { withRole,
group: { id: group_id }, all_projects,
} = result; ...rest
const promiseList = []; } = params;
if (select_user || select_project) { return rest;
const newProjects = Object.keys(newProjectRoles);
select_user.forEach((user_id) => {
promiseList.push(this.addGroupUsers({ id: group_id, user_id }));
});
select_project.forEach((id) => {
if (newProjects.indexOf(id) === -1) {
const role_id = defaultRole;
promiseList.push(
globalProjectStore.assignGroupRole({ id, group_id, role_id })
);
} else {
newProjectRoles[id].forEach((role_id) => {
promiseList.push(
globalProjectStore.assignGroupRole({ id, group_id, role_id })
);
});
}
});
await Promise.all(promiseList);
}
this.isSubmitting = false;
return result;
}
@action
async fetchDomain() {
const domainsResult = await this.domainClient.list();
this.domains = domainsResult.domains;
}
get mapper() {
return (item) => {
const domain = this.domains.filter((it) => it.id === item.domain_id);
if (domain[0]) {
item.domain_name = domain[0].name;
}
return item;
}; };
} }
listFetchByClient(params, originParams) {
const { userId } = originParams;
if (userId) {
return this.userClient.groups.list(userId, params);
}
return this.client.list(params);
}
@action @action
async edit({ id, description, name }) { async edit({ id, description, name }) {
this.isSubmitting = true;
const reqBody = { const reqBody = {
group: { description, name }, group: { description, name },
}; };
const result = await this.client.patch(id, reqBody); return this.submitting(this.client.patch(id, reqBody));
this.isSubmitting = false;
return result;
} }
@action @action
@ -131,13 +94,13 @@ export class GroupStore extends Base {
} }
@action @action
async assignSystemRole({ id, role_id }) { async assignSystemRole({ id, roleId }) {
return this.systemGroupClient.roles.update(id, role_id); return this.systemGroupClient.roles.update(id, roleId);
} }
@action @action
async deleteSystemRole({ id, role_id }) { async deleteSystemRole({ id, roleId }) {
return this.systemGroupClient.roles.delete(id, role_id); return this.systemGroupClient.roles.delete(id, roleId);
} }
@action @action
@ -151,328 +114,113 @@ export class GroupStore extends Base {
} }
@action @action
async assignDomainRole({ id, role_id, domain_id }) { async assignDomainRole({ id, roleId, domain_id }) {
return this.domainClient.groups.roles.update(domain_id, id, role_id); return this.domainClient.groups.roles.update(domain_id, id, roleId);
} }
@action @action
async deleteDomainRole({ id, role_id, domain_id }) { async deleteDomainRole({ id, roleId, domain_id }) {
return this.domainClient.groups.roles.delete(domain_id, id, role_id); return this.domainClient.groups.roles.delete(domain_id, id, roleId);
}
@action
async fetchListInProjectDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { projectId } = filters;
const params = {};
const [roleAssignmentsResult, result] = await Promise.all([
this.roleAssignmentClient.list(),
this.client.list(params),
]);
const projectGroupIds = [];
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
if (roleAssignment.group) {
const {
group: { id: group_id },
scope: { project: { id } = {} } = {},
} = roleAssignment;
if (id && id === projectId) {
projectGroupIds.push(group_id);
}
}
});
let data = get(result, this.listResponseKey, []);
data = data.filter((it) => projectGroupIds.indexOf(it.id) >= 0);
// const items = data.map(this.mapper);
// const newData = await this.listDidFetch(items);
Promise.all(data.map((it) => this.client.users.list(it.id))).then(
(rest) => {
const addUserItem = data.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
const userInfo = users.map((user) => ({
id: user.id,
name: user.name,
}));
it.users = userIds;
it.user_num = users.length;
it.user_info = userInfo;
return it;
});
const items = addUserItem.map((item) =>
this.mapperProject(roleAssignmentsResult, item)
);
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
}
);
}
@action
async fetchListInUserDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { userId } = filters;
const params = {};
const [roleAssignmentsResult, result] = await Promise.all([
this.roleAssignmentClient.list(),
this.userClient.groups.list(userId, params),
]);
const projectGroupIds = [];
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
if (roleAssignment.group) {
const {
group: { id: group_id },
scope: { project: { id } = {} } = {},
} = roleAssignment;
if (id && id === userId) {
projectGroupIds.push(group_id);
}
}
});
const data = get(result, this.listResponseKey, []);
const items = data.map((item) =>
this.mapperProject(roleAssignmentsResult, item)
);
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
} }
@action @action
async fetchGroupUsers({ id }) { async fetchGroupUsers({ id }) {
const usersResult = await this.client.users.list(id); const usersResult = await this.client.users.list(id);
const { users: result } = usersResult; const { users } = usersResult;
this.groupUsers = result; this.groupUsers = users;
return result; return users;
} }
@action @action
async deleteGroupUsers({ id, user_id }) { async deleteGroupUsers({ id, userId }) {
return this.client.users.delete(id, user_id); return this.client.users.delete(id, userId);
} }
@action @action
async addGroupUsers({ id, user_id }) { async addGroupUsers({ id, userId }) {
return this.client.users.update(id, user_id); return this.client.users.update(id, userId);
} }
mapperProject = (roleAssignmentsResult, item) => { updateUserGroup = (group, roleAssignments, roles, domains, projects) => {
const projects = roleAssignmentsResult.role_assignments.filter( const projectMapRoles = {};
(it) => const { id } = group || {};
it.group && roleAssignments.forEach((roleAssignment) => {
it.group.id === item.id && const {
it.scope && scope: { project: { id: projectId } = {} } = {},
it.scope.project && group: { id: groupId } = {},
it.scope.project.id role: { id: roleId } = {},
); } = roleAssignment;
item.projects = projects; if (groupId === id && roleId) {
item.project_num = projects.length; const roleItem = roles.find((it) => it.id === roleId);
return item; if (projectId) {
}; if (!projectMapRoles[projectId]) {
const projectItem = projects.find((it) => it.id === projectId);
@action projectMapRoles[projectId] = {
async fetchList({ project: projectItem,
limit, roles: [roleItem],
page, };
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const params = { ...filters };
const result = await this.client.list(params);
const roleAssignmentsResult = await this.roleAssignmentClient.list();
const data = get(result, this.listResponseKey, []);
Promise.all(
data.map(
(it) => this.client.users.list(it.id)
// const { users } = userResult;
// return { ...it, users };
)
).then((rest) => {
const addUserItem = data.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
const userInfo = users.map((user) => ({
id: user.id,
name: user.name,
}));
it.users = userIds;
it.user_num = users.length;
it.user_info = userInfo;
return it;
});
const items = addUserItem.map((item) =>
this.mapperProject(roleAssignmentsResult, item)
);
// const items = addUserItem.map(this.mapperProject);
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
}
@action
async fetchDetail({ id, silent }) {
if (!silent) {
this.isLoading = true;
}
const [roleAssignmentsResult, groupResult, usersInGroup] =
await Promise.all([
this.roleAssignmentClient.list(),
this.client.show(id),
this.client.users.list(id),
]);
const originData = get(groupResult, this.responseKey) || groupResult;
const { users } = usersInGroup;
const userIds = users.map((user) => user.id);
originData.users = userIds;
originData.user_num = users.length;
originData.user_info = users.map((user) => ({
id: user.id,
name: user.name,
}));
const group = this.mapperProject(roleAssignmentsResult, originData);
this.detail = group;
this.isLoading = false;
return this.detail;
}
@action
async fetchGroupData() {
const result = await this.client.list();
const { groups } = result;
return groups;
}
@action
async fetchListInRoleDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { roleId } = filters;
const params = {};
const [roleAssignmentsResult, projectResult, result] = await Promise.all([
this.roleAssignmentClient.list(),
this.projectClient.list(),
this.client.list(params),
]);
const projectRoleUsers = {};
const systemRoleUsers = {};
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
if (roleAssignment.group) {
const {
group: { id: group_id },
role: { id: role_id },
scope: { project, system } = {},
} = roleAssignment;
if (role_id === roleId && project) {
const projectData = projectResult.projects.find(
(it) => it.id === project.id
);
if (projectRoleUsers[group_id]) {
projectRoleUsers[group_id].push(projectData.name);
} else { } else {
projectRoleUsers[group_id] = [projectData.name]; projectMapRoles[projectId].roles = [
...projectMapRoles[projectId].roles,
roleItem,
];
} }
} else if (role_id === roleId && system) {
systemRoleUsers[group_id] = system.all;
} }
} }
}); });
const data = get(result, this.listResponseKey, []); const domain = domains.find((it) => it.id === group.domain_id);
const items = data return {
.filter((it) => projectRoleUsers[it.id] || systemRoleUsers[it.id]) ...group,
.map((it) => ({ projects: projectMapRoles,
projectScope: projectRoleUsers[it.id] || [], projectCount: Object.keys(projectMapRoles).length,
systemScope: systemRoleUsers[it.id] || [], domain,
...it, domainName: (domain || {}).name || group.domain_id,
})); };
};
// const items = data.map(this.mapper); async listDidFetch(items, allProjects, filters) {
// const newData = await this.listDidFetch(items); if (!items.length) {
Promise.all(data.map((it) => this.client.users.list(it.id))).then( return items;
(rest) => { }
items.map((it, index) => { const { projectId, roleId, withRole = true } = filters;
const { users } = rest[index]; const params = {};
const userIds = users.map((user) => user.id); if (projectId) {
const userInfo = users.map((user) => ({ params['project.id'] = projectId;
id: user.id, }
name: user.name, if (roleId) {
})); params['role.id'] = roleId;
it.users = userIds; }
it.user_num = users.length; const [roleAssignmentResult, roleResult, domainResult, projectsResult] =
it.user_info = userInfo; await Promise.all([
return it; withRole ? this.roleAssignmentClient.list(params) : null,
}); withRole ? this.roleClient.list() : null,
this.list.update({ this.domainClient.list(),
data: items, withRole ? this.projectClient.list() : null,
total: items.length || 0, ]);
limit: Number(limit) || 10, const { roles = [] } = roleResult || {};
page: Number(page) || 1, const { domains = [] } = domainResult;
sortKey, const { projects = [] } = projectsResult || {};
sortOrder, const { role_assignments: assigns = [] } = roleAssignmentResult || {};
filters, const newItems = items.map((group) => {
isLoading: false, return this.updateUserGroup(group, assigns, roles, domains, projects);
...(this.list.silent ? {} : { selectedRowKeys: [] }), });
}); if (projectId || roleId) {
return newItems.filter((it) => it.projectCount);
}
return newItems;
}
return items; async detailDidFetch(item) {
} const { id } = item;
); const [domainResult, userResult] = await Promise.all([
this.domainClient.list(),
this.client.users.list(id),
]);
const { domains = [] } = domainResult;
const { users = [] } = userResult;
const newItem = this.updateUserGroup(item, [], [], domains, []);
newItem.userCount = users.length;
return newItem;
} }
} }

View File

@ -96,7 +96,9 @@ export class UserStore extends Base {
if (select_user_group[0] || select_project[0]) { if (select_user_group[0] || select_project[0]) {
const newProjects = Object.keys(newProjectRoles); const newProjects = Object.keys(newProjectRoles);
select_user_group.forEach((id) => { select_user_group.forEach((id) => {
promiseList.push(globalGroupStore.addGroupUsers({ id, user_id })); promiseList.push(
globalGroupStore.addGroupUsers({ id, userId: user_id })
);
}); });
select_project.forEach((id) => { select_project.forEach((id) => {
if (!newProjects.includes(id)) { if (!newProjects.includes(id)) {
@ -128,9 +130,10 @@ export class UserStore extends Base {
get mapper() { get mapper() {
return (item) => { return (item) => {
const domain = this.domains.filter((it) => it.id === item.domain_id); const domain = this.domains.find((it) => it.id === item.domain_id);
if (domain[0]) { if (domain) {
item.domain_name = domain[0].name; item.domain_name = domain.name;
item.domainName = domain.name;
} }
return item; return item;
}; };
@ -624,6 +627,23 @@ export class UserStore extends Base {
return newData; return newData;
} }
@action
async fetchAllWithDomain() {
this.list.isLoading = true;
await this.fetchDomain();
const result = await this.client.list();
const data = get(result, this.listResponseKey, []);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
this.list.update({
data: newData,
total: items.length || 0,
isLoading: false,
});
return items;
}
} }
const globalUserStore = new UserStore(); const globalUserStore = new UserStore();