translate login/logout visualization component part 2 (#26082) (#26621)

* translate login/logout visualization component part 2

* Update login translation part 2 - change FormattedMessage to intl.formatMessage

* change some ids

* update Infra Ops Part 2 - directly wrap some classes by injectI18n()

* update one snapshot

* update one snapshot

* update tests

* update collapsible_panel.test.tsx

* update one snapshot

* update one test

* change some code

* update one snapshot

* update roles.html

* Fix unit tests

* Fix message
This commit is contained in:
Maryia Lapata 2018-12-04 16:01:23 +03:00 committed by GitHub
parent 197e5b094c
commit 0c6a9429d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 192 additions and 95 deletions

View file

@ -134,7 +134,10 @@ class EditUserUI extends Component {
usernameError = () => {
const { username } = this.state.user;
if (username !== null && !username) {
return 'Username is required';
return this.props.intl.formatMessage({
id: "xpack.security.management.users.editUser.requiredUsernameErrorMessage",
defaultMessage: "Username is required"
});
} else if (username && !username.match(validUsernameRegex)) {
return this.props.intl.formatMessage({
id: "xpack.security.management.users.editUser.usernameAllowedCharactersErrorMessage",

View file

@ -20,15 +20,19 @@ const SESSION_TIMEOUT_GRACE_PERIOD_MS = 5000;
const module = uiModules.get('security', []);
module.config(($httpProvider) => {
$httpProvider.interceptors.push(($timeout, $window, $q, $injector, sessionTimeout, Notifier, Private, autoLogout) => {
$httpProvider.interceptors.push(($timeout, $window, $q, $injector, sessionTimeout, Notifier, Private, autoLogout, i18n) => {
const isUnauthenticated = Private(PathProvider).isUnauthenticated();
const notifier = new Notifier();
const notificationLifetime = 60 * 1000;
const notificationOptions = {
type: 'warning',
content: 'You will soon be logged out due to inactivity. Click OK to resume.',
content: i18n('xpack.security.hacks.logoutNotification', {
defaultMessage: 'You will soon be logged out due to inactivity. Click OK to resume.'
}),
icon: 'warning',
title: 'Warning',
title: i18n('xpack.security.hacks.warningTitle', {
defaultMessage: 'Warning'
}),
lifetime: Math.min(
(sessionTimeout - SESSION_TIMEOUT_GRACE_PERIOD_MS),
notificationLifetime

View file

@ -8,11 +8,15 @@
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
FeatureCatalogueRegistryProvider.register(() => {
FeatureCatalogueRegistryProvider.register(i18n => {
return {
id: 'security',
title: 'Security Settings',
description: 'Protect your data and easily manage who has access to what with users and roles.',
title: i18n('xpack.security.registerFeature.securitySettingsTitle', {
defaultMessage: 'Security Settings'
}),
description: i18n('xpack.security.registerFeature.securitySettingsDescription', {
defaultMessage: 'Protect your data and easily manage who has access to what with users and roles.'
}),
icon: 'securityApp',
path: '/app/kibana#/management/security',
showOnHomePage: true,

View file

@ -14,7 +14,13 @@ exports[`BasicLoginForm renders as expected 1`] = `
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
label="Username"
label={
<FormattedMessage
defaultMessage="Username"
id="xpack.security.login.basicLoginForm.usernameFormRowLabel"
values={Object {}}
/>
}
>
<EuiFieldText
aria-required={true}
@ -35,7 +41,13 @@ exports[`BasicLoginForm renders as expected 1`] = `
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
label="Password"
label={
<FormattedMessage
defaultMessage="Password"
id="xpack.security.login.basicLoginForm.passwordFormRowLabel"
values={Object {}}
/>
}
>
<EuiFieldText
aria-required={true}
@ -61,7 +73,11 @@ exports[`BasicLoginForm renders as expected 1`] = `
onClick={[Function]}
type="submit"
>
Log in
<FormattedMessage
defaultMessage="Log in"
id="xpack.security.login.basicLoginForm.logInButtonLabel"
values={Object {}}
/>
</EuiButton>
</form>
</EuiPanel>

View file

@ -5,8 +5,8 @@
*/
import { EuiButton, EuiCallOut } from '@elastic/eui';
import { mount, shallow } from 'enzyme';
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { LoginState } from '../../../../../common/login_state';
import { BasicLoginForm } from './basic_login_form';
@ -43,8 +43,14 @@ describe('BasicLoginForm', () => {
const mockWindow = {};
const loginState = createLoginState();
expect(
shallow(
<BasicLoginForm http={mockHttp} window={mockWindow} loginState={loginState} next={''} />
shallowWithIntl(
<BasicLoginForm.WrappedComponent
http={mockHttp}
window={mockWindow}
loginState={loginState}
next={''}
intl={null as any}
/>
)
).toMatchSnapshot();
});
@ -54,13 +60,14 @@ describe('BasicLoginForm', () => {
const mockWindow = {};
const loginState = createLoginState();
const wrapper = shallow(
<BasicLoginForm
const wrapper = shallowWithIntl(
<BasicLoginForm.WrappedComponent
http={mockHttp}
window={mockWindow}
loginState={loginState}
next={''}
infoMessage={'Hey this is an info message'}
intl={null as any}
/>
);
@ -72,8 +79,14 @@ describe('BasicLoginForm', () => {
const mockWindow = {};
const loginState = createLoginState();
const wrapper = mount(
<BasicLoginForm http={mockHttp} window={mockWindow} loginState={loginState} next={''} />
const wrapper = mountWithIntl(
<BasicLoginForm.WrappedComponent
http={mockHttp}
window={mockWindow}
loginState={loginState}
next={''}
intl={null as any}
/>
);
wrapper.find('input[name="username"]').simulate('change', { target: { value: 'username' } });

View file

@ -5,6 +5,7 @@
*/
import { EuiButton, EuiCallOut, EuiFieldText, EuiFormRow, EuiPanel, EuiSpacer } from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React, { ChangeEvent, Component, FormEvent, Fragment, MouseEvent } from 'react';
import { LoginState } from '../../../../../common/login_state';
@ -14,6 +15,7 @@ interface Props {
infoMessage?: string;
loginState: LoginState;
next: string;
intl: InjectedIntl;
}
interface State {
@ -24,7 +26,7 @@ interface State {
message: string;
}
export class BasicLoginForm extends Component<Props, State> {
class BasicLoginFormUI extends Component<Props, State> {
public state = {
hasError: false,
isLoading: false,
@ -39,7 +41,14 @@ export class BasicLoginForm extends Component<Props, State> {
{this.renderMessage()}
<EuiPanel>
<form onSubmit={this.submit}>
<EuiFormRow label="Username">
<EuiFormRow
label={
<FormattedMessage
id="xpack.security.login.basicLoginForm.usernameFormRowLabel"
defaultMessage="Username"
/>
}
>
<EuiFieldText
id="username"
name="username"
@ -53,7 +62,14 @@ export class BasicLoginForm extends Component<Props, State> {
/>
</EuiFormRow>
<EuiFormRow label="Password">
<EuiFormRow
label={
<FormattedMessage
id="xpack.security.login.basicLoginForm.passwordFormRowLabel"
defaultMessage="Password"
/>
}
>
<EuiFieldText
id="password"
name="password"
@ -75,7 +91,10 @@ export class BasicLoginForm extends Component<Props, State> {
isLoading={this.state.isLoading}
data-test-subj="loginSubmit"
>
Log in
<FormattedMessage
id="xpack.security.login.basicLoginForm.logInButtonLabel"
defaultMessage="Log in"
/>
</EuiButton>
</form>
</EuiPanel>
@ -152,7 +171,7 @@ export class BasicLoginForm extends Component<Props, State> {
message: '',
});
const { http, window, next } = this.props;
const { http, window, next, intl } = this.props;
const { username, password } = this.state;
@ -161,9 +180,15 @@ export class BasicLoginForm extends Component<Props, State> {
(error: any) => {
const { statusCode = 500 } = error.data || {};
let message = 'Oops! Error. Try again.';
let message = intl.formatMessage({
id: 'xpack.security.login.basicLoginForm.unknownErrorMessage',
defaultMessage: 'Oops! Error. Try again.',
});
if (statusCode === 401) {
message = 'Invalid username or password. Please try again.';
message = intl.formatMessage({
id: 'xpack.security.login.basicLoginForm.invalidUsernameOrPasswordErrorMessage',
defaultMessage: 'Invalid username or password. Please try again.',
});
}
this.setState({
@ -175,3 +200,5 @@ export class BasicLoginForm extends Component<Props, State> {
);
};
}
export const BasicLoginForm = injectI18n(BasicLoginFormUI);

View file

@ -442,7 +442,7 @@ exports[`LoginPage enabled form state renders as expected 1`] = `
component="div"
grow={true}
>
<BasicLoginForm
<InjectIntl(BasicLoginFormUI)
http={
Object {
"post": [MockFunction],

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { parseNext } from 'plugins/security/lib/parse_next';
import { LoginPage } from 'plugins/security/views/login/components';
@ -17,7 +18,9 @@ import { parse } from 'url';
import { LoginState } from '../../../common/login_state';
import './login.less';
const messageMap = {
SESSION_EXPIRED: 'Your session has timed out. Please log in again.',
SESSION_EXPIRED: i18n.translate('xpack.security.login.sessionExpiredDescription', {
defaultMessage: 'Your session has timed out. Please log in again.',
}),
};
interface AnyObject {

View file

@ -1,9 +1,11 @@
<ng-form name="changePasswordForm">
<!-- Password -->
<div class="kuiFormSection">
<label class="kuiFormLabel">
Password
</label>
<label
class="kuiFormLabel"
i18n-id="xpack.security.management.changePasswordForm.passwordLabel"
i18n-default-message="Password"
></label>
<!-- Change password button -->
<a
@ -11,9 +13,9 @@
class="kuiLink"
ng-show="!changePasswordController.isFormVisible"
ng-click="changePasswordController.showForm()"
>
Change password
</a>
i18n-id="xpack.security.management.changePasswordForm.changePasswordLinkLabel"
i18n-default-message="Change password"
></a>
<!-- Changing password -->
<div
@ -22,9 +24,12 @@
>
<!-- Current password -->
<div class="kuiFormSection" ng-if="requireCurrentPassword">
<label for="password" class="kuiFormSubLabel mgtForm__subLabel">
Current password
</label>
<label
for="password"
class="kuiFormSubLabel mgtForm__subLabel"
i18n-id="xpack.security.management.changePasswordForm.currentPasswordLabel"
i18n-default-message="Current password"
></label>
<input
type="password"
class="kuiTextInput fullWidth"
@ -38,16 +43,19 @@
<div
class="kuiInputNote kuiInputNote--danger"
ng-show="changePasswordController.isIncorrectPassword"
>
The Current Password you entered is incorrect.
</div>
i18n-id="xpack.security.management.changePasswordForm.incorrectPasswordDescription"
i18n-default-message="The Current Password you entered is incorrect."
></div>
</div>
<!-- New password -->
<div class="kuiFormSection">
<label for="newPassword" class="kuiFormSubLabel mgtForm__subLabel">
New password
</label>
<label
for="newPassword"
class="kuiFormSubLabel mgtForm__subLabel"
i18n-id="xpack.security.management.changePasswordForm.newPasswordLabel"
i18n-default-message="New password"
></label>
<input
type="password"
class="kuiTextInput fullWidth"
@ -62,16 +70,19 @@
<div
class="kuiInputNote kuiInputNote--danger"
ng-show="changePasswordForm.newPassword.$touched && (changePasswordForm.newPassword.$error.required || changePasswordForm.newPassword.$error.minlength)"
>
Password must be at least 6 characters
</div>
i18n-id="xpack.security.management.changePasswordForm.passwordLengthDescription"
i18n-default-message="Password must be at least 6 characters"
></div>
</div>
<!-- New password confirmation -->
<div class="kuiFormSection">
<label for="confirmPassword" class="kuiFormSubLabel mgtForm__subLabel">
Confirm password
</label>
<label
for="confirmPassword"
class="kuiFormSubLabel mgtForm__subLabel"
i18n-id="xpack.security.management.changePasswordForm.confirmPasswordLabel"
i18n-default-message="Confirm password"
></label>
<input
type="password"
class="kuiTextInput fullWidth"
@ -84,9 +95,9 @@
<div
class="kuiInputNote kuiInputNote--danger"
ng-show="changePasswordForm.confirmPassword.$touched && (changePasswordController.newPassword !== changePasswordController.newPasswordConfirmation)"
>
Passwords do not match
</div>
i18n-id="xpack.security.management.changePasswordForm.passwordDontMatchDescription"
i18n-default-message="Passwords do not match"
></div>
<!-- Warnings -->
<div
@ -94,7 +105,10 @@
ng-show="showKibanaWarning"
>
<span class="kuiIcon fa-exclamation-triangle"></span>
After you change the password for the kibana user, you must update the kibana.yml file and restart Kibana
<span
i18n-id="xpack.security.management.changePasswordForm.updateAndRestartKibanaDescription"
i18n-default-message="After you change the password for the kibana user, you must update the kibana.yml file and restart Kibana"
></span>
</div>
</div>
@ -105,17 +119,17 @@
class="kuiButton kuiButton--primary"
ng-click="onChangePassword({ newPassword: changePasswordController.newPassword, currentPassword: changePasswordController.currentPassword, onSuccess: changePasswordController.hideForm, onIncorrectPassword: changePasswordController.onIncorrectPassword })"
ng-disabled="changePasswordForm.newPassword.$invalid || (changePasswordController.newPassword !== changePasswordController.newPasswordConfirmation)"
>
Save changes
</button>
i18n-id="xpack.security.management.changePasswordForm.saveChangesButtonLabel"
i18n-default-message="Save changes"
></button>
<button
type="button"
class="kuiButton kuiButton--basic"
ng-click="changePasswordController.hideForm()"
>
Cancel
</button>
i18n-id="xpack.security.management.changePasswordForm.cancelButtonLabel"
i18n-default-message="Cancel"
></button>
</div>
</div>
</div>

View file

@ -118,7 +118,7 @@ exports[`it renders without crashing 1`] = `
isDisabled={false}
onChange={[Function]}
options={Array []}
placeholder="Add a user..."
placeholder="Add a user"
selectedOptions={Array []}
singleSelection={false}
/>

View file

@ -127,7 +127,7 @@ class ElasticsearchPrivilegesUI extends Component<Props, {}> {
? intl.formatMessage({
id:
'xpack.security.management.editRoles.elasticSearchPrivileges.addUserTitle',
defaultMessage: 'Add a user...',
defaultMessage: 'Add a user',
})
: undefined
}

View file

@ -29,9 +29,10 @@ test('it renders without crashing', () => {
validator: new RoleValidator(),
onChange: jest.fn(),
onDelete: jest.fn(),
intl: {} as any,
};
const wrapper = shallowWithIntl(<IndexPrivilegeForm {...props} />);
const wrapper = shallowWithIntl(<IndexPrivilegeForm.WrappedComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
@ -55,6 +56,7 @@ describe('delete button', () => {
validator: new RoleValidator(),
onChange: jest.fn(),
onDelete: jest.fn(),
intl: {} as any,
};
test('it is hidden when allowDelete is false', () => {
@ -62,7 +64,7 @@ describe('delete button', () => {
...props,
allowDelete: false,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find(EuiButtonIcon)).toHaveLength(0);
});
@ -71,7 +73,7 @@ describe('delete button', () => {
...props,
allowDelete: true,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find(EuiButtonIcon)).toHaveLength(1);
});
@ -80,7 +82,7 @@ describe('delete button', () => {
...props,
allowDelete: true,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
wrapper.find(EuiButtonIcon).simulate('click');
expect(testProps.onDelete).toHaveBeenCalledTimes(1);
});
@ -106,6 +108,7 @@ describe(`document level security`, () => {
validator: new RoleValidator(),
onChange: jest.fn(),
onDelete: jest.fn(),
intl: {} as any,
};
test(`inputs are hidden when DLS is not allowed`, () => {
@ -114,7 +117,7 @@ describe(`document level security`, () => {
allowDocumentLevelSecurity: false,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find(EuiSwitch)).toHaveLength(0);
expect(wrapper.find(EuiTextArea)).toHaveLength(0);
});
@ -128,7 +131,7 @@ describe(`document level security`, () => {
},
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find(EuiSwitch)).toHaveLength(1);
expect(wrapper.find(EuiTextArea)).toHaveLength(0);
});
@ -138,7 +141,7 @@ describe(`document level security`, () => {
...props,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find(EuiSwitch)).toHaveLength(1);
expect(wrapper.find(EuiTextArea)).toHaveLength(1);
});
@ -164,6 +167,7 @@ describe('field level security', () => {
validator: new RoleValidator(),
onChange: jest.fn(),
onDelete: jest.fn(),
intl: {} as any,
};
test(`input is hidden when FLS is not allowed`, () => {
@ -172,7 +176,7 @@ describe('field level security', () => {
allowFieldLevelSecurity: false,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find('.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(0);
});
@ -181,7 +185,7 @@ describe('field level security', () => {
...props,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1);
});
@ -196,7 +200,7 @@ describe('field level security', () => {
},
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1);
expect(wrapper.find('.euiFormHelpText')).toHaveLength(1);
});
@ -206,7 +210,7 @@ describe('field level security', () => {
...props,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
const wrapper = mountWithIntl(<IndexPrivilegeForm.WrappedComponent {...testProps} />);
expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1);
expect(wrapper.find('.euiFormHelpText')).toHaveLength(0);
});

View file

@ -15,7 +15,7 @@ import {
EuiSwitch,
EuiTextArea,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React, { ChangeEvent, Component, Fragment } from 'react';
import { IndexPrivilege } from '../../../../../../../common/model/index_privilege';
// @ts-ignore
@ -37,6 +37,7 @@ interface Props {
allowDocumentLevelSecurity: boolean;
allowFieldLevelSecurity: boolean;
validator: RoleValidator;
intl: InjectedIntl;
}
interface State {
@ -44,7 +45,7 @@ interface State {
documentQuery?: string;
}
export class IndexPrivilegeForm extends Component<Props, State> {
class IndexPrivilegeFormUI extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
@ -54,6 +55,7 @@ export class IndexPrivilegeForm extends Component<Props, State> {
}
public render() {
const { intl } = this.props;
return (
<Fragment>
<EuiHorizontalRule />
@ -63,7 +65,11 @@ export class IndexPrivilegeForm extends Component<Props, State> {
<EuiFlexItem grow={false}>
<EuiFormRow hasEmptyLabelSpace>
<EuiButtonIcon
aria-label={'Delete index privilege'}
aria-label={intl.formatMessage({
id:
'xpack.security.management.editRoles.indexPrivilegeForm.deleteSpacePrivilegeAriaLabel',
defaultMessage: 'Delete index privilege',
})}
color={'danger'}
onClick={this.props.onDelete}
iconType={'trash'}
@ -320,3 +326,5 @@ export class IndexPrivilegeForm extends Component<Props, State> {
});
};
}
export const IndexPrivilegeForm = injectI18n(IndexPrivilegeFormUI);

View file

@ -1,9 +1,11 @@
<ng-form name="passwordForm">
<!-- Password -->
<div class="kuiFormSection">
<label class="kuiFormLabel">
Password
</label>
<label
class="kuiFormLabel"
i18n-id="xpack.security.management.passwordForm.passwordLabel"
i18n-default-message="Password"
></label>
<input
type="password"
class="kuiTextInput fullWidth"
@ -19,16 +21,18 @@
<div
class="kuiInputNote kuiInputNote--danger"
ng-show="passwordForm.password.$touched && (passwordForm.password.$error.required || passwordForm.password.$error.minlength)"
>
Password must be at least 6 characters
</div>
i18n-id="xpack.security.management.passwordForm.passwordLengthDescription"
i18n-default-message="Password must be at least 6 characters"
></div>
</div>
<!-- Confirm password -->
<div class="kuiFormSection">
<label class="kuiFormLabel">
Confirm password
</label>
<label
class="kuiFormLabel"
i18n-id="xpack.security.management.passwordForm.confirmPasswordLabel"
i18n-default-message="Confirm password"
></label>
<input
type="password"
class="kuiTextInput fullWidth"
@ -42,8 +46,8 @@
<div
class="kuiInputNote kuiInputNote--danger"
ng-show="passwordForm.confirmation.$touched && (password !== passwordController.confirmation)"
>
Passwords do not match
</div>
i18n-id="xpack.security.management.passwordForm.passwordDontMatchDescription"
i18n-default-message="Passwords do not match"
></div>
</div>
</ng-form>

View file

@ -140,15 +140,9 @@
<span
class="kuiTableHeaderCell__liner"
i18n-id="xpack.security.management.roles.reversedTitle"
i18n-default-message="Reserved {icon}"
i18n-values="{
html_icon: '<span
class=\'kuiIcon fa-question-circle\'
tooltip={{reversedTooltip}}
aria-label={{reversedAriaLabel}}
></span>'
}"
i18n-default-message="Reserved"
></span>
<span class="kuiIcon fa-question-circle" tooltip={{reversedTooltip}} aria-label={{reversedAriaLabel}} ></span>
</th>
</tr>
</thead>

View file

@ -12,6 +12,6 @@
kbn-route="'/logout'"
icon="'plugins/security/images/logout.svg'"
tooltip-content="formatTooltip('Logout')"
label="'Logout'"
label="logoutLabel"
></global-nav-link>
</div>

View file

@ -29,7 +29,7 @@ chromeNavControlsRegistry.register(constant({
}));
const module = uiModules.get('security', ['kibana']);
module.controller('securityNavController', ($scope, ShieldUser, globalNavState, kbnBaseUrl, Private, esDataIsTribe) => {
module.controller('securityNavController', ($scope, ShieldUser, globalNavState, kbnBaseUrl, Private, esDataIsTribe, i18n) => {
const xpackInfo = Private(XPackInfoProvider);
const showSecurityLinks = xpackInfo.get('features.security.showLinks');
if (Private(PathProvider).isUnauthenticated() || !showSecurityLinks) return;
@ -61,6 +61,9 @@ module.controller('securityNavController', ($scope, ShieldUser, globalNavState,
}
};
$scope.logoutLabel = i18n('xpack.security.navControl.logoutLabel', {
defaultMessage: "Logout"
});
});