Implement add users to roles

pull/10616/head
Andrew Watkins 2017-03-09 10:53:53 -08:00
parent e7c4b297c0
commit 20c68fae84
7 changed files with 87 additions and 34 deletions

View File

@ -4,8 +4,11 @@ import {
createUser as createUserAJAX,
deleteRole as deleteRoleAJAX,
deleteUser as deleteUserAJAX,
addUsersToRole as addUsersToRoleAJAX,
} from 'src/admin/apis'
import {killQuery as killQueryProxy} from 'shared/apis/metaQuery'
import {publishNotification} from 'src/shared/actions/notifications';
import {publishNotification} from 'src/shared/actions/notifications';
@ -141,3 +144,12 @@ export const deleteUserAsync = (user, addFlashMessage) => (dispatch) => {
// delete user on server
deleteUserAJAX(user.links.self, addFlashMessage, user.name)
}
export const addUsersToRoleAsync = (users, role) => async (dispatch) => {
try {
await addUsersToRoleAJAX(role.links.self, users)
dispatch(publishNotification('success', 'Role upated successfully'))
} catch (error) {
dispatch(publishNotification('error', `Failed to update role: ${error.data.message}`))
}
}

View File

@ -73,3 +73,17 @@ export const deleteUser = async (url, addFlashMessage, username) => {
})
}
}
export const addUsersToRole = async (url, users) => {
try {
await AJAX({
method: 'PATCH',
url,
data: {
users,
},
})
} catch (error) {
console.error(error)
}
}

View File

