From 97739e84be4f824afb6446b6be330d3920819c87 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 9 Jan 2018 18:01:15 -0800 Subject: [PATCH] Duplicate UsersPage components into AllUsersPage; remove SuperAdmin --- .../admin/components/chronograf/AdminTabs.js | 6 +- .../components/chronograf/AllUsersTable.js | 143 ++++++++++++++++ .../chronograf/AllUsersTableEmpty.js | 46 +++++ .../chronograf/AllUsersTableHeader.js | 55 ++++++ .../components/chronograf/AllUsersTableRow.js | 93 ++++++++++ .../chronograf/AllUsersTableRowNew.js | 160 ++++++++++++++++++ .../components/chronograf/EmptyUsersTable.js | 15 +- .../admin/components/chronograf/UsersTable.js | 39 +---- .../components/chronograf/UsersTableRow.js | 17 +- .../components/chronograf/UsersTableRowNew.js | 18 +- .../containers/chronograf/AllUsersPage.js | 128 ++++++++++++++ .../admin/containers/chronograf/UsersPage.js | 7 - 12 files changed, 639 insertions(+), 88 deletions(-) create mode 100644 ui/src/admin/components/chronograf/AllUsersTable.js create mode 100644 ui/src/admin/components/chronograf/AllUsersTableEmpty.js create mode 100644 ui/src/admin/components/chronograf/AllUsersTableHeader.js create mode 100644 ui/src/admin/components/chronograf/AllUsersTableRow.js create mode 100644 ui/src/admin/components/chronograf/AllUsersTableRowNew.js create mode 100644 ui/src/admin/containers/chronograf/AllUsersPage.js diff --git a/ui/src/admin/components/chronograf/AdminTabs.js b/ui/src/admin/components/chronograf/AdminTabs.js index 3194ff2fc2..fcc9031650 100644 --- a/ui/src/admin/components/chronograf/AdminTabs.js +++ b/ui/src/admin/components/chronograf/AdminTabs.js @@ -9,6 +9,7 @@ import { import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs' import OrganizationsPage from 'src/admin/containers/chronograf/OrganizationsPage' import UsersPage from 'src/admin/containers/chronograf/UsersPage' +import AllUsersPage from 'src/admin/containers/chronograf/AllUsersPage' const ORGANIZATIONS_TAB_NAME = 'Organizations' const CURRENT_ORG_USERS_TAB_NAME = 'Current Org Users' @@ -36,7 +37,10 @@ const AdminTabs = ({ requiredRole: SUPERADMIN_ROLE, type: ALL_USERS_TAB_NAME, component: ( - + ), }, ].filter(t => isUserAuthorized(meRole, t.requiredRole)) diff --git a/ui/src/admin/components/chronograf/AllUsersTable.js b/ui/src/admin/components/chronograf/AllUsersTable.js new file mode 100644 index 0000000000..d369dc8799 --- /dev/null +++ b/ui/src/admin/components/chronograf/AllUsersTable.js @@ -0,0 +1,143 @@ +import React, {Component, PropTypes} from 'react' + +import uuid from 'node-uuid' + +import AllUsersTableHeader from 'src/admin/components/chronograf/AllUsersTableHeader' +import AllUsersTableRowNew from 'src/admin/components/chronograf/AllUsersTableRowNew' +import AllUsersTableRow from 'src/admin/components/chronograf/AllUsersTableRow' + +import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing' + +class AllUsersTable extends Component { + constructor(props) { + super(props) + + this.state = { + isCreatingUser: false, + } + } + + handleChangeUserRole = (user, currentRole) => newRole => { + this.props.onUpdateUserRole(user, currentRole, newRole) + } + + handleChangeSuperAdmin = user => newStatus => { + this.props.onUpdateUserSuperAdmin(user, newStatus) + } + + handleDeleteUser = user => { + this.props.onDeleteUser(user) + } + + handleClickCreateUser = () => { + this.setState({isCreatingUser: true}) + } + + handleBlurCreateUserRow = () => { + this.setState({isCreatingUser: false}) + } + + render() { + const {organization, users, onCreateUser, meID, notify} = this.props + + const {isCreatingUser} = this.state + const { + colRole, + colSuperAdmin, + colProvider, + colScheme, + colActions, + } = USERS_TABLE + + return ( +
+ +
+ + + + + + + + + + + + {isCreatingUser + ? + : null} + {users.length || !isCreatingUser + ? users.map(user => + + ) + : + + } + +
Username + Role + + SuperAdmin + ProviderScheme +
+

No Users to display

+
+
+
+ ) + } +} + +const {arrayOf, bool, func, shape, string} = PropTypes + +AllUsersTable.propTypes = { + users: arrayOf( + shape({ + id: string, + links: shape({ + self: string.isRequired, + }), + name: string.isRequired, + provider: string.isRequired, + roles: arrayOf( + shape({ + name: string.isRequired, + organization: string.isRequired, + }) + ), + scheme: string.isRequired, + superAdmin: bool, + }) + ).isRequired, + organization: shape({ + name: string.isRequired, + id: string.isRequired, + }), + onCreateUser: func.isRequired, + onUpdateUserRole: func.isRequired, + onUpdateUserSuperAdmin: func.isRequired, + onDeleteUser: func.isRequired, + meID: string.isRequired, + notify: func.isRequired, +} + +export default AllUsersTable diff --git a/ui/src/admin/components/chronograf/AllUsersTableEmpty.js b/ui/src/admin/components/chronograf/AllUsersTableEmpty.js new file mode 100644 index 0000000000..3ded5aea42 --- /dev/null +++ b/ui/src/admin/components/chronograf/AllUsersTableEmpty.js @@ -0,0 +1,46 @@ +import React from 'react' + +import UsersTableHeader from 'src/admin/components/chronograf/UsersTableHeader' + +import Authorized, {SUPERADMIN_ROLE} from 'src/auth/Authorized' + +import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing' + +const EmptyUsersTable = () => { + const { + colRole, + colSuperAdmin, + colProvider, + colScheme, + colActions, + } = USERS_TABLE + + return ( +
+ +
+ + + + + + + + + + + + + +
Username + Role + + SuperAdmin + ProviderScheme +
+
+
+ ) +} + +export default EmptyUsersTable diff --git a/ui/src/admin/components/chronograf/AllUsersTableHeader.js b/ui/src/admin/components/chronograf/AllUsersTableHeader.js new file mode 100644 index 0000000000..f4790980bc --- /dev/null +++ b/ui/src/admin/components/chronograf/AllUsersTableHeader.js @@ -0,0 +1,55 @@ +import React, {Component, PropTypes} from 'react' + +class AllUsersTableHeader extends Component { + constructor(props) { + super(props) + } + + render() { + const { + onClickCreateUser, + numUsers, + isCreatingUser, + organization, + } = this.props + + const panelTitle = numUsers === 1 ? `${numUsers} User` : `${numUsers} Users` + + return ( +
+

+ {panelTitle} in {organization.name} +

+ +
+ ) + } +} + +const {bool, func, shape, string, number} = PropTypes + +AllUsersTableHeader.defaultProps = { + numUsers: 0, + organization: { + name: '', + }, + isCreatingUser: false, +} + +AllUsersTableHeader.propTypes = { + numUsers: number.isRequired, + onClickCreateUser: func, + isCreatingUser: bool.isRequired, + organization: shape({ + name: string.isRequired, + }), +} + +export default AllUsersTableHeader diff --git a/ui/src/admin/components/chronograf/AllUsersTableRow.js b/ui/src/admin/components/chronograf/AllUsersTableRow.js new file mode 100644 index 0000000000..12a1d33393 --- /dev/null +++ b/ui/src/admin/components/chronograf/AllUsersTableRow.js @@ -0,0 +1,93 @@ +import React, {PropTypes} from 'react' + +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 = ({ + user, + organization, + onChangeUserRole, + onChangeSuperAdmin, + onDelete, + meID, +}) => { + const {colRole, colSuperAdmin, colProvider, colScheme} = USERS_TABLE + + const dropdownRolesItems = USER_ROLES.map(r => ({ + ...r, + text: r.name, + })) + const currentRole = user.roles.find( + role => role.organization === organization.id + ) + + const userIsMe = user.id === meID + + return ( + + + {userIsMe + ? + + {user.name} + + : + {user.name} + } + + + + + + + + + + + {user.provider} + + + {user.scheme} + + + + ) +} + +const {func, shape, string} = PropTypes + +AllUsersTableRow.propTypes = { + user: shape(), + organization: shape({ + name: string.isRequired, + id: string.isRequired, + }), + onChangeUserRole: func.isRequired, + onChangeSuperAdmin: func.isRequired, + onDelete: func.isRequired, + meID: string.isRequired, +} + +export default AllUsersTableRow diff --git a/ui/src/admin/components/chronograf/AllUsersTableRowNew.js b/ui/src/admin/components/chronograf/AllUsersTableRowNew.js new file mode 100644 index 0000000000..7ad61b1b13 --- /dev/null +++ b/ui/src/admin/components/chronograf/AllUsersTableRowNew.js @@ -0,0 +1,160 @@ +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 { + constructor(props) { + super(props) + + this.state = { + name: '', + provider: '', + scheme: 'oauth2', + role: this.props.organization.defaultRole, + } + } + + handleInputChange = fieldName => e => { + this.setState({[fieldName]: e.target.value.trim()}) + } + + handleConfirmCreateUser = () => { + const {onBlur, onCreateUser, organization} = this.props + const {name, provider, scheme, role, superAdmin} = this.state + + const newUser = { + name, + provider, + scheme, + superAdmin, + roles: [ + { + name: role, + organization: organization.id, + }, + ], + } + + onCreateUser(newUser) + onBlur() + } + + handleInputFocus = e => { + e.target.select() + } + + handleSelectRole = newRole => { + this.setState({role: newRole.text}) + } + + handleKeyDown = e => { + const {name, provider} = this.state + const preventCreate = !name || !provider + + if (e.key === 'Escape') { + this.props.onBlur() + } + + if (e.key === 'Enter') { + if (preventCreate) { + return this.props.notify( + 'warning', + 'User must have a name and provider' + ) + } + this.handleConfirmCreateUser() + } + } + + render() { + const { + colRole, + colProvider, + colScheme, + 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 preventCreate = !name || !provider + + return ( + + + + + + + + + — + + + + + + + + + + + + + ) + } +} + +const {func, shape, string} = PropTypes + +UsersTableRowNew.propTypes = { + organization: shape({ + id: string.isRequired, + name: string.isRequired, + }), + onBlur: func.isRequired, + onCreateUser: func.isRequired, + notify: func.isRequired, +} + +export default UsersTableRowNew diff --git a/ui/src/admin/components/chronograf/EmptyUsersTable.js b/ui/src/admin/components/chronograf/EmptyUsersTable.js index 3ded5aea42..7434e494e9 100644 --- a/ui/src/admin/components/chronograf/EmptyUsersTable.js +++ b/ui/src/admin/components/chronograf/EmptyUsersTable.js @@ -2,18 +2,10 @@ import React from 'react' import UsersTableHeader from 'src/admin/components/chronograf/UsersTableHeader' -import Authorized, {SUPERADMIN_ROLE} from 'src/auth/Authorized' - import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing' const EmptyUsersTable = () => { - const { - colRole, - colSuperAdmin, - colProvider, - colScheme, - colActions, - } = USERS_TABLE + const {colRole, colProvider, colScheme, colActions} = USERS_TABLE return (
@@ -26,11 +18,6 @@ const EmptyUsersTable = () => { Role - - - SuperAdmin - - Provider Scheme diff --git a/ui/src/admin/components/chronograf/UsersTable.js b/ui/src/admin/components/chronograf/UsersTable.js index 9da6c5d8ea..10656c0415 100644 --- a/ui/src/admin/components/chronograf/UsersTable.js +++ b/ui/src/admin/components/chronograf/UsersTable.js @@ -2,8 +2,6 @@ import React, {Component, PropTypes} from 'react' import uuid from 'node-uuid' -import Authorized, {SUPERADMIN_ROLE} from 'src/auth/Authorized' - import UsersTableHeader from 'src/admin/components/chronograf/UsersTableHeader' import UsersTableRowNew from 'src/admin/components/chronograf/UsersTableRowNew' import UsersTableRow from 'src/admin/components/chronograf/UsersTableRow' @@ -23,10 +21,6 @@ class UsersTable extends Component { this.props.onUpdateUserRole(user, currentRole, newRole) } - handleChangeSuperAdmin = user => newStatus => { - this.props.onUpdateUserSuperAdmin(user, newStatus) - } - handleDeleteUser = user => { this.props.onDeleteUser(user) } @@ -43,13 +37,7 @@ class UsersTable extends Component { const {organization, users, onCreateUser, meID, notify} = this.props const {isCreatingUser} = this.state - const { - colRole, - colSuperAdmin, - colProvider, - colScheme, - colActions, - } = USERS_TABLE + const {colRole, colProvider, colScheme, colActions} = USERS_TABLE return (
@@ -67,11 +55,6 @@ class UsersTable extends Component { Role - - - SuperAdmin - - Provider Scheme @@ -93,24 +76,14 @@ class UsersTable extends Component { key={uuid.v4()} organization={organization} onChangeUserRole={this.handleChangeUserRole} - onChangeSuperAdmin={this.handleChangeSuperAdmin} onDelete={this.handleDeleteUser} meID={meID} /> ) : - -

No Users to display

- - } - > - -

No Users to display

- -
+ +

No Users to display

+ } @@ -120,7 +93,7 @@ class UsersTable extends Component { } } -const {arrayOf, bool, func, shape, string} = PropTypes +const {arrayOf, func, shape, string} = PropTypes UsersTable.propTypes = { users: arrayOf( @@ -138,7 +111,6 @@ UsersTable.propTypes = { }) ), scheme: string.isRequired, - superAdmin: bool, }) ).isRequired, organization: shape({ @@ -147,7 +119,6 @@ UsersTable.propTypes = { }), onCreateUser: func.isRequired, onUpdateUserRole: func.isRequired, - onUpdateUserSuperAdmin: func.isRequired, onDeleteUser: func.isRequired, meID: string.isRequired, notify: func.isRequired, diff --git a/ui/src/admin/components/chronograf/UsersTableRow.js b/ui/src/admin/components/chronograf/UsersTableRow.js index 561ca99684..ca02b56d60 100644 --- a/ui/src/admin/components/chronograf/UsersTableRow.js +++ b/ui/src/admin/components/chronograf/UsersTableRow.js @@ -1,9 +1,6 @@ import React, {PropTypes} from 'react' -import Authorized, {SUPERADMIN_ROLE} from 'src/auth/Authorized' - 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' @@ -13,11 +10,10 @@ const UsersTableRow = ({ user, organization, onChangeUserRole, - onChangeSuperAdmin, onDelete, meID, }) => { - const {colRole, colSuperAdmin, colProvider, colScheme} = USERS_TABLE + const {colRole, colProvider, colScheme} = USERS_TABLE const dropdownRolesItems = USER_ROLES.map(r => ({ ...r, @@ -53,16 +49,6 @@ const UsersTableRow = ({ /> - - - - - {user.provider} @@ -89,7 +75,6 @@ UsersTableRow.propTypes = { id: string.isRequired, }), onChangeUserRole: func.isRequired, - onChangeSuperAdmin: func.isRequired, onDelete: func.isRequired, meID: string.isRequired, } diff --git a/ui/src/admin/components/chronograf/UsersTableRowNew.js b/ui/src/admin/components/chronograf/UsersTableRowNew.js index 7b63c3e46c..4af835e089 100644 --- a/ui/src/admin/components/chronograf/UsersTableRowNew.js +++ b/ui/src/admin/components/chronograf/UsersTableRowNew.js @@ -1,7 +1,5 @@ import React, {Component, PropTypes} from 'react' -import Authorized, {SUPERADMIN_ROLE} from 'src/auth/Authorized' - import Dropdown from 'shared/components/Dropdown' import {USERS_TABLE} from 'src/admin/constants/chronografTableSizing' @@ -25,13 +23,12 @@ class UsersTableRowNew extends Component { handleConfirmCreateUser = () => { const {onBlur, onCreateUser, organization} = this.props - const {name, provider, scheme, role, superAdmin} = this.state + const {name, provider, scheme, role} = this.state const newUser = { name, provider, scheme, - superAdmin, roles: [ { name: role, @@ -72,13 +69,7 @@ class UsersTableRowNew extends Component { } render() { - const { - colRole, - colProvider, - colScheme, - colSuperAdmin, - colActions, - } = USERS_TABLE + const {colRole, colProvider, colScheme, colActions} = USERS_TABLE const {onBlur} = this.props const {name, provider, scheme, role} = this.state @@ -108,11 +99,6 @@ class UsersTableRowNew extends Component { className="dropdown-stretch" /> - - - — - - { + const {links, actions: {createUserAsync}} = this.props + createUserAsync(links.users, user) + } + + handleUpdateUserRole = (user, currentRole, {name}) => { + const {actions: {updateUserAsync}} = this.props + const updatedRole = {...currentRole, name} + const newRoles = user.roles.map( + r => (r.organization === currentRole.organization ? updatedRole : r) + ) + updateUserAsync(user, {...user, roles: newRoles}) + } + + handleUpdateUserSuperAdmin = (user, superAdmin) => { + const {actions: {updateUserAsync}} = this.props + const updatedUser = {...user, superAdmin} + updateUserAsync(user, updatedUser) + } + + handleDeleteUser = user => { + const {actions: {deleteUserAsync}} = this.props + deleteUserAsync(user) + } + + async componentWillMount() { + const { + links, + actions: {loadOrganizationsAsync, loadUsersAsync}, + } = this.props + + this.setState({isLoading: true}) + + await Promise.all([ + loadOrganizationsAsync(links.organizations), + loadUsersAsync(links.users), + ]) + + this.setState({isLoading: false}) + } + + render() { + const { + meCurrentOrganization, + organizations, + meID, + users, + notify, + } = this.props + const {isLoading} = this.state + + if (isLoading) { + return + } + + const organization = organizations.find( + o => o.id === meCurrentOrganization.id + ) + + return ( + + ) + } +} + +const {arrayOf, func, shape, string} = PropTypes + +AllUsersPage.propTypes = { + links: shape({ + users: string.isRequired, + }), + meID: string.isRequired, + meCurrentOrganization: shape({ + id: string.isRequired, + name: string.isRequired, + }).isRequired, + users: arrayOf(shape), + organizations: arrayOf(shape), + actions: shape({ + loadUsersAsync: func.isRequired, + loadOrganizationsAsync: func.isRequired, + createUserAsync: func.isRequired, + updateUserAsync: func.isRequired, + deleteUserAsync: func.isRequired, + }), + notify: func.isRequired, +} + +const mapStateToProps = ({links, adminChronograf: {organizations, users}}) => ({ + links, + organizations, + users, +}) + +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(adminChronografActionCreators, dispatch), + notify: bindActionCreators(publishAutoDismissingNotification, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(AllUsersPage) diff --git a/ui/src/admin/containers/chronograf/UsersPage.js b/ui/src/admin/containers/chronograf/UsersPage.js index a8d21a051c..2da41d7a07 100644 --- a/ui/src/admin/containers/chronograf/UsersPage.js +++ b/ui/src/admin/containers/chronograf/UsersPage.js @@ -31,12 +31,6 @@ class UsersPage extends Component { updateUserAsync(user, {...user, roles: newRoles}) } - handleUpdateUserSuperAdmin = (user, superAdmin) => { - const {actions: {updateUserAsync}} = this.props - const updatedUser = {...user, superAdmin} - updateUserAsync(user, updatedUser) - } - handleDeleteUser = user => { const {actions: {deleteUserAsync}} = this.props deleteUserAsync(user) @@ -83,7 +77,6 @@ class UsersPage extends Component { organization={organization} onCreateUser={this.handleCreateUser} onUpdateUserRole={this.handleUpdateUserRole} - onUpdateUserSuperAdmin={this.handleUpdateUserSuperAdmin} onDeleteUser={this.handleDeleteUser} notify={notify} />