Skip to content

Commit

Permalink
[CE-346] Implement user management page
Browse files Browse the repository at this point in the history
Can create/edit/delete user in user management page.

Change-Id: Ibd1e91afb642528c9fe63fd2c3c0ecb94843fde1
Signed-off-by: Haitao Yue <[email protected]>
  • Loading branch information
hightall committed May 2, 2018
1 parent 981f029 commit 293504d
Show file tree
Hide file tree
Showing 12 changed files with 749 additions and 96 deletions.
10 changes: 5 additions & 5 deletions src/modules/user/management/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@

user_create_parser = reqparse.RequestParser()
user_create_parser.add_argument('username', required=True,
location='form',
location=['form', 'json'],
help='Username for create')
user_create_parser.add_argument('password', required=True,
location='form',
location=['form', 'json'],
help='Password for create')
user_create_parser.add_argument('role', type=int, required=True,
location='form',
location=['form', 'json'],
help='User role for create')
user_create_parser.add_argument('balance', type=int, default=0,
location='form',
location=['form', 'json'],
help='User balance')
user_create_parser.add_argument('active', required=True,
location='form',
location=['form', 'json'],
help='Whether active user when create')


Expand Down
8 changes: 4 additions & 4 deletions src/modules/user/management/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@

user_update_parser = reqparse.RequestParser()
user_update_parser.add_argument('username', required=True,
location='form',
location=['form', 'json'],
help='Username for create')
user_update_parser.add_argument('role', type=int, required=True,
location='form',
location=['form', 'json'],
help='User role for create')
user_update_parser.add_argument('balance', type=int, default=0,
location='form',
location=['form', 'json'],
help='User balance')
user_update_parser.add_argument('active', required=True,
location='form',
location=['form', 'json'],
help='Whether active user when create')


Expand Down
2 changes: 1 addition & 1 deletion src/themes/react/static/dashboard/src/common/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const getRouterData = app => {
),
},
'/user-management': {
component: dynamicWrapper(app, [], () => import('../routes/UserManagement')),
component: dynamicWrapper(app, ['user'], () => import('../routes/UserManagement')),
},
};
// Get name from ./menu.js or just set it in the router data.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import React, { PureComponent, Fragment } from 'react';
import { Table, Alert } from 'antd';
import { defineMessages, FormattedMessage } from 'react-intl';
import styles from './index.less';

const messages = defineMessages({
label: {
selected: {
id: 'Components.StandardTable.Label.Selected',
defaultMessage: 'Selected',
},
total: {
id: 'Components.StandardTable.Label.Total',
defaultMessage: 'Total',
},
item: {
id: 'Components.StandardTable.Label.Item',
defaultMessage: 'Item',
},
},
button: {
clear: {
id: 'Components.StandardTable.Button.Clear',
defaultMessage: 'Clear',
},
},
});

function initTotalList(columns) {
const totalList = [];
columns.forEach(column => {
if (column.needTotal) {
totalList.push({ ...column, total: 0 });
}
});
return totalList;
}