@ -18,6 +18,7 @@ const AdminTabs = ({
onDeleteUser,
onFilterRoles,
onFilterUsers,
onAddUsersToRole,
}) => {
const hasRoles = !!source.links.roles
@ -39,7 +40,7 @@ const AdminTabs = ({
},
{
type: 'Roles',
component: (<RolesTable roles={roles} allUsers={users} onDelete={onDeleteRole} onFilter={onFilterRoles} />),
component: (<RolesTable roles={roles} allUsers={users} onDelete={onDeleteRole} onFilter={onFilterRoles} onAddUsersToRole={onAddUsersToRole}/>),
},
{
type: 'Queries',
@ -94,6 +95,7 @@ AdminTabs.propTypes = {
onDeleteUser: func.isRequired,
onFilterRoles: func.isRequired,
onFilterUsers: func.isRequired,
onAddUsersToRole: func.isRequired,
}
export default AdminTabs

View File

@ -26,37 +26,50 @@ const PERMISSIONS = [
"KapacitorConfigAPI",
]
const RoleRow = ({role: {name, permissions, users}, role, allUsers, onDelete}) => (
<tr>
<td>{name}</td>
<td>
{
permissions && permissions.length ?
<MultiSelectDropdown
items={PERMISSIONS}
selectedItems={_.get(permissions, ['0', 'allowed'], [])}
label={'Select Permissions'}
onApply={() => '//TODO'}
/> :
'\u2014'
}
</td>
<td>
{
allUsers && allUsers.length ?
<MultiSelectDropdown
items={allUsers.map((u) => u.name)}
selectedItems={users.map((u) => u.name)}
onApply={() => '//TODO'}
/> :
'\u2014'
}
</td>
<td className="text-right" style={{width: "85px"}}>
<DeleteRow onDelete={onDelete} item={role} />
</td>
</tr>
)
const RoleRow = ({
role: {name, permissions, users},
role,
allUsers,
onDelete,
onAddUsersToRole,
}) => {
const wrapUsers = (u) => {
const updatedUsers = u.map((n) => {
return {name: n}
})
onAddUsersToRole(updatedUsers, role)
}
return (
<tr>
<td>{name}</td>
<td>
{
permissions && permissions.length ?
<MultiSelectDropdown
items={PERMISSIONS}
selectedItems={_.get(permissions, ['0', 'allowed'], [])}
label={'Select Permissions'}
onApply={() => '// TODO'}
/> : '\u2014'
}
</td>
<td>
{
allUsers && allUsers.length ?
<MultiSelectDropdown
items={allUsers.map((u) => u.name)}
selectedItems={users.map((u) => u.name)}
onApply={wrapUsers}
/> : '\u2014'
}
</td>
<td className="text-right" style={{width: "85px"}}>
<DeleteRow onDelete={onDelete} item={role} />
</td>
</tr>
)
}
const {
arrayOf,
@ -77,6 +90,7 @@ RoleRow.propTypes = {
}).isRequired,
onDelete: func.isRequired,
allUsers: arrayOf(shape()),
onAddUsersToRole: func.isRequired,
}
export default RoleRow

View File

@ -3,7 +3,7 @@ import RoleRow from 'src/admin/components/RoleRow'
import EmptyRow from 'src/admin/components/EmptyRow'
import FilterBar from 'src/admin/components/FilterBar'
const RolesTable = ({roles, allUsers, onDelete, onFilter}) => (
const RolesTable = ({roles, allUsers, onDelete, onFilter, onAddUsersToRole}) => (
<div className="panel panel-info">
<FilterBar type="roles" onFilter={onFilter} />
<div className="panel-body">
@ -20,7 +20,7 @@ const RolesTable = ({roles, allUsers, onDelete, onFilter}) => (
{
roles.length ?
roles.filter(r => !r.hidden).map((role) =>
<RoleRow key={role.name} allUsers={allUsers} role={role} onDelete={onDelete} />
<RoleRow key={role.name} allUsers={allUsers} role={role} onDelete={onDelete} onAddUsersToRole={onAddUsersToRole}/>
) : <EmptyRow tableName={'Roles'} />
}
</tbody>
@ -50,6 +50,7 @@ RolesTable.propTypes = {
onDelete: func.isRequired,
onFilter: func,
allUsers: arrayOf(shape()),
onAddUsersToRole: func.isRequired,
}
export default RolesTable

View File

@ -10,6 +10,7 @@ import {
createUserAsync,
deleteRoleAsync,
deleteUserAsync,
addUsersToRoleAsync,
filterRoles as filterRolesAction,
filterUsers as filterUsersAction,
} from 'src/admin/actions'
@ -30,6 +31,7 @@ class AdminPage extends Component {
this.handleCancelEdit = ::this.handleCancelEdit
this.handleDeleteRole = ::this.handleDeleteRole
this.handleDeleteUser = ::this.handleDeleteUser
this.handleAddUsersToRole = ::this.handleAddUsersToRole
}
componentDidMount() {
@ -76,6 +78,10 @@ class AdminPage extends Component {
this.props.deleteUser(user, this.props.addFlashMessage)
}
handleAddUsersToRole(users, role) {
this.props.addUsersToRole(users, role)
}
render() {
const {users, roles, source, filterUsers, filterRoles, addFlashMessage} = this.props
@ -109,6 +115,7 @@ class AdminPage extends Component {
onFilterUsers={filterUsers}
onFilterRoles={filterRoles}
addFlashMessage={addFlashMessage}
onAddUsersToRole={this.handleAddUsersToRole}
/> :
<span>Loading...</span>
}
@ -147,6 +154,7 @@ AdminPage.propTypes = {
addFlashMessage: func,
filterRoles: func,
filterUsers: func,
addUsersToRole: func,
}
const mapStateToProps = ({admin: {users, roles}}) => ({
@ -165,6 +173,7 @@ const mapDispatchToProps = (dispatch) => ({
deleteUser: bindActionCreators(deleteUserAsync, dispatch),
filterRoles: bindActionCreators(filterRolesAction, dispatch),
filterUsers: bindActionCreators(filterUsersAction, dispatch),
addUsersToRole: bindActionCreators(addUsersToRoleAsync, dispatch),
})
export default connect(mapStateToProps, mapDispatchToProps)(AdminPage)

View File

@ -10,6 +10,7 @@ const labelText = ({localSelectedItems, isOpen, label}) => {
return localSelectedItems.map((s) => s).join(', ')
}
// TODO: be smarter about the text displayed here
if (isOpen) {
return '0 Selected'
}