Reorient AllUsersTable around organizations, not roles
Use new links.rawUsers route to get users for AllUsersPage. Introduce '*' role name to tell server to assign org defaultRole. Update table header to display number of users & num orgs. Remove concept of roles from AllUsers UI. Note: The update & create AJAX are both broken or disabled until the server is modified to accept '*' for role.pull/10616/head
parent
4c33cf7846
commit
6728ec5d82
|
@ -36,12 +36,7 @@ const AdminTabs = ({
|
|||
{
|
||||
requiredRole: SUPERADMIN_ROLE,
|
||||
type: ALL_USERS_TAB_NAME,
|
||||
component: (
|
||||
<AllUsersPage
|
||||
meID={meID}
|
||||
meCurrentOrganization={meCurrentOrganization}
|
||||
/>
|
||||
),
|
||||
component: <AllUsersPage meID={meID} />,
|
||||
},
|
||||
].filter(t => isUserAuthorized(meRole, t.requiredRole))
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ class AllUsersTable extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleChangeUserRole = (user, currentRole) => newRole => {
|
||||
this.props.onUpdateUserRole(user, currentRole, newRole)
|
||||
handleAddUserToOrganization = user => newOrganization => {
|
||||
console.log('handleAddUserToOrganization', user.name, newOrganization.id)
|
||||
// const newOrganizationRole = newOrganization + newOrganizationDefaultRole -- need to get this fresh from server or have server determine it, which requires a change to ValidUpdate
|
||||
// this.props.onUpdateUserRole(user, newOrganizationRole)
|
||||
}
|
||||
|
||||
handleChangeSuperAdmin = user => newStatus => {
|
||||
|
@ -38,7 +40,7 @@ class AllUsersTable extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {organization, users, onCreateUser, meID, notify} = this.props
|
||||
const {users, organizations, onCreateUser, meID, notify} = this.props
|
||||
|
||||
const {isCreatingUser} = this.state
|
||||
const {
|
||||
|
@ -53,9 +55,9 @@ class AllUsersTable extends Component {
|
|||
<div className="panel panel-default">
|
||||
<AllUsersTableHeader
|
||||
numUsers={users.length}
|
||||
numOrganizations={organizations.length}
|
||||
onClickCreateUser={this.handleClickCreateUser}
|
||||
isCreatingUser={isCreatingUser}
|
||||
organization={organization}
|
||||
/>
|
||||
<div className="panel-body">
|
||||
<table className="table table-highlight v-center chronograf-admin-table">
|
||||
|
@ -76,7 +78,7 @@ class AllUsersTable extends Component {
|
|||
<tbody>
|
||||
{isCreatingUser
|
||||
? <AllUsersTableRowNew
|
||||
organization={organization}
|
||||
organizations={organizations}
|
||||
onBlur={this.handleBlurCreateUserRow}
|
||||
onCreateUser={onCreateUser}
|
||||
notify={notify}
|
||||
|
@ -87,8 +89,8 @@ class AllUsersTable extends Component {
|
|||
<AllUsersTableRow
|
||||
user={user}
|
||||
key={uuid.v4()}
|
||||
organization={organization}
|
||||
onChangeUserRole={this.handleChangeUserRole}
|
||||
organizations={organizations}
|
||||
onAddUserToOrganization={this.handleAddUserToOrganization}
|
||||
onChangeSuperAdmin={this.handleChangeSuperAdmin}
|
||||
onDelete={this.handleDeleteUser}
|
||||
meID={meID}
|
||||
|
@ -128,10 +130,12 @@ AllUsersTable.propTypes = {
|
|||
superAdmin: bool,
|
||||
})
|
||||
).isRequired,
|
||||
organization: shape({
|
||||
name: string.isRequired,
|
||||
id: string.isRequired,
|
||||
}),
|
||||
organizations: arrayOf(
|
||||
shape({
|
||||
name: string.isRequired,
|
||||
id: string.isRequired,
|
||||
})
|
||||
),
|
||||
onCreateUser: func.isRequired,
|
||||
onUpdateUserRole: func.isRequired,
|
||||
onUpdateUserSuperAdmin: func.isRequired,
|
||||
|
|
|
@ -1,55 +1,47 @@
|
|||
import React, {Component, PropTypes} from 'react'
|
||||
import React, {PropTypes} from 'react'
|
||||
|
||||
class AllUsersTableHeader extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
const AllUsersTableHeader = ({
|
||||
numUsers,
|
||||
numOrganizations,
|
||||
onClickCreateUser,
|
||||
isCreatingUser,
|
||||
}) => {
|
||||
const numUsersString = `${numUsers} User${numUsers === 1 ? '' : 's'}`
|
||||
const numOrganizationsString = `${numOrganizations} Org${numOrganizations ===
|
||||
1
|
||||
? ''
|
||||
: 's'}`
|
||||
|
||||
render() {
|
||||
const {
|
||||
onClickCreateUser,
|
||||
numUsers,
|
||||
isCreatingUser,
|
||||
organization,
|
||||
} = this.props
|
||||
|
||||
const panelTitle = numUsers === 1 ? `${numUsers} User` : `${numUsers} Users`
|
||||
|
||||
return (
|
||||
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
|
||||
<h2 className="panel-title">
|
||||
{panelTitle} in <em>{organization.name}</em>
|
||||
</h2>
|
||||
<button
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={onClickCreateUser}
|
||||
disabled={isCreatingUser || !onClickCreateUser}
|
||||
>
|
||||
<span className="icon plus" />
|
||||
Create User
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
|
||||
<h2 className="panel-title">
|
||||
{numUsersString} in {numOrganizationsString}
|
||||
</h2>
|
||||
<button
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={onClickCreateUser}
|
||||
disabled={isCreatingUser || !onClickCreateUser}
|
||||
>
|
||||
<span className="icon plus" />
|
||||
Create User
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const {bool, func, shape, string, number} = PropTypes
|
||||
const {bool, func, number} = PropTypes
|
||||
|
||||
AllUsersTableHeader.defaultProps = {
|
||||
numUsers: 0,
|
||||
organization: {
|
||||
name: '',
|
||||
},
|
||||
numOrganizations: 0,
|
||||
isCreatingUser: false,
|
||||
}
|
||||
|
||||
AllUsersTableHeader.propTypes = {
|
||||
numUsers: number.isRequired,
|
||||
numOrganizations: number.isRequired,
|
||||
onClickCreateUser: func,
|
||||
isCreatingUser: bool.isRequired,
|
||||
organization: shape({
|
||||
name: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default AllUsersTableHeader
|
||||
|
|
|
@ -4,26 +4,22 @@ import Dropdown from 'shared/components/Dropdown'
|
|||
import SlideToggle from 'shared/components/SlideToggle'
|
||||
import DeleteConfirmTableCell from 'shared/components/DeleteConfirmTableCell'
|
||||
|
||||
import {USER_ROLES} from 'src/admin/constants/chronografAdmin'
|
||||
import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing'
|
||||
|
||||
const AllUsersTableRow = ({
|
||||
organizations,
|
||||
user,
|
||||
organization,
|
||||
onChangeUserRole,
|
||||
onAddUserToOrganization,
|
||||
onChangeSuperAdmin,
|
||||
onDelete,
|
||||
meID,
|
||||
}) => {
|
||||
const {colRole, colSuperAdmin, colProvider, colScheme} = USERS_TABLE
|
||||
|
||||
const dropdownRolesItems = USER_ROLES.map(r => ({
|
||||
const dropdownOrganizationsItems = organizations.map(r => ({
|
||||
...r,
|
||||
text: r.name,
|
||||
}))
|
||||
const currentRole = user.roles.find(
|
||||
role => role.organization === organization.id
|
||||
)
|
||||
|
||||
const userIsMe = user.id === meID
|
||||
|
||||
|
@ -42,9 +38,9 @@ const AllUsersTableRow = ({
|
|||
<td style={{width: colRole}}>
|
||||
<span className="chronograf-user--role">
|
||||
<Dropdown
|
||||
items={dropdownRolesItems}
|
||||
selected={currentRole.name}
|
||||
onChoose={onChangeUserRole(user, currentRole)}
|
||||
items={dropdownOrganizationsItems}
|
||||
selected={'Add to Organization'}
|
||||
onChoose={onAddUserToOrganization(user)}
|
||||
buttonColor="btn-primary"
|
||||
buttonSize="btn-xs"
|
||||
className="dropdown-stretch"
|
||||
|
@ -76,7 +72,7 @@ const AllUsersTableRow = ({
|
|||
)
|
||||
}
|
||||
|
||||
const {func, shape, string} = PropTypes
|
||||
const {arrayOf, func, shape, string} = PropTypes
|
||||
|
||||
AllUsersTableRow.propTypes = {
|
||||
user: shape(),
|
||||
|
@ -84,10 +80,16 @@ AllUsersTableRow.propTypes = {
|
|||
name: string.isRequired,
|
||||
id: string.isRequired,
|
||||
}),
|
||||
onChangeUserRole: func.isRequired,
|
||||
onAddUserToOrganization: func.isRequired,
|
||||
onChangeSuperAdmin: func.isRequired,
|
||||
onDelete: func.isRequired,
|
||||
meID: string.isRequired,
|
||||
organizations: arrayOf(
|
||||
shape({
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
})
|
||||
),
|
||||
}
|
||||
|
||||
export default AllUsersTableRow
|
||||
|
|
|
@ -3,9 +3,10 @@ import React, {Component, PropTypes} from 'react'
|
|||
import Dropdown from 'shared/components/Dropdown'
|
||||
|
||||
import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing'
|
||||
import {USER_ROLES} from 'src/admin/constants/chronografAdmin'
|
||||
|
||||
class UsersTableRowNew extends Component {
|
||||
const nullOrganization = {id: null, name: 'None'}
|
||||
|
||||
class AllUsersTableRowNew extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
|
@ -13,7 +14,11 @@ class UsersTableRowNew extends Component {
|
|||
name: '',
|
||||
provider: '',
|
||||
scheme: 'oauth2',
|
||||
role: this.props.organization.defaultRole,
|
||||
roles: [
|
||||
{
|
||||
...nullOrganization,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,20 +27,15 @@ class UsersTableRowNew extends Component {
|
|||
}
|
||||
|
||||
handleConfirmCreateUser = () => {
|
||||
const {onBlur, onCreateUser, organization} = this.props
|
||||
const {name, provider, scheme, role, superAdmin} = this.state
|
||||
const {onBlur, onCreateUser} = this.props
|
||||
const {name, provider, scheme, roles, superAdmin} = this.state
|
||||
|
||||
const newUser = {
|
||||
name,
|
||||
provider,
|
||||
scheme,
|
||||
superAdmin,
|
||||
roles: [
|
||||
{
|
||||
name: role,
|
||||
organization: organization.id,
|
||||
},
|
||||
],
|
||||
roles: roles[0].id === null ? [] : roles,
|
||||
}
|
||||
|
||||
onCreateUser(newUser)
|
||||
|
@ -46,8 +46,18 @@ class UsersTableRowNew extends Component {
|
|||
e.target.select()
|
||||
}
|
||||
|
||||
handleSelectRole = newRole => {
|
||||
this.setState({role: newRole.text})
|
||||
handleSelectOrganization = newOrganization => {
|
||||
const newRoles = [
|
||||
newOrganization.id === null
|
||||
? {
|
||||
...nullOrganization,
|
||||
}
|
||||
: {
|
||||
id: newOrganization.id,
|
||||
name: '*', // '*' causes the server to determine the current defaultRole of the selected organization
|
||||
},
|
||||
]
|
||||
this.setState({roles: newRoles})
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
|
@ -70,6 +80,9 @@ class UsersTableRowNew extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {organizations, onBlur} = this.props
|
||||
const {name, provider, scheme, roles} = this.state
|
||||
|
||||
const {
|
||||
colRole,
|
||||
colProvider,
|
||||
|
@ -77,10 +90,18 @@ class UsersTableRowNew extends Component {
|
|||
colSuperAdmin,
|
||||
colActions,
|
||||
} = USERS_TABLE
|
||||
const {onBlur} = this.props
|
||||
const {name, provider, scheme, role} = this.state
|
||||
|
||||
const dropdownRolesItems = USER_ROLES.map(r => ({...r, text: r.name}))
|
||||
const dropdownOrganizationsItems = [
|
||||
{...nullOrganization},
|
||||
...organizations,
|
||||
].map(o => ({
|
||||
...o,
|
||||
text: o.name,
|
||||
}))
|
||||
const selectedRole = dropdownOrganizationsItems.find(
|
||||
o => roles[0].id === o.id
|
||||
)
|
||||
|
||||
const preventCreate = !name || !provider
|
||||
|
||||
return (
|
||||
|
@ -98,9 +119,9 @@ class UsersTableRowNew extends Component {
|
|||
</td>
|
||||
<td style={{width: colRole}}>
|
||||
<Dropdown
|
||||
items={dropdownRolesItems}
|
||||
selected={role}
|
||||
onChoose={this.handleSelectRole}
|
||||
items={dropdownOrganizationsItems}
|
||||
selected={selectedRole.text}
|
||||
onChoose={this.handleSelectOrganization}
|
||||
buttonColor="btn-primary"
|
||||
buttonSize="btn-xs"
|
||||
className="dropdown-stretch"
|
||||
|
@ -145,16 +166,18 @@ class UsersTableRowNew extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
const {func, shape, string} = PropTypes
|
||||
const {arrayOf, func, shape, string} = PropTypes
|
||||
|
||||
UsersTableRowNew.propTypes = {
|
||||
organization: shape({
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
}),
|
||||
AllUsersTableRowNew.propTypes = {
|
||||
organizations: arrayOf(
|
||||
shape({
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
})
|
||||
),
|
||||
onBlur: func.isRequired,
|
||||
onCreateUser: func.isRequired,
|
||||
notify: func.isRequired,
|
||||
}
|
||||
|
||||
export default UsersTableRowNew
|
||||
export default AllUsersTableRowNew
|
||||
|
|
|
@ -52,35 +52,25 @@ class AllUsersPage extends Component {
|
|||
|
||||
await Promise.all([
|
||||
loadOrganizationsAsync(links.organizations),
|
||||
loadUsersAsync(links.users),
|
||||
loadUsersAsync(links.rawUsers),
|
||||
])
|
||||
|
||||
this.setState({isLoading: false})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
meCurrentOrganization,
|
||||
organizations,
|
||||
meID,
|
||||
users,
|
||||
notify,
|
||||
} = this.props
|
||||
const {organizations, meID, users, notify} = this.props
|
||||
const {isLoading} = this.state
|
||||
|
||||
if (isLoading) {
|
||||
return <AllUsersTableEmpty />
|
||||
}
|
||||
|
||||
const organization = organizations.find(
|
||||
o => o.id === meCurrentOrganization.id
|
||||
)
|
||||
|
||||
return (
|
||||
<AllUsersTable
|
||||
meID={meID}
|
||||
users={users}
|
||||
organization={organization}
|
||||
organizations={organizations}
|
||||
onCreateUser={this.handleCreateUser}
|
||||
onUpdateUserRole={this.handleUpdateUserRole}
|
||||
onUpdateUserSuperAdmin={this.handleUpdateUserSuperAdmin}
|
||||
|
@ -98,10 +88,6 @@ AllUsersPage.propTypes = {
|
|||
users: string.isRequired,
|
||||
}),
|
||||
meID: string.isRequired,
|
||||
meCurrentOrganization: shape({
|
||||
id: string.isRequired,
|
||||
name: string.isRequired,
|
||||
}).isRequired,
|
||||
users: arrayOf(shape),
|
||||
organizations: arrayOf(shape),
|
||||
actions: shape({
|
||||
|
|
|
@ -62,6 +62,7 @@ export const getMeAsync = ({shouldResetMe = false} = {}) => async dispatch => {
|
|||
data: me,
|
||||
auth,
|
||||
users,
|
||||
rawUsers,
|
||||
meLink,
|
||||
config,
|
||||
external,
|
||||
|
@ -82,6 +83,7 @@ export const getMeAsync = ({shouldResetMe = false} = {}) => async dispatch => {
|
|||
linksReceived({
|
||||
external,
|
||||
users,
|
||||
rawUsers,
|
||||
organizations,
|
||||
me: meLink,
|
||||
config,
|
||||
|
|
|
@ -15,6 +15,7 @@ const generateResponseWithLinks = (response, newLinks) => {
|
|||
logout,
|
||||
external,
|
||||
users,
|
||||
rawUsers,
|
||||
organizations,
|
||||
me: meLink,
|
||||
config,
|
||||
|
@ -27,6 +28,7 @@ const generateResponseWithLinks = (response, newLinks) => {
|
|||
logoutLink: logout,
|
||||
external,
|
||||
users,
|
||||
rawUsers,
|
||||
organizations,
|
||||
meLink,
|
||||
config,
|
||||
|
|
Loading…
Reference in New Issue