class StandardTable extends PureComponent {
constructor(props) {
super(props);
const { columns } = props;
const needTotalList = initTotalList(columns);

this.state = {
selectedRowKeys: [],
needTotalList,
};
}

componentWillReceiveProps(nextProps) {
// clean state
if (nextProps.selectedRows.length === 0) {
const needTotalList = initTotalList(nextProps.columns);
this.setState({
selectedRowKeys: [],
needTotalList,
});
}
}

handleRowSelectChange = (selectedRowKeys, selectedRows) => {
let needTotalList = [...this.state.needTotalList];
needTotalList = needTotalList.map(item => {
return {
...item,
total: selectedRows.reduce((sum, val) => {
return sum + parseFloat(val[item.dataIndex], 10);
}, 0),
};
});

if (this.props.onSelectRow) {
this.props.onSelectRow(selectedRows);
}

this.setState({ selectedRowKeys, needTotalList });
};

handleTableChange = (pagination, filters, sorter) => {
this.props.onChange(pagination, filters, sorter);
};

cleanSelectedKeys = () => {
this.handleRowSelectChange([], []);
};

render() {
const { selectedRowKeys, needTotalList } = this.state;
const { data: { list, pagination }, loading, columns, rowKey } = this.props;

const paginationProps = {
showSizeChanger: true,
showQuickJumper: true,
...pagination,
};

const rowSelection = {
selectedRowKeys,
onChange: this.handleRowSelectChange,
getCheckboxProps: record => ({
disabled: record.disabled,
}),
};

return (
<div className={styles.standardTable}>
<div className={styles.tableAlert}>
<Alert
message={
<Fragment>
<FormattedMessage {...messages.label.selected} />{' '}
<a style={{ fontWeight: 600 }}>{selectedRowKeys.length}</a>{' '}
<FormattedMessage {...messages.label.item} />&nbsp;&nbsp;
{needTotalList.map(item => (
<span style={{ marginLeft: 8 }} key={item.dataIndex}>
{item.title}
<FormattedMessage {...messages.label.total} />&nbsp;
<span style={{ fontWeight: 600 }}>
{item.render ? item.render(item.total) : item.total}
</span>
</span>
))}
<a onClick={this.cleanSelectedKeys} style={{ marginLeft: 24 }}>
<FormattedMessage {...messages.button.clear} />
</a>
</Fragment>
}
type="info"
showIcon
/>
</div>
<Table
loading={loading}
rowKey={rowKey || 'key'}
rowSelection={rowSelection}
dataSource={list}
columns={columns}
pagination={paginationProps}
onChange={this.handleTableChange}
/>
</div>
);
}
}

export default StandardTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@import '~antd/lib/style/themes/default.less';

.standardTable {
:global {
.ant-table-pagination {
margin-top: 24px;
}
}

.tableAlert {
margin-bottom: 16px;
}
}
24 changes: 23 additions & 1 deletion src/themes/react/static/dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,27 @@
"Chain.Create.Title": "Create New Chain",
"Chain.Create.Validate.Required.Host": "Must select a host",
"Chain.Create.Label.Host": "Host",
"Chain.Create.Label.ChainSize": "Chain Size"
"Chain.Create.Label.ChainSize": "Chain Size",
"Components.StandardTable.Label.Selected": "Selected",
"Components.StandardTable.Label.Total": "Total",
"Components.StandardTable.Label.Item": "Item",
"Components.StandardTable.Button.Clear": "Clear",
"UserManagement.Button.New": "New",
"UserManagement.Button.Edit": "Edit",
"UserManagement.Button.Delete": "Delete",
"UserManagement.Title.Create": "Create new user",
"UserManagement.Title.Edit": "Edit user",
"UserManagement.Label.Name": "Username",
"UserManagement.Label.Password": "Password",
"UserManagement.Label.Active": "Active",
"UserManagement.Label.Balance": "Balance",
"UserManagement.Label.Role": "Role",
"UserManagement.Label.Operate": "Operate",
"UserManagement.Validate.Required.Name": "Please input username",
"UserManagement.Validate.NameExists": "{name} already exists",
"UserManagement.Validate.Required.Password": "Please input password",
"UserManagement.Messages.Operate.Success.Create": "Create user {name} successfully",
"UserManagement.Messages.Operate.Success.Delete": "Delete user {name} successfully",
"UserManagement.Messages.Operate.Success.Update": "Update user {name} successfully",
"UserManagement.Confirm.DeleteUser": "Do you confirm to delete user {name}"
}
24 changes: 23 additions & 1 deletion src/themes/react/static/dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,27 @@
"Chain.Create.Title": "创建新的链",
"Chain.Create.Validate.Required.Host": "必须选择一个主机",
"Chain.Create.Label.Host": "主机",
"Chain.Create.Label.ChainSize": "链大小"
"Chain.Create.Label.ChainSize": "链大小",
"Components.StandardTable.Label.Selected": "已选择",
"Components.StandardTable.Label.Total": "总共",
"Components.StandardTable.Label.Item": "",
"Components.StandardTable.Button.Clear": "清空",
"UserManagement.Button.New": "新建",
"UserManagement.Button.Edit": "编辑",
"UserManagement.Button.Delete": "删除",
"UserManagement.Title.Create": "创建新用户",
"UserManagement.Title.Edit": "编辑用户",
"UserManagement.Label.Name": "用户名",
"UserManagement.Label.Password": "密码",
"UserManagement.Label.Active": "激活",
"UserManagement.Label.Balance": "",
"UserManagement.Label.Role": "角色",
"UserManagement.Label.Operate": "操作",
"UserManagement.Validate.Required.Name": "请输入用户名",
"UserManagement.Validate.NameExists": "{name} 已存在",
"UserManagement.Validate.Required.Password": "请输入密码",
"UserManagement.Messages.Operate.Success.Create": "创建用户 {name} 成功",
"UserManagement.Messages.Operate.Success.Delete": "删除用户 {name} 成功",
"UserManagement.Messages.Operate.Success.Update": "更新用户 {name} 成功",
"UserManagement.Confirm.DeleteUser": "是否确认删除用户 {name}"
}
89 changes: 85 additions & 4 deletions src/themes/react/static/dashboard/src/models/user.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,66 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
import { query as queryUsers, queryCurrent } from '../services/user';
import { message } from 'antd';
import { IntlProvider, defineMessages } from 'react-intl';
import {
query as queryUsers,
queryCurrent,
createUser,
deleteUser,
updateUser,
} from '../services/user';
import { getLocale } from '../utils/utils';

const currentLocale = getLocale();
const intlProvider = new IntlProvider(
{ locale: currentLocale.locale, messages: currentLocale.messages },
{}
);
const { intl } = intlProvider.getChildContext();

const messages = defineMessages({
operate: {
success: {
create: {
id: 'UserManagement.Messages.Operate.Success.Create',
defaultMessage: '创建用户 {name} 成功',
},
edit: {
id: 'UserManagement.Messages.Operate.Success.Update',
defaultMessage: '更新用户 {name} 成功',
},
delete: {
id: 'UserManagement.Messages.Operate.Success.Delete',
defaultMessage: '删除用户 {name} 成功',
},
},
},
});

export default {
namespace: 'user',

state: {
list: [],
users: [],
total: 0,
pageNo: 1,
pageSize: 10,
currentUser: {},
},

effects: {
*fetch(_, { call, put }) {
const response = yield call(queryUsers);
const { pageNo, pageSize, totalCount, result } = response.users;
yield put({
type: 'save',
payload: response,
payload: {
pageNo,
pageSize,
total: totalCount,
users: result,
},
});
},
*fetchCurrent(_, { call, put }) {
Expand All @@ -26,13 +70,50 @@ export default {
payload: response,
});
},
*createUser({ payload }, { call, put }) {
const response = yield call(createUser, payload);
if (response.status === 'OK') {
const values = { name: payload.username };
message.success(intl.formatMessage(messages.operate.success.create, values));
}
yield call(payload.callback);
yield put({
type: 'fetch',
});
},
*deleteUser({ payload }, { call, put }) {
const response = yield call(deleteUser, payload.id);
const jsonResponse = JSON.parse(response);
if (jsonResponse.status === 'OK') {
const values = { name: payload.name };
message.success(intl.formatMessage(messages.operate.success.delete, values));
}
yield put({
type: 'fetch',
});
},
*updateUser({ payload }, { call, put }) {
const response = yield call(updateUser, payload);
if (response.status === 'OK') {
const values = { name: payload.username };
message.success(intl.formatMessage(messages.operate.success.edit, values));
}
yield call(payload.callback);
yield put({
type: 'fetch',
});
},
},

reducers: {
save(state, action) {
const { users, pageNo, pageSize, total } = action.payload;
return {
...state,
list: action.payload,
users,
pageNo,
pageSize,
total,
};
},
saveCurrentUser(state, action) {
Expand Down
Loading

0 comments on commit 293504d

Please sign in to comment.