Merge pull request #2452 from influxdata/multitenancy_ui_prevent_self_deletion

Disable 'Remove' button for self in Chronograf UsersTable
pull/2469/head
Jared Scheib 2017-12-04 13:57:33 -08:00 committed by GitHub
commit 75e1c46577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 15 deletions

View File

@ -22,6 +22,7 @@ const AdminTabs = ({
onUpdateUserRole, onUpdateUserRole,
onUpdateUserSuperAdmin, onUpdateUserSuperAdmin,
onDeleteUser, onDeleteUser,
meID,
}) => { }) => {
const tabs = [ const tabs = [
{ {
@ -40,6 +41,7 @@ const AdminTabs = ({
onUpdateUserRole={onUpdateUserRole} onUpdateUserRole={onUpdateUserRole}
onUpdateUserSuperAdmin={onUpdateUserSuperAdmin} onUpdateUserSuperAdmin={onUpdateUserSuperAdmin}
onDeleteUser={onDeleteUser} onDeleteUser={onDeleteUser}
meID={meID}
/> />
), ),
}, },
@ -65,16 +67,34 @@ const AdminTabs = ({
) )
} }
const {arrayOf, func, shape, string} = PropTypes const {arrayOf, bool, func, shape, string} = PropTypes
AdminTabs.propTypes = { AdminTabs.propTypes = {
meRole: string.isRequired, meRole: string.isRequired,
meID: string.isRequired,
// UsersTable // UsersTable
users: arrayOf(shape()), 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({ organization: shape({
name: string.isRequired, name: string.isRequired,
id: string.isRequired, id: string.isRequired,
}), }).isRequired,
onCreateUser: func.isRequired, onCreateUser: func.isRequired,
onUpdateUserRole: func.isRequired, onUpdateUserRole: func.isRequired,
onUpdateUserSuperAdmin: func.isRequired, onUpdateUserSuperAdmin: func.isRequired,

View File

@ -40,7 +40,7 @@ class UsersTable extends Component {
} }
render() { render() {
const {organization, users, onCreateUser} = this.props const {organization, users, onCreateUser, meID} = this.props
const {isCreatingUser} = this.state const {isCreatingUser} = this.state
const { const {
@ -94,6 +94,7 @@ class UsersTable extends Component {
onChangeUserRole={this.handleChangeUserRole} onChangeUserRole={this.handleChangeUserRole}
onChangeSuperAdmin={this.handleChangeSuperAdmin} onChangeSuperAdmin={this.handleChangeSuperAdmin}
onDelete={this.handleDeleteUser} onDelete={this.handleDeleteUser}
meID={meID}
/> />
) )
: <tr className="table-empty-state"> : <tr className="table-empty-state">
@ -130,5 +131,6 @@ UsersTable.propTypes = {
onUpdateUserRole: func.isRequired, onUpdateUserRole: func.isRequired,
onUpdateUserSuperAdmin: func.isRequired, onUpdateUserSuperAdmin: func.isRequired,
onDeleteUser: func.isRequired, onDeleteUser: func.isRequired,
meID: string.isRequired,
} }
export default UsersTable export default UsersTable

View File

@ -15,6 +15,7 @@ const UsersTableRow = ({
onChangeUserRole, onChangeUserRole,
onChangeSuperAdmin, onChangeSuperAdmin,
onDelete, onDelete,
meID,
}) => { }) => {
const {colRole, colSuperAdmin, colProvider, colScheme} = USERS_TABLE const {colRole, colSuperAdmin, colProvider, colScheme} = USERS_TABLE
@ -65,6 +66,7 @@ const UsersTableRow = ({
onDelete={onDelete} onDelete={onDelete}
item={user} item={user}
buttonSize="btn-xs" buttonSize="btn-xs"
disabled={user.id === meID}
/> />
</tr> </tr>
) )
@ -81,6 +83,7 @@ UsersTableRow.propTypes = {
onChangeUserRole: func.isRequired, onChangeUserRole: func.isRequired,
onChangeSuperAdmin: func.isRequired, onChangeSuperAdmin: func.isRequired,
onDelete: func.isRequired, onDelete: func.isRequired,
meID: string.isRequired,
} }
export default UsersTableRow export default UsersTableRow

View File

@ -11,10 +11,10 @@ import FancyScrollbar from 'shared/components/FancyScrollbar'
class AdminChronografPage extends Component { class AdminChronografPage extends Component {
// TODO: revisit this, possibly don't call setState if both are deep equal // TODO: revisit this, possibly don't call setState if both are deep equal
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const {currentOrganization} = nextProps const {meCurrentOrganization} = nextProps
const hasChangedCurrentOrganization = const hasChangedCurrentOrganization =
currentOrganization.id !== this.props.currentOrganization.id meCurrentOrganization.id !== this.props.meCurrentOrganization.id
if (hasChangedCurrentOrganization) { if (hasChangedCurrentOrganization) {
this.loadUsers() this.loadUsers()
@ -64,7 +64,7 @@ class AdminChronografPage extends Component {
} }
render() { render() {
const {users, currentOrganization, meRole} = this.props const {users, meCurrentOrganization, meRole, meID} = this.props
return ( return (
<div className="page"> <div className="page">
@ -81,9 +81,10 @@ class AdminChronografPage extends Component {
<div className="row"> <div className="row">
<AdminTabs <AdminTabs
meRole={meRole} meRole={meRole}
meID={meID}
// UsersTable // UsersTable
users={users} users={users}
organization={currentOrganization} organization={meCurrentOrganization}
onCreateUser={this.handleCreateUser} onCreateUser={this.handleCreateUser}
onUpdateUserRole={this.handleUpdateUserRole} onUpdateUserRole={this.handleUpdateUserRole}
onUpdateUserSuperAdmin={this.handleUpdateUserSuperAdmin} onUpdateUserSuperAdmin={this.handleUpdateUserSuperAdmin}
@ -105,11 +106,12 @@ AdminChronografPage.propTypes = {
users: string.isRequired, users: string.isRequired,
}), }),
users: arrayOf(shape), users: arrayOf(shape),
currentOrganization: shape({ meCurrentOrganization: shape({
id: string.isRequired, id: string.isRequired,
name: string.isRequired, name: string.isRequired,
}).isRequired, }).isRequired,
meRole: string.isRequired, meRole: string.isRequired,
meID: string.isRequired,
actions: shape({ actions: shape({
loadUsersAsync: func.isRequired, loadUsersAsync: func.isRequired,
createUserAsync: func.isRequired, createUserAsync: func.isRequired,
@ -122,12 +124,15 @@ AdminChronografPage.propTypes = {
const mapStateToProps = ({ const mapStateToProps = ({
links, links,
adminChronograf: {users}, adminChronograf: {users},
auth: {me: {currentOrganization, role: meRole}}, auth: {
me: {currentOrganization: meCurrentOrganization, role: meRole, id: meID},
},
}) => ({ }) => ({
links, links,
users, users,
currentOrganization, meCurrentOrganization,
meRole, meRole,
meID,
}) })
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -4,10 +4,11 @@ import classnames from 'classnames'
import OnClickOutside from 'shared/components/OnClickOutside' import OnClickOutside from 'shared/components/OnClickOutside'
import ConfirmButtons from 'shared/components/ConfirmButtons' import ConfirmButtons from 'shared/components/ConfirmButtons'
const DeleteButton = ({onClickDelete, buttonSize, text}) => const DeleteButton = ({onClickDelete, buttonSize, text, disabled}) =>
<button <button
className={classnames('btn btn-danger table--show-on-row-hover', { className={classnames('btn btn-danger table--show-on-row-hover', {
[buttonSize]: buttonSize, [buttonSize]: buttonSize,
disabled,
})} })}
onClick={onClickDelete} onClick={onClickDelete}
> >
@ -37,7 +38,7 @@ class DeleteConfirmButtons extends Component {
} }
render() { render() {
const {onDelete, item, buttonSize, text} = this.props const {onDelete, item, buttonSize, text, disabled} = this.props
const {isConfirming} = this.state const {isConfirming} = this.state
return isConfirming return isConfirming
@ -49,18 +50,20 @@ class DeleteConfirmButtons extends Component {
/> />
: <DeleteButton : <DeleteButton
text={text} text={text}
onClickDelete={this.handleClickDelete} onClickDelete={disabled ? () => {} : this.handleClickDelete}
buttonSize={buttonSize} buttonSize={buttonSize}
disabled={disabled}
/> />
} }
} }
const {func, oneOfType, shape, string} = PropTypes const {bool, func, oneOfType, shape, string} = PropTypes
DeleteButton.propTypes = { DeleteButton.propTypes = {
text: string.isRequired, text: string.isRequired,
onClickDelete: func.isRequired, onClickDelete: func.isRequired,
buttonSize: string, buttonSize: string,
disabled: bool,
} }
DeleteButton.defaultProps = { DeleteButton.defaultProps = {
@ -72,6 +75,7 @@ DeleteConfirmButtons.propTypes = {
item: oneOfType([(string, shape())]), item: oneOfType([(string, shape())]),
onDelete: func.isRequired, onDelete: func.isRequired,
buttonSize: string, buttonSize: string,
disabled: bool,
} }
DeleteConfirmButtons.defaultProps = { DeleteConfirmButtons.defaultProps = {