mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
parent
75ce0c4fa2
commit
cff438faf9
8 changed files with 314 additions and 95 deletions
|
@ -11,7 +11,8 @@
|
|||
"tileMap": "src/core_plugins/tile_map",
|
||||
"tagCloud": "src/core_plugins/tagcloud",
|
||||
"xpack.idxMgmt": "x-pack/plugins/index_management",
|
||||
"xpack.watcher": "x-pack/plugins/watcher"
|
||||
"xpack.watcher": "x-pack/plugins/watcher",
|
||||
"xpack.security": "x-pack/plugins/security"
|
||||
},
|
||||
"exclude": [
|
||||
"src/ui/ui_render/bootstrap/app_bootstrap.js",
|
||||
|
|
|
@ -7,17 +7,29 @@
|
|||
import React, { Component, Fragment } from 'react';
|
||||
import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
export class ConfirmDelete extends Component {
|
||||
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
class ConfirmDeleteUI extends Component {
|
||||
deleteUsers = () => {
|
||||
const { usersToDelete, apiClient, callback } = this.props;
|
||||
const errors = [];
|
||||
usersToDelete.forEach(async username => {
|
||||
try {
|
||||
await apiClient.deleteUser(username);
|
||||
toastNotifications.addSuccess(`Deleted user ${username}`);
|
||||
toastNotifications.addSuccess(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.userSuccessfullyDeletedNotificationMessage",
|
||||
defaultMessage: "Deleted user {username}"
|
||||
}, { username })
|
||||
);
|
||||
} catch (e) {
|
||||
errors.push(username);
|
||||
toastNotifications.addDanger(`Error deleting user ${username}`);
|
||||
toastNotifications.addDanger(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.userDeletingErrorNotificationMessage",
|
||||
defaultMessage: "Error deleting user {username}"
|
||||
}, { username })
|
||||
);
|
||||
}
|
||||
if (callback) {
|
||||
callback(usersToDelete, errors);
|
||||
|
@ -25,34 +37,56 @@ export class ConfirmDelete extends Component {
|
|||
});
|
||||
};
|
||||
render() {
|
||||
const { usersToDelete, onCancel } = this.props;
|
||||
const { usersToDelete, onCancel, intl } = this.props;
|
||||
const moreThanOne = usersToDelete.length > 1;
|
||||
const title = moreThanOne
|
||||
? `Delete ${usersToDelete.length} users`
|
||||
: `Delete user '${usersToDelete[0]}'`;
|
||||
? intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.deleteMultipleUsersTitle",
|
||||
defaultMessage: "Delete {userLength} users"
|
||||
}, { userLength: usersToDelete.length })
|
||||
: intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.deleteOneUserTitle",
|
||||
defaultMessage: "Delete user {userLength}"
|
||||
}, { userLength: usersToDelete[0] });
|
||||
return (
|
||||
<EuiOverlayMask>
|
||||
<EuiConfirmModal
|
||||
title={title}
|
||||
onCancel={onCancel}
|
||||
onConfirm={this.deleteUsers}
|
||||
cancelButtonText="Cancel"
|
||||
confirmButtonText="Delete"
|
||||
cancelButtonText={intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.cancelButtonLabel",
|
||||
defaultMessage: "Cancel"
|
||||
})}
|
||||
confirmButtonText={intl.formatMessage({
|
||||
id: "xpack.security.management.users.confirmDelete.confirmButtonLabel",
|
||||
defaultMessage: "Delete"
|
||||
})}
|
||||
buttonColor="danger"
|
||||
>
|
||||
<div>
|
||||
{moreThanOne ? (
|
||||
<Fragment>
|
||||
<p>
|
||||
You are about to delete these users:
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.confirmDelete.removingUsersDescription"
|
||||
defaultMessage="You are about to delete these users:"
|
||||
/>
|
||||
</p>
|
||||
<ul>{usersToDelete.map(username => <li key={username}>{username}</li>)}</ul>
|
||||
</Fragment>
|
||||
) : null}
|
||||
<p>This operation cannot be undone.</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.confirmDelete.removingUsersWarningMessage"
|
||||
defaultMessage="This operation cannot be undone."
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</EuiConfirmModal>
|
||||
</EuiOverlayMask>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ConfirmDelete = injectI18n(ConfirmDeleteUI);
|
||||
|
|
|
@ -32,9 +32,11 @@ import {
|
|||
import { toastNotifications } from 'ui/notify';
|
||||
import { USERS_PATH } from '../../../views/management/management_urls';
|
||||
import { ConfirmDelete } from './confirm_delete';
|
||||
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
const validEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; //eslint-disable-line max-len
|
||||
const validUsernameRegex = /[a-zA-Z_][a-zA-Z0-9_@\-\$\.]*/;
|
||||
export class EditUser extends Component {
|
||||
class EditUserUI extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -63,7 +65,10 @@ export class EditUser extends Component {
|
|||
currentUser = await apiClient.getCurrentUser();
|
||||
} catch (err) {
|
||||
toastNotifications.addDanger({
|
||||
title: `Error loading user`,
|
||||
title: this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.errorLoadingUserTitle",
|
||||
defaultMessage: "Error loading user"
|
||||
}),
|
||||
text: get(err, 'data.message') || err.message,
|
||||
});
|
||||
return;
|
||||
|
@ -75,7 +80,10 @@ export class EditUser extends Component {
|
|||
roles = await apiClient.getRoles();
|
||||
} catch (err) {
|
||||
toastNotifications.addDanger({
|
||||
title: `Error loading roles`,
|
||||
title: this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.errorLoadingRolesTitle",
|
||||
defaultMessage: "Error loading roles"
|
||||
}),
|
||||
text: get(err, 'data.message') || err.message,
|
||||
});
|
||||
return;
|
||||
|
@ -99,19 +107,28 @@ export class EditUser extends Component {
|
|||
passwordError = () => {
|
||||
const { password } = this.state;
|
||||
if (password !== null && password.length < 6) {
|
||||
return 'Password must be at least 6 characters';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.passwordLengthErrorMessage",
|
||||
defaultMessage: "Password must be at least 6 characters"
|
||||
});
|
||||
}
|
||||
};
|
||||
currentPasswordError = () => {
|
||||
const { currentPasswordError } = this.state;
|
||||
if (currentPasswordError) {
|
||||
return 'The current password you entered is incorrect';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.incorrectPasswordErrorMessage",
|
||||
defaultMessage: "The current password you entered is incorrect"
|
||||
});
|
||||
}
|
||||
};
|
||||
confirmPasswordError = () => {
|
||||
const { password, confirmPassword } = this.state;
|
||||
if (password && confirmPassword !== null && password !== confirmPassword) {
|
||||
return 'Passwords do not match';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.passwordDoNotMatchErrorMessage",
|
||||
defaultMessage: "Passwords do not match"
|
||||
});
|
||||
}
|
||||
};
|
||||
usernameError = () => {
|
||||
|
@ -119,19 +136,28 @@ export class EditUser extends Component {
|
|||
if (username !== null && !username) {
|
||||
return 'Username is required';
|
||||
} else if (username && !username.match(validUsernameRegex)) {
|
||||
return 'Username must begin with a letter or underscore and contain only letters, underscores, and numbers';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.usernameAllowedCharactersErrorMessage",
|
||||
defaultMessage: "Username must begin with a letter or underscore and contain only letters, underscores, and numbers"
|
||||
});
|
||||
}
|
||||
};
|
||||
fullnameError = () => {
|
||||
const { full_name } = this.state.user;
|
||||
if (full_name !== null && !full_name) {
|
||||
return 'Full name is required';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.fullNameRequiredErrorMessage",
|
||||
defaultMessage: "Full name is required"
|
||||
});
|
||||
}
|
||||
};
|
||||
emailError = () => {
|
||||
const { email } = this.state.user;
|
||||
if (email !== null && (!email || !email.match(validEmailRegex))) {
|
||||
return 'A valid email address is required';
|
||||
return this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.validEmailRequiredErrorMessage",
|
||||
defaultMessage: "A valid email address is required"
|
||||
});
|
||||
}
|
||||
};
|
||||
changePassword = async () => {
|
||||
|
@ -139,12 +165,22 @@ export class EditUser extends Component {
|
|||
const { user, password, currentPassword } = this.state;
|
||||
try {
|
||||
await apiClient.changePassword(user.username, password, currentPassword);
|
||||
toastNotifications.addSuccess('Password changed.');
|
||||
toastNotifications.addSuccess(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.passwordSuccessfullyChangedNotificationMessage",
|
||||
defaultMessage: "Password changed."
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
if (e.status === 401) {
|
||||
return this.setState({ currentPasswordError: true });
|
||||
} else {
|
||||
toastNotifications.addDanger(`Error setting password: ${e.data.message}`);
|
||||
toastNotifications.addDanger(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.settingPasswordErrorMessage",
|
||||
defaultMessage: "Error setting password: {message}"
|
||||
}, { message: e.data.message })
|
||||
);
|
||||
}
|
||||
}
|
||||
this.clearPasswordForm();
|
||||
|
@ -161,10 +197,20 @@ export class EditUser extends Component {
|
|||
}
|
||||
try {
|
||||
await apiClient.saveUser(userToSave);
|
||||
toastNotifications.addSuccess(`Saved user ${user.username}`);
|
||||
toastNotifications.addSuccess(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.userSuccessfullySavedNotificationMessage",
|
||||
defaultMessage: "Saved user {message}"
|
||||
}, { message: user.username })
|
||||
);
|
||||
changeUrl(USERS_PATH);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(`Error saving user: ${e.data.message}`);
|
||||
toastNotifications.addDanger(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.savingUserErrorMessage",
|
||||
defaultMessage: "Error saving user: {message}"
|
||||
}, { message: e.data.message })
|
||||
);
|
||||
}
|
||||
};
|
||||
clearPasswordForm = () => {
|
||||
|
@ -181,7 +227,10 @@ export class EditUser extends Component {
|
|||
<Fragment>
|
||||
{userIsLoggedInUser ? (
|
||||
<EuiFormRow
|
||||
label="Current password"
|
||||
label={this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.currentPasswordFormRowLabel",
|
||||
defaultMessage: "Current password"
|
||||
})}
|
||||
isInvalid={!!this.currentPasswordError()}
|
||||
error={this.currentPasswordError()}
|
||||
>
|
||||
|
@ -193,7 +242,15 @@ export class EditUser extends Component {
|
|||
</EuiFormRow>
|
||||
) : null}
|
||||
<EuiFormRow
|
||||
label={userIsLoggedInUser ? 'New password' : 'Password'}
|
||||
label={
|
||||
userIsLoggedInUser ? this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.newPasswordFormRowLabel",
|
||||
defaultMessage: "New password"
|
||||
}) : this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.passwordFormRowLabel",
|
||||
defaultMessage: "Password"
|
||||
})
|
||||
}
|
||||
isInvalid={!!this.passwordError()}
|
||||
error={this.passwordError()}
|
||||
>
|
||||
|
@ -206,7 +263,10 @@ export class EditUser extends Component {
|
|||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label="Confirm password"
|
||||
label={this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.confirmPasswordFormRowLabel",
|
||||
defaultMessage: "Confirm password"
|
||||
})}
|
||||
isInvalid={!!this.confirmPasswordError()}
|
||||
error={this.confirmPasswordError()}
|
||||
>
|
||||
|
@ -237,10 +297,21 @@ export class EditUser extends Component {
|
|||
{this.passwordFields()}
|
||||
{username === 'kibana' ? (
|
||||
<Fragment>
|
||||
<EuiCallOut title="Extra step needed" color="warning" iconType="help">
|
||||
<EuiCallOut
|
||||
title={this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.changePasswordExtraStepTitle",
|
||||
defaultMessage: "Extra step needed"
|
||||
})}
|
||||
color="warning"
|
||||
iconType="help"
|
||||
>
|
||||
<p>
|
||||
After you change the password for the kibana user, you must update the kibana.yml
|
||||
file and restart Kibana.
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.changePasswordUpdateKibanaTitle"
|
||||
defaultMessage="After you change the password for the kibana user, you must update the {kibana}
|
||||
file and restart Kibana."
|
||||
values={{ kibana: 'kibana.yml' }}
|
||||
/>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer />
|
||||
|
@ -258,7 +329,10 @@ export class EditUser extends Component {
|
|||
this.changePassword(password);
|
||||
}}
|
||||
>
|
||||
Save password
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.savePasswordButtonLabel"
|
||||
defaultMessage="Save password"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -268,7 +342,10 @@ export class EditUser extends Component {
|
|||
this.clearPasswordForm();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.savePasswordCancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -298,7 +375,7 @@ export class EditUser extends Component {
|
|||
this.setState({ showDeleteConfirmation: false });
|
||||
};
|
||||
render() {
|
||||
const { changeUrl, apiClient } = this.props;
|
||||
const { changeUrl, apiClient, intl } = this.props;
|
||||
const {
|
||||
user,
|
||||
roles,
|
||||
|
@ -323,7 +400,20 @@ export class EditUser extends Component {
|
|||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h2>{isNewUser ? 'New user' : `Edit "${user.username}" user`}</h2>
|
||||
<h2>
|
||||
{isNewUser ?
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.newUserTitle"
|
||||
defaultMessage="New user"
|
||||
/>
|
||||
:
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.editUserTitle"
|
||||
defaultMessage="Edit {userName} user"
|
||||
values={{ userName: user.username }}
|
||||
/>
|
||||
}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
{reserved && (
|
||||
|
@ -336,8 +426,11 @@ export class EditUser extends Component {
|
|||
{reserved && (
|
||||
<EuiText size="s" color="subdued">
|
||||
<p>
|
||||
Reserved users are built-in and cannot be removed or modified. Only the password
|
||||
may be changed.
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.modifyingReservedUsersDescription"
|
||||
defaultMessage="Reserved users are built-in and cannot be removed or modified. Only the password
|
||||
may be changed."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
)}
|
||||
|
@ -362,10 +455,16 @@ export class EditUser extends Component {
|
|||
error={this.usernameError()}
|
||||
helpText={
|
||||
!isNewUser && !reserved
|
||||
? "Username's cannot be changed after creation."
|
||||
? intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.changingUserNameAfterCreationDescription",
|
||||
defaultMessage: "Username's cannot be changed after creation."
|
||||
})
|
||||
: null
|
||||
}
|
||||
label="Username"
|
||||
label={intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.usernameFormRowLabel",
|
||||
defaultMessage: "Username"
|
||||
})}
|
||||
>
|
||||
<EuiFieldText
|
||||
onBlur={event =>
|
||||
|
@ -393,7 +492,10 @@ export class EditUser extends Component {
|
|||
<EuiFormRow
|
||||
isInvalid={!!this.fullnameError()}
|
||||
error={this.fullnameError()}
|
||||
label="Full name"
|
||||
label={intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.fullNameFormRowLabel",
|
||||
defaultMessage: "Full name"
|
||||
})}
|
||||
>
|
||||
<EuiFieldText
|
||||
onBlur={event =>
|
||||
|
@ -420,7 +522,10 @@ export class EditUser extends Component {
|
|||
<EuiFormRow
|
||||
isInvalid={!!this.emailError()}
|
||||
error={this.emailError()}
|
||||
label="Email address"
|
||||
label={intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.emailAddressFormRowLabel",
|
||||
defaultMessage: "Email address"
|
||||
})}
|
||||
>
|
||||
<EuiFieldText
|
||||
onBlur={event =>
|
||||
|
@ -446,10 +551,18 @@ export class EditUser extends Component {
|
|||
</EuiFormRow>
|
||||
</Fragment>
|
||||
)}
|
||||
<EuiFormRow label="Roles">
|
||||
<EuiFormRow
|
||||
label={intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.rolesFormRowLabel",
|
||||
defaultMessage: "Roles"
|
||||
})}
|
||||
>
|
||||
<EuiComboBox
|
||||
data-test-subj="userFormRolesDropdown"
|
||||
placeholder="Add roles"
|
||||
placeholder={intl.formatMessage({
|
||||
id: "xpack.security.management.users.editUser.addRolesPlaceholder",
|
||||
defaultMessage: "Add roles"
|
||||
})}
|
||||
onChange={this.onRolesChange}
|
||||
isDisabled={reserved}
|
||||
name="roles"
|
||||
|
@ -462,7 +575,12 @@ export class EditUser extends Component {
|
|||
|
||||
{isNewUser || showChangePasswordForm ? null : (
|
||||
<EuiFormRow label="Password">
|
||||
<EuiLink onClick={this.toggleChangePasswordForm}>Change password</EuiLink>
|
||||
<EuiLink onClick={this.toggleChangePasswordForm}>
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.changePasswordButtonLabel"
|
||||
defaultMessage="Change password"
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
{this.changePasswordForm()}
|
||||
|
@ -470,7 +588,12 @@ export class EditUser extends Component {
|
|||
<EuiHorizontalRule />
|
||||
|
||||
{reserved && (
|
||||
<EuiButton onClick={() => changeUrl(USERS_PATH)}>Return to user list</EuiButton>
|
||||
<EuiButton onClick={() => changeUrl(USERS_PATH)}>
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.returnToUserListButtonLabel"
|
||||
defaultMessage="Return to user list"
|
||||
/>
|
||||
</EuiButton>
|
||||
)}
|
||||
{reserved ? null : (
|
||||
<EuiFlexGroup responsive={false}>
|
||||
|
@ -481,7 +604,16 @@ export class EditUser extends Component {
|
|||
data-test-subj="userFormSaveButton"
|
||||
onClick={() => this.saveUser()}
|
||||
>
|
||||
{isNewUser ? 'Create user' : 'Update user'}
|
||||
{isNewUser ?
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.createUserButtonLabel"
|
||||
defaultMessage="Create user"
|
||||
/>
|
||||
:
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.updateUserButtonLabel"
|
||||
defaultMessage="Update user"
|
||||
/>}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -489,7 +621,10 @@ export class EditUser extends Component {
|
|||
data-test-subj="userFormCancelButton"
|
||||
onClick={() => changeUrl(USERS_PATH)}
|
||||
>
|
||||
Cancel
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={true} />
|
||||
|
@ -502,7 +637,10 @@ export class EditUser extends Component {
|
|||
data-test-subj="userFormDeleteButton"
|
||||
color="danger"
|
||||
>
|
||||
Delete user
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.editUser.deleteUserButtonLabel"
|
||||
defaultMessage="Delete user"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
@ -517,3 +655,5 @@ export class EditUser extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const EditUser = injectI18n(EditUserUI);
|
||||
|
|
|
@ -21,8 +21,9 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { ConfirmDelete } from './confirm_delete';
|
||||
import { injectI18n, FormattedMessage } from "@kbn/i18n/react";
|
||||
|
||||
export class Users extends Component {
|
||||
class UsersUI extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -53,7 +54,12 @@ export class Users extends Component {
|
|||
if (e.status === 403) {
|
||||
this.setState({ permissionDenied: true });
|
||||
} else {
|
||||
toastNotifications.addDanger(`Error fetching users: ${e.data.message}`);
|
||||
toastNotifications.addDanger(
|
||||
this.props.intl.formatMessage({
|
||||
id: "xpack.security.management.users.fetchingUsersErrorMessage",
|
||||
defaultMessage: "Error fetching users: {message}"
|
||||
}, { message: e.data.message })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +75,13 @@ export class Users extends Component {
|
|||
color="danger"
|
||||
onClick={() => this.setState({ showDeleteConfirmation: true })}
|
||||
>
|
||||
Delete {numSelected} user{numSelected > 1 ? 's' : ''}
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.deleteUsersButtonLabel"
|
||||
defaultMessage="Delete {numSelected} user{numSelected, plural, one { } other {s}}"
|
||||
values={{
|
||||
numSelected: numSelected,
|
||||
}}
|
||||
/>
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
@ -78,7 +90,7 @@ export class Users extends Component {
|
|||
}
|
||||
render() {
|
||||
const { users, filter, permissionDenied, showDeleteConfirmation, selection } = this.state;
|
||||
const { apiClient } = this.props;
|
||||
const { apiClient, intl } = this.props;
|
||||
if (permissionDenied) {
|
||||
return (
|
||||
<EuiPage className="mgtUsersListingPage">
|
||||
|
@ -87,8 +99,20 @@ export class Users extends Component {
|
|||
<EuiEmptyPrompt
|
||||
iconType="securityApp"
|
||||
iconColor={null}
|
||||
title={<h2>Permission denied</h2>}
|
||||
body={<p data-test-subj="permissionDeniedMessage">You do not have permission to manage users.</p>}
|
||||
title={
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.deniedPermissionTitle"
|
||||
defaultMessage="Permission denied"
|
||||
/>
|
||||
</h2>}
|
||||
body={
|
||||
<p data-test-subj="permissionDeniedMessage">
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.permissionDeniedToManageUsersDescription"
|
||||
defaultMessage="You do not have permission to manage users."
|
||||
/>
|
||||
</p>}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
|
@ -99,7 +123,7 @@ export class Users extends Component {
|
|||
const columns = [
|
||||
{
|
||||
field: 'full_name',
|
||||
name: 'Full Name',
|
||||
name: intl.formatMessage({ id: "xpack.security.management.users.fullNameColumnName", defaultMessage: "Full Name" }),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
render: fullName => {
|
||||
|
@ -108,7 +132,7 @@ export class Users extends Component {
|
|||
},
|
||||
{
|
||||
field: 'username',
|
||||
name: 'User Name',
|
||||
name: intl.formatMessage({ id: "xpack.security.management.users.userNameColumnName", defaultMessage: "User Name" }),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
render: username => (
|
||||
|
@ -119,13 +143,16 @@ export class Users extends Component {
|
|||
},
|
||||
{
|
||||
field: 'email',
|
||||
name: 'Email Address',
|
||||
name: intl.formatMessage({
|
||||
id: "xpack.security.management.users.emailAddressColumnName",
|
||||
defaultMessage: "Email Address"
|
||||
}),
|
||||
sortable: true,
|
||||
truncateText: true,
|
||||
},
|
||||
{
|
||||
field: 'roles',
|
||||
name: 'Roles',
|
||||
name: intl.formatMessage({ id: "xpack.security.management.users.rolesColumnName", defaultMessage: "Roles" }),
|
||||
render: rolenames => {
|
||||
const roleLinks = rolenames.map((rolename, index) => {
|
||||
return (
|
||||
|
@ -140,12 +167,15 @@ export class Users extends Component {
|
|||
},
|
||||
{
|
||||
field: 'metadata._reserved',
|
||||
name: 'Reserved',
|
||||
name: intl.formatMessage({ id: "xpack.security.management.users.reservedColumnName", defaultMessage: "Reserved" }),
|
||||
sortable: false,
|
||||
width: '100px',
|
||||
align: 'right',
|
||||
description:
|
||||
'Reserved users are built-in and cannot be removed. Only the password can be changed.',
|
||||
intl.formatMessage({
|
||||
id: "xpack.security.management.users.reservedColumnDescription",
|
||||
defaultMessage: "Reserved users are built-in and cannot be removed. Only the password can be changed."
|
||||
}),
|
||||
render: reserved =>
|
||||
reserved ? (
|
||||
<EuiIcon aria-label="Reserved user" data-test-subj="reservedUser" type="check" />
|
||||
|
@ -198,7 +228,12 @@ export class Users extends Component {
|
|||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle>
|
||||
<h2>Users</h2>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.usersTitle"
|
||||
defaultMessage="Users"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
<EuiPageContentHeaderSection>
|
||||
|
@ -206,7 +241,10 @@ export class Users extends Component {
|
|||
data-test-subj="createUserButton"
|
||||
href="#/management/security/users/edit"
|
||||
>
|
||||
Create new user
|
||||
<FormattedMessage
|
||||
id="xpack.security.management.users.createNewUserButtonLabel"
|
||||
defaultMessage="Create new user"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
|
@ -241,3 +279,5 @@ export class Users extends Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Users = injectI18n(UsersUI);
|
||||
|
|
|
@ -29,7 +29,7 @@ exports[`LoginPage disabled form states renders as expected when a connection to
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Welcome to Kibana"
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
|
@ -43,7 +43,7 @@ exports[`LoginPage disabled form states renders as expected when a connection to
|
|||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
|
@ -73,14 +73,14 @@ exports[`LoginPage disabled form states renders as expected when a connection to
|
|||
message={
|
||||
<FormattedMessage
|
||||
defaultMessage="See the Kibana logs for details and try reloading the page."
|
||||
id="kbn.login.esUnavailableMessage"
|
||||
id="xpack.security.loginPage.esUnavailableMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Cannot connect to the Elastiscearch cluster"
|
||||
id="kbn.login.esUnavailableTitle"
|
||||
id="xpack.security.loginPage.esUnavailableTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ exports[`LoginPage disabled form states renders as expected when an unknown logi
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Welcome to Kibana"
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
|
@ -135,7 +135,7 @@ exports[`LoginPage disabled form states renders as expected when an unknown logi
|
|||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
|
@ -165,14 +165,14 @@ exports[`LoginPage disabled form states renders as expected when an unknown logi
|
|||
message={
|
||||
<FormattedMessage
|
||||
defaultMessage="Refer to the Kibana logs for more details and refresh to try again."
|
||||
id="kbn.login.unknownLayoutMessage"
|
||||
id="xpack.security.loginPage.unknownLayoutMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Unsupported login form layout."
|
||||
id="kbn.login.unknownLayoutTitle"
|
||||
id="xpack.security.loginPage.unknownLayoutTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ exports[`LoginPage disabled form states renders as expected when secure cookies
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Welcome to Kibana"
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
|
@ -227,7 +227,7 @@ exports[`LoginPage disabled form states renders as expected when secure cookies
|
|||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
|
@ -257,14 +257,14 @@ exports[`LoginPage disabled form states renders as expected when secure cookies
|
|||
message={
|
||||
<FormattedMessage
|
||||
defaultMessage="Contact your system administrator."
|
||||
id="kbn.login.requiresSecureConnectionMessage"
|
||||
id="xpack.security.loginPage.requiresSecureConnectionMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="A secure connection is required for log in"
|
||||
id="kbn.login.requiresSecureConnectionTitle"
|
||||
id="xpack.security.loginPage.requiresSecureConnectionTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ exports[`LoginPage disabled form states renders as expected when xpack is not av
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Welcome to Kibana"
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
|
@ -319,7 +319,7 @@ exports[`LoginPage disabled form states renders as expected when xpack is not av
|
|||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
|
@ -349,14 +349,14 @@ exports[`LoginPage disabled form states renders as expected when xpack is not av
|
|||
message={
|
||||
<FormattedMessage
|
||||
defaultMessage="To use the full set of free features in this distribution of Kibana, please update Elasticsearch to the default distribution."
|
||||
id="kbn.login.xpackUnavailableMessage"
|
||||
id="xpack.security.loginPage.xpackUnavailableMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Cannot connect to the Elasticsearch cluster currently configured for Kibana."
|
||||
id="kbn.login.xpackUnavailableTitle"
|
||||
id="xpack.security.loginPage.xpackUnavailableTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -397,7 +397,7 @@ exports[`LoginPage enabled form state renders as expected 1`] = `
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Welcome to Kibana"
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h1>
|
||||
|
@ -411,7 +411,7 @@ exports[`LoginPage enabled form state renders as expected 1`] = `
|
|||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
values={Object {}}
|
||||
/>
|
||||
</p>
|
||||
|
|
|
@ -58,7 +58,7 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<EuiTitle size="l" className="loginWelcome__title">
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="kbn.login.welcomeTitle"
|
||||
id="xpack.security.loginPage.welcomeTitle"
|
||||
defaultMessage="Welcome to Kibana"
|
||||
/>
|
||||
</h1>
|
||||
|
@ -66,7 +66,7 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<EuiText size="s" color="subdued" className="loginWelcome__subtitle">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="kbn.login.welcomeDescription"
|
||||
id="xpack.security.loginPage.welcomeDescription"
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
/>
|
||||
</p>
|
||||
|
@ -98,13 +98,13 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<DisabledLoginForm
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.login.requiresSecureConnectionTitle"
|
||||
id="xpack.security.loginPage.requiresSecureConnectionTitle"
|
||||
defaultMessage="A secure connection is required for log in"
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id="kbn.login.requiresSecureConnectionMessage"
|
||||
id="xpack.security.loginPage.requiresSecureConnectionMessage"
|
||||
defaultMessage="Contact your system administrator."
|
||||
/>
|
||||
}
|
||||
|
@ -121,13 +121,13 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<DisabledLoginForm
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.login.esUnavailableTitle"
|
||||
id="xpack.security.loginPage.esUnavailableTitle"
|
||||
defaultMessage="Cannot connect to the Elastiscearch cluster"
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id="kbn.login.esUnavailableMessage"
|
||||
id="xpack.security.loginPage.esUnavailableMessage"
|
||||
defaultMessage="See the Kibana logs for details and try reloading the page."
|
||||
/>
|
||||
}
|
||||
|
@ -138,13 +138,13 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<DisabledLoginForm
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.login.xpackUnavailableTitle"
|
||||
id="xpack.security.loginPage.xpackUnavailableTitle"
|
||||
defaultMessage="Cannot connect to the Elasticsearch cluster currently configured for Kibana."
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id="kbn.login.xpackUnavailableMessage"
|
||||
id="xpack.security.loginPage.xpackUnavailableMessage"
|
||||
defaultMessage="To use the full set of free features in this distribution of Kibana, please update Elasticsearch to the default distribution."
|
||||
/>
|
||||
}
|
||||
|
@ -155,13 +155,13 @@ export class LoginPage extends Component<Props, {}> {
|
|||
<DisabledLoginForm
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.login.unknownLayoutTitle"
|
||||
id="xpack.security.loginPage.unknownLayoutTitle"
|
||||
defaultMessage="Unsupported login form layout."
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id="kbn.login.unknownLayoutMessage"
|
||||
id="xpack.security.loginPage.unknownLayoutMessage"
|
||||
defaultMessage="Refer to the Kibana logs for more details and refresh to try again."
|
||||
/>
|
||||
}
|
||||
|
|
|
@ -14,14 +14,17 @@ import { EditUser } from '../../components/management/users';
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { createApiClient } from '../../lib/api';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
|
||||
const renderReact = (elem, httpClient, changeUrl, username) => {
|
||||
render(
|
||||
<EditUser
|
||||
changeUrl={changeUrl}
|
||||
apiClient={createApiClient(httpClient)}
|
||||
username={username}
|
||||
/>,
|
||||
<I18nProvider>
|
||||
<EditUser
|
||||
changeUrl={changeUrl}
|
||||
apiClient={createApiClient(httpClient)}
|
||||
username={username}
|
||||
/>
|
||||
</I18nProvider>,
|
||||
elem
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,12 +12,13 @@ import 'plugins/security/services/shield_user';
|
|||
import { SECURITY_PATH, USERS_PATH } from './management_urls';
|
||||
import { Users } from '../../components/management/users';
|
||||
import { createApiClient } from '../../lib/api';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
routes.when(SECURITY_PATH, {
|
||||
redirectTo: USERS_PATH,
|
||||
});
|
||||
|
||||
const renderReact = (elem, httpClient, changeUrl) => {
|
||||
render(<Users changeUrl={changeUrl} apiClient={createApiClient(httpClient)} />, elem);
|
||||
render(<I18nProvider><Users changeUrl={changeUrl} apiClient={createApiClient(httpClient)} /></I18nProvider>, elem);
|
||||
};
|
||||
|
||||
routes.when(USERS_PATH, {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue