nacos 1.2.1
This commit is contained in:
1 parent
6231887d25
commit
ce58c8d7c7
33 files changed
+2735
No files matched your search
@@ -0,0 +1,75 @@
|
||||
import { isJsonString } from '../utils/nacosutil';
|
||||
|
||||
const configurationMenu = {
|
||||
key: 'configurationManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'configurationManagement',
|
||||
url: '/configurationManagement',
|
||||
},
|
||||
{
|
||||
key: 'historyRollback',
|
||||
url: '/historyRollback',
|
||||
},
|
||||
{
|
||||
key: 'listeningToQuery',
|
||||
url: '/listeningToQuery',
|
||||
},
|
||||
],
|
||||
};
|
||||
/**
|
||||
* 权限控制相关
|
||||
*/
|
||||
const authorityControlMenu = {
|
||||
key: 'authorityControl',
|
||||
children: [
|
||||
{
|
||||
key: 'userList',
|
||||
url: '/userManagement',
|
||||
},
|
||||
{
|
||||
key: 'roleManagement',
|
||||
url: '/rolesManagement',
|
||||
},
|
||||
{
|
||||
key: 'privilegeManagement',
|
||||
url: '/permissionsManagement',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default function(model) {
|
||||
const { token = '{}' } = localStorage;
|
||||
const { globalAdmin } = isJsonString(token) ? JSON.parse(token) || {} : {};
|
||||
|
||||
return [
|
||||
model === 'naming' ? undefined : configurationMenu,
|
||||
{
|
||||
key: 'serviceManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'serviceManagement',
|
||||
url: '/serviceManagement',
|
||||
},
|
||||
{
|
||||
key: 'subscriberList',
|
||||
url: '/subscriberList',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'clusterManagementVirtual',
|
||||
children: [
|
||||
{
|
||||
key: 'clusterManagement',
|
||||
url: '/clusterManagement',
|
||||
},
|
||||
],
|
||||
},
|
||||
globalAdmin ? authorityControlMenu : undefined,
|
||||
{
|
||||
key: 'namespace',
|
||||
url: '/namespace',
|
||||
},
|
||||
].filter(item => item);
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, Form, Input, Select, Dialog, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getNamespaces } from '../../../reducers/namespace';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 4 },
|
||||
wrapperCol: { span: 19 },
|
||||
};
|
||||
|
||||
@connect(state => ({ namespaces: state.namespace.namespaces }), { getNamespaces })
|
||||
@ConfigProvider.config
|
||||
class NewPermissions extends React.Component {
|
||||
static displayName = 'NewPermissions';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
getNamespaces: PropTypes.func,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
namespaces: PropTypes.array,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getNamespaces();
|
||||
}
|
||||
|
||||
check() {
|
||||
const { locale } = this.props;
|
||||
const errors = {
|
||||
role: locale.roleError,
|
||||
resource: locale.resourceError,
|
||||
action: locale.actionError,
|
||||
};
|
||||
const vals = Object.keys(errors).map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length === 3) {
|
||||
return vals;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getError } = this.field;
|
||||
const { visible, onOk, onCancel, locale, namespaces } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title={locale.addPermission}
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label={locale.role} required help={getError('role')}>
|
||||
<Input name="role" trim placeholder={locale.rolePlaceholder} />
|
||||
</FormItem>
|
||||
<FormItem label={locale.resource} required help={getError('resource')}>
|
||||
<Select
|
||||
name="resource"
|
||||
placeholder={locale.resourcePlaceholder}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{namespaces.map(({ namespace, namespaceShowName }) => (
|
||||
<Option value={`${namespace}:*:*`}>
|
||||
{namespaceShowName} {namespace ? `(${namespace})` : ''}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label={locale.action} required help={getError('action')}>
|
||||
<Select
|
||||
name="action"
|
||||
placeholder={locale.actionPlaceholder}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<Option value="r">{locale.readOnly}(r)</Option>
|
||||
<Option value="w">{locale.writeOnly}(w)</Option>
|
||||
<Option value="rw">{locale.readWrite}(rw)</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewPermissions;
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Dialog, Pagination, Table, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getPermissions, createPermission, deletePermission } from '../../../reducers/authority';
|
||||
import { getNamespaces } from '../../../reducers/namespace';
|
||||
import RegionGroup from '../../../components/RegionGroup';
|
||||
import NewPermissions from './NewPermissions';
|
||||
|
||||
import './PermissionsManagement.scss';
|
||||
|
||||
@connect(
|
||||
state => ({
|
||||
permissions: state.authority.permissions,
|
||||
namespaces: state.namespace.namespaces,
|
||||
}),
|
||||
{ getPermissions, getNamespaces }
|
||||
)
|
||||
@ConfigProvider.config
|
||||
class PermissionsManagement extends React.Component {
|
||||
static displayName = 'PermissionsManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
permissions: PropTypes.object,
|
||||
namespaces: PropTypes.object,
|
||||
getPermissions: PropTypes.func,
|
||||
getNamespaces: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
pageNo: 1,
|
||||
pageSize: 9,
|
||||
createPermission: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getPermissions();
|
||||
this.props.getNamespaces();
|
||||
}
|
||||
|
||||
getPermissions() {
|
||||
const { pageNo, pageSize } = this.state;
|
||||
this.props
|
||||
.getPermissions({ pageNo, pageSize })
|
||||
.then(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
})
|
||||
.catch(() => this.setState({ loading: false }));
|
||||
}
|
||||
|
||||
colseCreatePermission() {
|
||||
this.setState({ createPermissionVisible: false });
|
||||
}
|
||||
|
||||
getActionText(action) {
|
||||
const { locale } = this.props;
|
||||
return {
|
||||
r: `${locale.readOnly} (r)`,
|
||||
w: `${locale.writeOnly} (w)`,
|
||||
rw: `${locale.readWrite} (rw)`,
|
||||
}[action];
|
||||
}
|
||||
|
||||
render() {
|
||||
const { permissions, namespaces = [], locale } = this.props;
|
||||
const { loading, pageSize, pageNo, createPermissionVisible } = this.state;
|
||||
return (
|
||||
<>
|
||||
<RegionGroup left={locale.privilegeManagement} />
|
||||
<div className="filter-panel">
|
||||
<Button type="primary" onClick={() => this.setState({ createPermissionVisible: true })}>
|
||||
{locale.addPermission}
|
||||
</Button>
|
||||
</div>
|
||||
<Table dataSource={permissions.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
|
||||
<Table.Column title={locale.role} dataIndex="role" />
|
||||
<Table.Column
|
||||
title={locale.resource}
|
||||
dataIndex="resource"
|
||||
cell={value => {
|
||||
const [item = {}] = namespaces.filter(({ namespace }) => {
|
||||
const [itemNamespace] = value.split(':');
|
||||
return itemNamespace === namespace;
|
||||
});
|
||||
const { namespaceShowName = '', namespace = '' } = item;
|
||||
return namespaceShowName + (namespace ? ` (${namespace})` : '');
|
||||
}}
|
||||
/>
|
||||
<Table.Column
|
||||
title={locale.action}
|
||||
dataIndex="action"
|
||||
cell={action => this.getActionText(action)}
|
||||
/>
|
||||
<Table.Column
|
||||
title={locale.operation}
|
||||
cell={(value, index, record) => (
|
||||
<>
|
||||
<Button
|
||||
type="primary"
|
||||
warning
|
||||
onClick={() =>
|
||||
Dialog.confirm({
|
||||
title: locale.deletePermission,
|
||||
content: locale.deletePermissionTip,
|
||||
onOk: () =>
|
||||
deletePermission(record).then(() => {
|
||||
this.setState({ pageNo: 1 }, () => this.getPermissions());
|
||||
}),
|
||||
})
|
||||
}
|
||||
>
|
||||
{locale.deletePermission}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
{permissions.totalCount > pageSize && (
|
||||
<Pagination
|
||||
className="users-pagination"
|
||||
current={pageNo}
|
||||
total={permissions.totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={pageNo => this.setState({ pageNo }, () => this.getPermissions())}
|
||||
/>
|
||||
)}
|
||||
<NewPermissions
|
||||
visible={createPermissionVisible}
|
||||
onOk={permission =>
|
||||
createPermission(permission).then(res => {
|
||||
this.setState({ pageNo: 1 }, () => this.getPermissions());
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.colseCreatePermission()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PermissionsManagement;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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.
|
||||
*/
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 PermissionsManagement from './PermissionsManagement';
|
||||
|
||||
export default PermissionsManagement;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# 权限控制
|
||||
|
||||
> AuthorityControl
|
||||
|
||||
1. UserManagement => 用户管理
|
||||
2. RolesManagement => 角色管理
|
||||
3. PermissionsManagement => 权限管理
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, Form, Input, Dialog, ConfigProvider } from '@alifd/next';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 4 },
|
||||
wrapperCol: { span: 19 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class NewRole extends React.Component {
|
||||
static displayName = 'NewRole';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
};
|
||||
|
||||
check() {
|
||||
const { locale } = this.props;
|
||||
const errors = {
|
||||
role: locale.roleError,
|
||||
username: locale.usernameError,
|
||||
};
|
||||
const vals = Object.keys(errors).map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length === 2) {
|
||||
return vals;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale } = this.props;
|
||||
const { getError } = this.field;
|
||||
const { visible, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title={locale.bindingRoles}
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label={locale.role} required help={getError('role')}>
|
||||
<Input name="role" trim placeholder={locale.rolePlaceholder} />
|
||||
</FormItem>
|
||||
<FormItem label={locale.username} required help={getError('username')}>
|
||||
<Input name="username" placeholder={locale.usernamePlaceholder} />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewRole;
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Dialog, Pagination, Table, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getRoles, createRole, deleteRole } from '../../../reducers/authority';
|
||||
import RegionGroup from '../../../components/RegionGroup';
|
||||
import NewRole from './NewRole';
|
||||
|
||||
import './RolesManagement.scss';
|
||||
|
||||
@connect(state => ({ roles: state.authority.roles }), { getRoles })
|
||||
@ConfigProvider.config
|
||||
class RolesManagement extends React.Component {
|
||||
static displayName = 'RolesManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
roles: PropTypes.object,
|
||||
getRoles: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
pageNo: 1,
|
||||
pageSize: 9,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getRoles();
|
||||
}
|
||||
|
||||
getRoles() {
|
||||
const { pageNo, pageSize } = this.state;
|
||||
this.props
|
||||
.getRoles({ pageNo, pageSize })
|
||||
.then(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
})
|
||||
.catch(() => this.setState({ loading: false }));
|
||||
}
|
||||
|
||||
colseCreateRole() {
|
||||
this.setState({ createRoleVisible: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { roles, locale } = this.props;
|
||||
const { loading, pageSize, pageNo, createRoleVisible, passwordResetUser } = this.state;
|
||||
return (
|
||||
<>
|
||||
<RegionGroup left={locale.roleManagement} />
|
||||
<div className="filter-panel">
|
||||
<Button type="primary" onClick={() => this.setState({ createRoleVisible: true })}>
|
||||
{locale.bindingRoles}
|
||||
</Button>
|
||||
</div>
|
||||
<Table dataSource={roles.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
|
||||
<Table.Column title={locale.role} dataIndex="role" />
|
||||
<Table.Column title={locale.username} dataIndex="username" />
|
||||
<Table.Column
|
||||
title={locale.operation}
|
||||
dataIndex="role"
|
||||
cell={(value, index, record) => {
|
||||
if (value === 'ROLE_ADMIN') {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
type="primary"
|
||||
warning
|
||||
onClick={() =>
|
||||
Dialog.confirm({
|
||||
title: locale.deleteRole,
|
||||
content: locale.deleteRoleTip,
|
||||
onOk: () =>
|
||||
deleteRole(record).then(() => {
|
||||
this.setState({ pageNo: 1 }, () => this.getRoles());
|
||||
}),
|
||||
})
|
||||
}
|
||||
>
|
||||
{locale.deleteRole}
|
||||
</Button>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Table>
|
||||
{roles.totalCount > pageSize && (
|
||||
<Pagination
|
||||
className="users-pagination"
|
||||
current={pageNo}
|
||||
total={roles.totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={pageNo => this.setState({ pageNo }, () => this.getRoles())}
|
||||
/>
|
||||
)}
|
||||
<NewRole
|
||||
visible={createRoleVisible}
|
||||
onOk={role =>
|
||||
createRole(role).then(res => {
|
||||
this.getRoles();
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.colseCreateRole()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RolesManagement;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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.
|
||||
*/
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 RolesManagement from './RolesManagement';
|
||||
|
||||
export default RolesManagement;
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, Form, Input, Dialog, ConfigProvider } from '@alifd/next';
|
||||
import './UserManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 4 },
|
||||
wrapperCol: { span: 19 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class NewUser extends React.Component {
|
||||
static displayName = 'NewUser';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
};
|
||||
|
||||
check() {
|
||||
const { locale } = this.props;
|
||||
const errors = {
|
||||
username: locale.usernameError,
|
||||
password: locale.passwordError,
|
||||
rePassword: locale.rePasswordError,
|
||||
};
|
||||
const vals = Object.keys(errors).map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length !== 3) {
|
||||
return null;
|
||||
}
|
||||
const [password, rePassword] = ['password', 'rePassword'].map(k => this.field.getValue(k));
|
||||
if (password !== rePassword) {
|
||||
this.field.setError('rePassword', locale.rePasswordError2);
|
||||
return null;
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale } = this.props;
|
||||
const { getError } = this.field;
|
||||
const { visible, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title={locale.createUser}
|
||||
visible={visible}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label={locale.username} required help={getError('username')}>
|
||||
<Input name="username" trim placeholder={locale.usernamePlaceholder} />
|
||||
</FormItem>
|
||||
<FormItem label={locale.password} required help={getError('password')}>
|
||||
<Input name="password" htmlType="password" placeholder={locale.passwordPlaceholder} />
|
||||
</FormItem>
|
||||
<FormItem label={locale.rePassword} required help={getError('rePassword')}>
|
||||
<Input
|
||||
name="rePassword"
|
||||
htmlType="password"
|
||||
placeholder={locale.rePasswordPlaceholder}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewUser;
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, Form, Input, Dialog, ConfigProvider } from '@alifd/next';
|
||||
import './UserManagement.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 4 },
|
||||
wrapperCol: { span: 19 },
|
||||
};
|
||||
|
||||
@ConfigProvider.config
|
||||
class PasswordReset extends React.Component {
|
||||
static displayName = 'PasswordReset';
|
||||
|
||||
field = new Field(this);
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
visible: PropTypes.bool,
|
||||
username: PropTypes.string,
|
||||
onCancel: PropTypes.func,
|
||||
onOk: PropTypes.func,
|
||||
};
|
||||
|
||||
check() {
|
||||
const { locale } = this.props;
|
||||
const errors = {
|
||||
password: locale.passwordError,
|
||||
rePassword: locale.rePasswordError,
|
||||
};
|
||||
const vals = Object.keys(errors).map(key => {
|
||||
const val = this.field.getValue(key);
|
||||
if (!val) {
|
||||
this.field.setError(key, errors[key]);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
if (vals.filter(v => v).length !== 2) {
|
||||
return null;
|
||||
}
|
||||
const [password, rePassword] = ['password', 'rePassword'].map(k => this.field.getValue(k));
|
||||
if (password !== rePassword) {
|
||||
this.field.setError('rePassword', locale.rePasswordError2);
|
||||
return null;
|
||||
}
|
||||
return [this.props.username, ...vals];
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale } = this.props;
|
||||
const { getError } = this.field;
|
||||
const { username, onOk, onCancel } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
title={locale.resetPassword}
|
||||
visible={username}
|
||||
onOk={() => {
|
||||
const vals = this.check();
|
||||
if (vals) {
|
||||
onOk(vals).then(() => onCancel());
|
||||
}
|
||||
}}
|
||||
onClose={onCancel}
|
||||
onCancel={onCancel}
|
||||
afterClose={() => this.field.reset()}
|
||||
>
|
||||
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
|
||||
<FormItem label={locale.username} required>
|
||||
<p>{username}</p>
|
||||
</FormItem>
|
||||
<FormItem label={locale.password} required help={getError('password')}>
|
||||
<Input name="password" htmlType="password" placeholder={locale.passwordPlaceholder} />
|
||||
</FormItem>
|
||||
<FormItem label={locale.rePassword} required help={getError('rePassword')}>
|
||||
<Input
|
||||
name="rePassword"
|
||||
htmlType="password"
|
||||
placeholder={locale.rePasswordPlaceholder}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PasswordReset;
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Dialog, Pagination, Table, ConfigProvider } from '@alifd/next';
|
||||
import { connect } from 'react-redux';
|
||||
import { getUsers, createUser, deleteUser, passwordReset } from '../../../reducers/authority';
|
||||
import RegionGroup from '../../../components/RegionGroup';
|
||||
import NewUser from './NewUser';
|
||||
import PasswordReset from './PasswordReset';
|
||||
|
||||
import './UserManagement.scss';
|
||||
|
||||
@connect(state => ({ users: state.authority.users }), { getUsers })
|
||||
@ConfigProvider.config
|
||||
class UserManagement extends React.Component {
|
||||
static displayName = 'UserManagement';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
users: PropTypes.object,
|
||||
getUsers: PropTypes.func,
|
||||
createUser: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
pageNo: 1,
|
||||
pageSize: 9,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getUsers();
|
||||
}
|
||||
|
||||
getUsers() {
|
||||
const { pageNo, pageSize } = this.state;
|
||||
this.props
|
||||
.getUsers({ pageNo, pageSize })
|
||||
.then(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
})
|
||||
.catch(() => this.setState({ loading: false }));
|
||||
}
|
||||
|
||||
colseCreateUser() {
|
||||
this.setState({ createUserVisible: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users, locale } = this.props;
|
||||
const { loading, pageSize, pageNo, createUserVisible, passwordResetUser } = this.state;
|
||||
return (
|
||||
<>
|
||||
<RegionGroup left={locale.userManagement} />
|
||||
<div className="filter-panel">
|
||||
<Button type="primary" onClick={() => this.setState({ createUserVisible: true })}>
|
||||
{locale.createUser}
|
||||
</Button>
|
||||
</div>
|
||||
<Table dataSource={users.pageItems} loading={loading} maxBodyHeight={476} fixedHeader>
|
||||
<Table.Column title={locale.username} dataIndex="username" />
|
||||
<Table.Column
|
||||
title={locale.password}
|
||||
dataIndex="password"
|
||||
cell={value => value.replace(/\S/g, '*')}
|
||||
/>
|
||||
<Table.Column
|
||||
title={locale.operation}
|
||||
dataIndex="username"
|
||||
cell={username => (
|
||||
<>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.setState({ passwordResetUser: username })}
|
||||
>
|
||||
{locale.resetPassword}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
warning
|
||||
onClick={() =>
|
||||
Dialog.confirm({
|
||||
title: locale.deleteUser,
|
||||
content: locale.deleteUserTip,
|
||||
onOk: () =>
|
||||
deleteUser(username).then(() => {
|
||||
this.setState({ pageNo: 1 }, () => this.getUsers());
|
||||
}),
|
||||
})
|
||||
}
|
||||
>
|
||||
{locale.deleteUser}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</Table>
|
||||
{users.totalCount > pageSize && (
|
||||
<Pagination
|
||||
className="users-pagination"
|
||||
current={pageNo}
|
||||
total={users.totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={pageNo => this.setState({ pageNo }, () => this.getUsers())}
|
||||
/>
|
||||
)}
|
||||
<NewUser
|
||||
visible={createUserVisible}
|
||||
onOk={user =>
|
||||
createUser(user).then(res => {
|
||||
this.setState({ pageNo: 1 }, () => this.getUsers());
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.colseCreateUser()}
|
||||
/>
|
||||
<PasswordReset
|
||||
username={passwordResetUser}
|
||||
onOk={user =>
|
||||
passwordReset(user).then(res => {
|
||||
this.getUsers();
|
||||
return res;
|
||||
})
|
||||
}
|
||||
onCancel={() => this.setState({ passwordResetUser: undefined })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserManagement;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 '../authority.scss';
|
||||
|
||||
.users-pagination {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 UserManagement from './UserManagement';
|
||||
|
||||
export default UserManagement;
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.filter-panel {
|
||||
text-align: right;
|
||||
padding: 10px 0;
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 { Message } from '@alifd/next';
|
||||
import request from '../utils/request';
|
||||
import { UPDATE_USER, SIGN_IN, USER_LIST, ROLE_LIST, PERMISSIONS_LIST } from '../constants';
|
||||
|
||||
const initialState = {
|
||||
users: {
|
||||
totalCount: 0,
|
||||
pageNumber: 1,
|
||||
pagesAvailable: 1,
|
||||
pageItems: [],
|
||||
},
|
||||
roles: {
|
||||
totalCount: 0,
|
||||
pageNumber: 1,
|
||||
pagesAvailable: 1,
|
||||
pageItems: [],
|
||||
},
|
||||
permissions: {
|
||||
totalCount: 0,
|
||||
pageNumber: 1,
|
||||
pagesAvailable: 1,
|
||||
pageItems: [],
|
||||
},
|
||||
};
|
||||
|
||||
const successMsg = res => {
|
||||
if (res.code === 200) {
|
||||
Message.success(res.message);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户列表
|
||||
* @param {*} params
|
||||
*/
|
||||
const getUsers = params => dispatch =>
|
||||
request.get('v1/auth/users', { params }).then(data => dispatch({ type: USER_LIST, data }));
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
* @param {*} param0
|
||||
*/
|
||||
const createUser = ([username, password]) =>
|
||||
request.post('v1/auth/users', { username, password }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param {*} username
|
||||
*/
|
||||
const deleteUser = username =>
|
||||
request.delete('v1/auth/users', { params: { username } }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
* @param {*} param0
|
||||
*/
|
||||
const passwordReset = ([username, newPassword]) =>
|
||||
request.put('v1/auth/users', { username, newPassword }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
* @param {*} params
|
||||
*/
|
||||
|
||||
const getRoles = params => dispatch =>
|
||||
request.get('v1/auth/roles', { params }).then(data => dispatch({ type: ROLE_LIST, data }));
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
* @param {*} param0
|
||||
*/
|
||||
const createRole = ([role, username]) =>
|
||||
request.post('v1/auth/roles', { role, username }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param {*} param0
|
||||
*/
|
||||
const deleteRole = role =>
|
||||
request.delete('v1/auth/roles', { params: role }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
* @param {*} params
|
||||
*/
|
||||
const getPermissions = params => dispatch =>
|
||||
request
|
||||
.get('v1/auth/permissions', { params })
|
||||
.then(data => dispatch({ type: PERMISSIONS_LIST, data }));
|
||||
|
||||
/**
|
||||
* 给角色添加权限
|
||||
* @param {*} param0
|
||||
*/
|
||||
const createPermission = ([role, resource, action]) =>
|
||||
request.post('v1/auth/permissions', { role, resource, action }).then(res => successMsg(res));
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
* @param {*} param0
|
||||
*/
|
||||
const deletePermission = permission =>
|
||||
request.delete('v1/auth/permissions', { params: permission }).then(res => successMsg(res));
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case USER_LIST:
|
||||
return { ...state, users: { ...action.data } };
|
||||
case ROLE_LIST:
|
||||
return { ...state, roles: { ...action.data } };
|
||||
case PERMISSIONS_LIST:
|
||||
return { ...state, permissions: { ...action.data } };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
getUsers,
|
||||
createUser,
|
||||
deleteUser,
|
||||
passwordReset,
|
||||
getRoles,
|
||||
createRole,
|
||||
deleteRole,
|
||||
getPermissions,
|
||||
createPermission,
|
||||
deletePermission,
|
||||
};
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 request from '../utils/request';
|
||||
import { GET_CONFIGURATION } from '../constants';
|
||||
|
||||
const initialState = {
|
||||
configurations: [],
|
||||
};
|
||||
|
||||
const getConfigs = params => dispatch =>
|
||||
request
|
||||
.get('v1/cs/configs', { params })
|
||||
.then(data => dispatch({ type: GET_CONFIGURATION, data }));
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GET_CONFIGURATION:
|
||||
return { ...state, configurations: action.data };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { getConfigs };
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* 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 request from '../utils/request';
|
||||
import { GET_NAMESPACES } from '../constants';
|
||||
|
||||
const initialState = {
|
||||
namespaces: [],
|
||||
};
|
||||
|
||||
const getNamespaces = params => dispatch =>
|
||||
request.get('v1/console/namespaces', { params }).then(response => {
|
||||
const { code, data } = response;
|
||||
dispatch({
|
||||
type: GET_NAMESPACES,
|
||||
data: code === 200 ? data : [],
|
||||
});
|
||||
});
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GET_NAMESPACES:
|
||||
return { ...state, namespaces: action.data };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { getNamespaces };
|
||||
Reference in new issue
Block a user