|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
import React, { FC, PureComponent } from 'react'; |
|
|
|
|
import React, { FC, PureComponent, useRef, useState } from 'react'; |
|
|
|
|
import { AccessControlAction, UserDTO } from 'app/types'; |
|
|
|
|
import { css, cx } from '@emotion/css'; |
|
|
|
|
import { config } from 'app/core/config'; |
|
|
|
@ -16,73 +16,60 @@ interface Props { |
|
|
|
|
onPasswordChange(password: string): void; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
interface State { |
|
|
|
|
isLoading: boolean; |
|
|
|
|
showDeleteModal: boolean; |
|
|
|
|
showDisableModal: boolean; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
state = { |
|
|
|
|
isLoading: false, |
|
|
|
|
showDeleteModal: false, |
|
|
|
|
showDisableModal: false, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
showDeleteUserModal = (show: boolean) => () => { |
|
|
|
|
this.setState({ showDeleteModal: show }); |
|
|
|
|
export function UserProfile({ |
|
|
|
|
user, |
|
|
|
|
onUserUpdate, |
|
|
|
|
onUserDelete, |
|
|
|
|
onUserDisable, |
|
|
|
|
onUserEnable, |
|
|
|
|
onPasswordChange, |
|
|
|
|
}: Props) { |
|
|
|
|
const [showDeleteModal, setShowDeleteModal] = useState(false); |
|
|
|
|
const [showDisableModal, setShowDisableModal] = useState(false); |
|
|
|
|
|
|
|
|
|
const deleteUserRef = useRef<HTMLButtonElement | null>(null); |
|
|
|
|
const showDeleteUserModal = (show: boolean) => () => { |
|
|
|
|
setShowDeleteModal(show); |
|
|
|
|
if (!show && deleteUserRef.current) { |
|
|
|
|
deleteUserRef.current.focus(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
showDisableUserModal = (show: boolean) => () => { |
|
|
|
|
this.setState({ showDisableModal: show }); |
|
|
|
|
const disableUserRef = useRef<HTMLButtonElement | null>(null); |
|
|
|
|
const showDisableUserModal = (show: boolean) => () => { |
|
|
|
|
setShowDisableModal(show); |
|
|
|
|
if (!show && disableUserRef.current) { |
|
|
|
|
disableUserRef.current.focus(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
onUserDelete = () => { |
|
|
|
|
const { user, onUserDelete } = this.props; |
|
|
|
|
onUserDelete(user.id); |
|
|
|
|
}; |
|
|
|
|
const handleUserDelete = () => onUserDelete(user.id); |
|
|
|
|
|
|
|
|
|
onUserDisable = () => { |
|
|
|
|
const { user, onUserDisable } = this.props; |
|
|
|
|
onUserDisable(user.id); |
|
|
|
|
}; |
|
|
|
|
const handleUserDisable = () => onUserDisable(user.id); |
|
|
|
|
|
|
|
|
|
onUserEnable = () => { |
|
|
|
|
const { user, onUserEnable } = this.props; |
|
|
|
|
onUserEnable(user.id); |
|
|
|
|
}; |
|
|
|
|
const handleUserEnable = () => onUserEnable(user.id); |
|
|
|
|
|
|
|
|
|
onUserNameChange = (newValue: string) => { |
|
|
|
|
const { user, onUserUpdate } = this.props; |
|
|
|
|
const onUserNameChange = (newValue: string) => { |
|
|
|
|
onUserUpdate({ |
|
|
|
|
...user, |
|
|
|
|
name: newValue, |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
onUserEmailChange = (newValue: string) => { |
|
|
|
|
const { user, onUserUpdate } = this.props; |
|
|
|
|
const onUserEmailChange = (newValue: string) => { |
|
|
|
|
onUserUpdate({ |
|
|
|
|
...user, |
|
|
|
|
email: newValue, |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
onUserLoginChange = (newValue: string) => { |
|
|
|
|
const { user, onUserUpdate } = this.props; |
|
|
|
|
const onUserLoginChange = (newValue: string) => { |
|
|
|
|
onUserUpdate({ |
|
|
|
|
...user, |
|
|
|
|
login: newValue, |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
onPasswordChange = (newValue: string) => { |
|
|
|
|
this.props.onPasswordChange(newValue); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
render() { |
|
|
|
|
const { user } = this.props; |
|
|
|
|
const { showDeleteModal, showDisableModal } = this.state; |
|
|
|
|
const authSource = user.authLabels?.length && user.authLabels[0]; |
|
|
|
|
const lockMessage = authSource ? `Synced via ${authSource}` : ''; |
|
|
|
|
const styles = getStyles(config.theme); |
|
|
|
@ -105,21 +92,21 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
value={user.name} |
|
|
|
|
locked={editLocked} |
|
|
|
|
lockMessage={lockMessage} |
|
|
|
|
onChange={this.onUserNameChange} |
|
|
|
|
onChange={onUserNameChange} |
|
|
|
|
/> |
|
|
|
|
<UserProfileRow |
|
|
|
|
label="Email" |
|
|
|
|
value={user.email} |
|
|
|
|
locked={editLocked} |
|
|
|
|
lockMessage={lockMessage} |
|
|
|
|
onChange={this.onUserEmailChange} |
|
|
|
|
onChange={onUserEmailChange} |
|
|
|
|
/> |
|
|
|
|
<UserProfileRow |
|
|
|
|
label="Username" |
|
|
|
|
value={user.login} |
|
|
|
|
locked={editLocked} |
|
|
|
|
lockMessage={lockMessage} |
|
|
|
|
onChange={this.onUserLoginChange} |
|
|
|
|
onChange={onUserLoginChange} |
|
|
|
|
/> |
|
|
|
|
<UserProfileRow |
|
|
|
|
label="Password" |
|
|
|
@ -127,7 +114,7 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
inputType="password" |
|
|
|
|
locked={passwordChangeLocked} |
|
|
|
|
lockMessage={lockMessage} |
|
|
|
|
onChange={this.onPasswordChange} |
|
|
|
|
onChange={onPasswordChange} |
|
|
|
|
/> |
|
|
|
|
</tbody> |
|
|
|
|
</table> |
|
|
|
@ -135,7 +122,7 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
<div className={styles.buttonRow}> |
|
|
|
|
{canDelete && ( |
|
|
|
|
<> |
|
|
|
|
<Button variant="destructive" onClick={this.showDeleteUserModal(true)}> |
|
|
|
|
<Button variant="destructive" onClick={showDeleteUserModal(true)} ref={deleteUserRef}> |
|
|
|
|
Delete user |
|
|
|
|
</Button> |
|
|
|
|
<ConfirmModal |
|
|
|
@ -143,19 +130,19 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
title="Delete user" |
|
|
|
|
body="Are you sure you want to delete this user?" |
|
|
|
|
confirmText="Delete user" |
|
|
|
|
onConfirm={this.onUserDelete} |
|
|
|
|
onDismiss={this.showDeleteUserModal(false)} |
|
|
|
|
onConfirm={handleUserDelete} |
|
|
|
|
onDismiss={showDeleteUserModal(false)} |
|
|
|
|
/> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
{user.isDisabled && canEnable && ( |
|
|
|
|
<Button variant="secondary" onClick={this.onUserEnable}> |
|
|
|
|
<Button variant="secondary" onClick={handleUserEnable}> |
|
|
|
|
Enable user |
|
|
|
|
</Button> |
|
|
|
|
)} |
|
|
|
|
{!user.isDisabled && canDisable && ( |
|
|
|
|
<> |
|
|
|
|
<Button variant="secondary" onClick={this.showDisableUserModal(true)}> |
|
|
|
|
<Button variant="secondary" onClick={showDisableUserModal(true)} ref={disableUserRef}> |
|
|
|
|
Disable user |
|
|
|
|
</Button> |
|
|
|
|
<ConfirmModal |
|
|
|
@ -163,8 +150,8 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
title="Disable user" |
|
|
|
|
body="Are you sure you want to disable this user?" |
|
|
|
|
confirmText="Disable user" |
|
|
|
|
onConfirm={this.onUserDisable} |
|
|
|
|
onDismiss={this.showDisableUserModal(false)} |
|
|
|
|
onConfirm={handleUserDisable} |
|
|
|
|
onDismiss={showDisableUserModal(false)} |
|
|
|
|
/> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
@ -172,7 +159,6 @@ export class UserProfile extends PureComponent<Props, State> { |
|
|
|
|
</div> |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const getStyles = stylesFactory((theme: GrafanaTheme) => { |
|
|
|
@ -269,7 +255,6 @@ export class UserProfileRow extends PureComponent<UserProfileRowProps, UserProfi |
|
|
|
|
font-weight: 500; |
|
|
|
|
` |
|
|
|
|
); |
|
|
|
|
const editButtonContainerClass = cx('pull-right'); |
|
|
|
|
|
|
|
|
|
if (locked) { |
|
|
|
|
return <LockedRow label={label} value={value} lockMessage={lockMessage} />; |
|
|
|
@ -297,7 +282,6 @@ export class UserProfileRow extends PureComponent<UserProfileRowProps, UserProfi |
|
|
|
|
)} |
|
|
|
|
</td> |
|
|
|
|
<td> |
|
|
|
|
<div className={editButtonContainerClass}> |
|
|
|
|
<ConfirmButton |
|
|
|
|
confirmText="Save" |
|
|
|
|
onClick={this.onEditClick} |
|
|
|
@ -306,7 +290,6 @@ export class UserProfileRow extends PureComponent<UserProfileRowProps, UserProfi |
|
|
|
|
> |
|
|
|
|
Edit |
|
|
|
|
</ConfirmButton> |
|
|
|
|
</div> |
|
|
|
|
</td> |
|
|
|
|
</tr> |
|
|
|
|
); |
|
|
|
@ -320,13 +303,10 @@ interface LockedRowProps { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export const LockedRow: FC<LockedRowProps> = ({ label, value, lockMessage }) => { |
|
|
|
|
const lockMessageClass = cx( |
|
|
|
|
'pull-right', |
|
|
|
|
css` |
|
|
|
|
const lockMessageClass = css` |
|
|
|
|
font-style: italic; |
|
|
|
|
margin-right: 0.6rem; |
|
|
|
|
` |
|
|
|
|
); |
|
|
|
|
`;
|
|
|
|
|
const labelClass = cx( |
|
|
|
|
'width-16', |
|
|
|
|
css` |
|
|
|
|