diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/__snapshots__/collapsible_panel.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/__snapshots__/collapsible_panel.test.tsx.snap index 3b3587c7ff524..a940a55b3754b 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/__snapshots__/collapsible_panel.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/__snapshots__/collapsible_panel.test.tsx.snap @@ -43,7 +43,11 @@ exports[`it renders without blowing up 1`] = ` onClick={[Function]} type="button" > - hide + diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.test.tsx index 86f1e73b78e1b..b1e23cb43983e 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.test.tsx @@ -5,12 +5,12 @@ */ import { EuiLink } from '@elastic/eui'; -import { mount, shallow } from 'enzyme'; import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { CollapsiblePanel } from './collapsible_panel'; test('it renders without blowing up', () => { - const wrapper = shallow( + const wrapper = shallowWithIntl(

child

@@ -20,7 +20,7 @@ test('it renders without blowing up', () => { }); test('it renders children by default', () => { - const wrapper = mount( + const wrapper = mountWithIntl(

child 1

child 2

@@ -32,7 +32,7 @@ test('it renders children by default', () => { }); test('it hides children when the "hide" link is clicked', () => { - const wrapper = mount( + const wrapper = mountWithIntl(

child 1

child 2

diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.tsx index f8271d4d83d2a..1a2907b790c9c 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/collapsible_panel.tsx @@ -13,6 +13,7 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; interface Props { @@ -55,7 +56,19 @@ export class CollapsiblePanel extends Component { - {this.state.collapsed ? 'show' : 'hide'} + + {this.state.collapsed ? ( + + ) : ( + + )} + ); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.test.tsx index 8a78748b46232..cc16866c88355 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.test.tsx @@ -9,20 +9,20 @@ import { // @ts-ignore EuiConfirmModal, } from '@elastic/eui'; -import { mount, shallow } from 'enzyme'; import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { DeleteRoleButton } from './delete_role_button'; test('it renders without crashing', () => { const deleteHandler = jest.fn(); - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper.find(EuiButtonEmpty)).toHaveLength(1); expect(deleteHandler).toHaveBeenCalledTimes(0); }); test('it shows a confirmation dialog when clicked', () => { const deleteHandler = jest.fn(); - const wrapper = mount(); + const wrapper = mountWithIntl(); wrapper.find(EuiButtonEmpty).simulate('click'); @@ -33,7 +33,7 @@ test('it shows a confirmation dialog when clicked', () => { test('it renders nothing when canDelete is false', () => { const deleteHandler = jest.fn(); - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper.find('*')).toHaveLength(0); expect(deleteHandler).toHaveBeenCalledTimes(0); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.tsx index 28b3107a96c42..22820edd73c98 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/delete_role_button.tsx @@ -11,6 +11,7 @@ import { // @ts-ignore EuiOverlayMask, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; interface Props { @@ -35,7 +36,10 @@ export class DeleteRoleButton extends Component { return ( - Delete role + {this.maybeShowModal()} @@ -49,15 +53,40 @@ export class DeleteRoleButton extends Component { return ( + } onCancel={this.closeModal} onConfirm={this.onConfirmDelete} - cancelButtonText={"No, don't delete"} - confirmButtonText={'Yes, delete role'} + cancelButtonText={ + + } + confirmButtonText={ + + } buttonColor={'danger'} > -

Are you sure you want to delete this role?

-

This action cannot be undone!

+

+ +

+

+ +

); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx index 98f8bbcf10873..a3b6b58d09d06 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/edit_role_page.tsx @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { EuiButton, EuiButtonEmpty, @@ -19,6 +20,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { get } from 'lodash'; import React, { ChangeEvent, Component, Fragment, HTMLProps } from 'react'; import { toastNotifications } from 'ui/notify'; @@ -47,6 +49,7 @@ interface Props { spaces?: Space[]; spacesEnabled: boolean; userProfile: UserProfile; + intl: InjectedIntl; } interface State { @@ -54,7 +57,7 @@ interface State { formError: RoleValidationResult | null; } -export class EditRolePage extends Component { +class EditRolePageUI extends Component { private validator: RoleValidator; constructor(props: Props) { @@ -67,9 +70,17 @@ export class EditRolePage extends Component { } public render() { - const description = this.props.spacesEnabled - ? `Set privileges on your Elasticsearch data and control access to your Kibana spaces.` - : `Set privileges on your Elasticsearch data and control access to Kibana.`; + const description = this.props.spacesEnabled ? ( + + ) : ( + + ); return ( @@ -86,7 +97,10 @@ export class EditRolePage extends Component {

- Reserved roles are built-in and cannot be removed or modified. +

@@ -115,12 +129,27 @@ export class EditRolePage extends Component { tabIndex: 0, }; if (isReservedRole(this.props.role)) { - titleText = 'Viewing role'; + titleText = ( + + ); props['aria-describedby'] = 'reservedRoleDescription'; } else if (this.editingExistingRole()) { - titleText = 'Edit role'; + titleText = ( + + ); } else { - titleText = 'Create role'; + titleText = ( + + ); } return ( @@ -148,11 +177,21 @@ export class EditRolePage extends Component { return ( + } helpText={ - !isReservedRole(this.props.role) && this.editingExistingRole() - ? "A role's name cannot be changed once it has been created." - : undefined + !isReservedRole(this.props.role) && this.editingExistingRole() ? ( + + ) : ( + undefined + ) } {...this.validator.validateRoleName(this.state.role)} > @@ -225,10 +264,27 @@ export class EditRolePage extends Component { public getFormButtons = () => { if (isReservedRole(this.props.role)) { - return Return to role list; + return ( + + + + ); } - const saveText = this.editingExistingRole() ? 'Update role' : 'Create role'; + const saveText = this.editingExistingRole() ? ( + + ) : ( + + ); return ( @@ -244,7 +300,10 @@ export class EditRolePage extends Component { - Cancel + @@ -274,7 +333,7 @@ export class EditRolePage extends Component { formError: null, }); - const { httpClient } = this.props; + const { httpClient, intl } = this.props; const role = { ...this.state.role, @@ -287,7 +346,12 @@ export class EditRolePage extends Component { saveRole(httpClient, role) .then(() => { - toastNotifications.addSuccess('Saved role'); + toastNotifications.addSuccess( + intl.formatMessage({ + id: 'xpack.security.management.editRole.roleSuccessfullySavedNotificationMessage', + defaultMessage: 'Saved role', + }) + ); this.backToRoleList(); }) .catch((error: any) => { @@ -297,11 +361,16 @@ export class EditRolePage extends Component { }; public handleDeleteRole = () => { - const { httpClient, role } = this.props; + const { httpClient, role, intl } = this.props; deleteRole(httpClient, role.name) .then(() => { - toastNotifications.addSuccess('Deleted role'); + toastNotifications.addSuccess( + intl.formatMessage({ + id: 'xpack.security.management.editRole.roleSuccessfullyDeletedNotificationMessage', + defaultMessage: 'Deleted role', + }) + ); this.backToRoleList(); }) .catch((error: any) => { @@ -313,3 +382,5 @@ export class EditRolePage extends Component { window.location.hash = ROLES_PATH; }; } + +export const EditRolePage = injectI18n(EditRolePageUI); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap index 416cec99b3271..02d44c23ac5c3 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap @@ -1,181 +1,220 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`it renders without crashing 1`] = ` - - - - Manage the actions this role can perform against your cluster. - - - Learn more - -

- } - fullWidth={false} - gutterSize="l" - title={ + + + + + + + + +

+ } + fullWidth={false} + gutterSize="l" + title={ +

+ +

+ } + titleSize="xs" + > + + + +
+ + + + + + +

+ } + fullWidth={false} + gutterSize="l" + title={ +

+ +

+ } + titleSize="xs" + > + + + +
+ +

- Cluster privileges +

- } - titleSize="xs" - > - + + - - -
- - - Allow requests to be submitted on the behalf of other users. - + - Learn more +

- } - fullWidth={false} - gutterSize="l" - title={ -

- Run As privileges -

- } - titleSize="xs" - > - - - -
- - -

- Index privileges -

-
- - -

- Control access to the data in your cluster. - - - Learn more - -

-
- + - - - Add index privilege - -
-
+ /> + + + + + +
+ `; diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap index c55876b87186b..54446baa76a6f 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privilege_form.test.tsx.snap @@ -39,7 +39,13 @@ exports[`it renders without crashing 1`] = ` fullWidth={true} hasEmptyLabelSpace={false} isInvalid={false} - label="Indices" + label={ + + } > + } > + } + label={ + + } > + } onChange={[Function]} value={false} /> diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx index 3a948801102a5..b58cab2197fe4 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount, shallow } from 'enzyme'; import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { RoleValidator } from '../../../lib/validate_role'; import { ClusterPrivileges } from './cluster_privileges'; import { ElasticsearchPrivileges } from './elasticsearch_privileges'; @@ -34,7 +34,9 @@ test('it renders without crashing', () => { allowFieldLevelSecurity: true, validator: new RoleValidator(), }; - const wrapper = shallow(); + const wrapper = shallowWithIntl( + + ); expect(wrapper).toMatchSnapshot(); }); @@ -61,7 +63,9 @@ test('it renders ClusterPrivileges', () => { allowFieldLevelSecurity: true, validator: new RoleValidator(), }; - const wrapper = mount(); + const wrapper = mountWithIntl( + + ); expect(wrapper.find(ClusterPrivileges)).toHaveLength(1); }); @@ -88,6 +92,8 @@ test('it renders IndexPrivileges', () => { allowFieldLevelSecurity: true, validator: new RoleValidator(), }; - const wrapper = mount(); + const wrapper = mountWithIntl( + + ); expect(wrapper.find(IndexPrivileges)).toHaveLength(1); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx index 2625ff9879d3f..d2caf24053815 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/elasticsearch_privileges.tsx @@ -16,6 +16,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage, I18nProvider, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; import { Role } from '../../../../../../../common/model/role'; // @ts-ignore @@ -36,14 +37,17 @@ interface Props { indexPatterns: string[]; allowDocumentLevelSecurity: boolean; allowFieldLevelSecurity: boolean; + intl: InjectedIntl; } -export class ElasticsearchPrivileges extends Component { +class ElasticsearchPrivilegesUI extends Component { public render() { return ( - - {this.getForm()} - + + + {this.getForm()} + + ); } @@ -56,6 +60,7 @@ export class ElasticsearchPrivileges extends Component { indexPatterns, allowDocumentLevelSecurity, allowFieldLevelSecurity, + intl, } = this.props; const indexProps = { @@ -71,10 +76,20 @@ export class ElasticsearchPrivileges extends Component { return ( Cluster privileges} + title={ +

+ +

+ } description={

- Manage the actions this role can perform against your cluster.{' '} + {this.learnMore(documentationLinks.esClusterPrivileges)}

} @@ -87,17 +102,35 @@ export class ElasticsearchPrivileges extends Component { Run As privileges} + title={ +

+ +

+ } description={

- Allow requests to be submitted on the behalf of other users.{' '} + {this.learnMore(documentationLinks.esRunAsPrivileges)}

} > ({ id: username, label: username, @@ -113,12 +146,20 @@ export class ElasticsearchPrivileges extends Component { -

Index privileges

+

+ +

- Control access to the data in your cluster.{' '} + {this.learnMore(documentationLinks.esIndicesPrivileges)}

@@ -129,7 +170,10 @@ export class ElasticsearchPrivileges extends Component { {this.props.editable && ( - Add index privilege + )}
@@ -138,7 +182,10 @@ export class ElasticsearchPrivileges extends Component { public learnMore = (href: string) => ( - Learn more + ); @@ -189,3 +236,5 @@ export class ElasticsearchPrivileges extends Component { this.props.onChange(role); }; } + +export const ElasticsearchPrivileges = injectI18n(ElasticsearchPrivilegesUI); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx index 2d68676694304..dd3092293d3bc 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { EuiButtonIcon, EuiSwitch, EuiTextArea } from '@elastic/eui'; -import { mount, shallow } from 'enzyme'; import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { RoleValidator } from '../../../lib/validate_role'; import { IndexPrivilegeForm } from './index_privilege_form'; @@ -31,7 +31,7 @@ test('it renders without crashing', () => { onDelete: jest.fn(), }; - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); @@ -62,7 +62,7 @@ describe('delete button', () => { ...props, allowDelete: false, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(EuiButtonIcon)).toHaveLength(0); }); @@ -71,7 +71,7 @@ describe('delete button', () => { ...props, allowDelete: true, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(EuiButtonIcon)).toHaveLength(1); }); @@ -80,7 +80,7 @@ describe('delete button', () => { ...props, allowDelete: true, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); wrapper.find(EuiButtonIcon).simulate('click'); expect(testProps.onDelete).toHaveBeenCalledTimes(1); }); @@ -114,7 +114,7 @@ describe(`document level security`, () => { allowDocumentLevelSecurity: false, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(EuiSwitch)).toHaveLength(0); expect(wrapper.find(EuiTextArea)).toHaveLength(0); }); @@ -128,7 +128,7 @@ describe(`document level security`, () => { }, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(EuiSwitch)).toHaveLength(1); expect(wrapper.find(EuiTextArea)).toHaveLength(0); }); @@ -138,7 +138,7 @@ describe(`document level security`, () => { ...props, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(EuiSwitch)).toHaveLength(1); expect(wrapper.find(EuiTextArea)).toHaveLength(1); }); @@ -172,7 +172,7 @@ describe('field level security', () => { allowFieldLevelSecurity: false, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find('.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(0); }); @@ -181,7 +181,7 @@ describe('field level security', () => { ...props, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1); }); @@ -196,7 +196,7 @@ describe('field level security', () => { }, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1); expect(wrapper.find('.euiFormHelpText')).toHaveLength(1); }); @@ -206,7 +206,7 @@ describe('field level security', () => { ...props, }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find('div.indexPrivilegeForm__grantedFieldsRow')).toHaveLength(1); expect(wrapper.find('.euiFormHelpText')).toHaveLength(0); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx index 6f1416ab43552..42834afa888ee 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx @@ -15,6 +15,7 @@ import { EuiSwitch, EuiTextArea, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { ChangeEvent, Component, Fragment } from 'react'; import { IndexPrivilege } from '../../../../../../../common/model/index_privilege'; // @ts-ignore @@ -81,7 +82,12 @@ export class IndexPrivilegeForm extends Component { + } fullWidth={true} {...this.props.validator.validateIndexPrivilege(this.props.indexPrivilege)} > @@ -96,7 +102,15 @@ export class IndexPrivilegeForm extends Component { - + + } + fullWidth={true} + > { return ( + } fullWidth={true} className="indexPrivilegeForm__grantedFieldsRow" helpText={ - !isReservedRole && grant.length === 0 - ? 'If no fields are granted, then users assigned to this role will not be able to see any data for this index.' - : undefined + !isReservedRole && grant.length === 0 ? ( + + ) : ( + undefined + ) } > @@ -170,7 +194,12 @@ export class IndexPrivilegeForm extends Component { + } // @ts-ignore compressed={true} // @ts-ignore @@ -181,7 +210,15 @@ export class IndexPrivilegeForm extends Component { )} {this.state.queryExpanded && ( - + + } + fullWidth={true} + > { allowFieldLevelSecurity: true, validator: new RoleValidator(), }; - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); @@ -65,6 +65,6 @@ test('it renders a IndexPrivilegeForm for each privilege on the role', () => { allowFieldLevelSecurity: true, validator: new RoleValidator(), }; - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(IndexPrivilegeForm)).toHaveLength(1); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/impacted_spaces_flyout.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/impacted_spaces_flyout.test.tsx.snap index c67cde88bb444..c749a49bce110 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/impacted_spaces_flyout.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/impacted_spaces_flyout.test.tsx.snap @@ -10,7 +10,11 @@ exports[` renders without crashing 1`] = ` onClick={[Function]} type="button" > - View summary of spaces privileges +
diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges.test.tsx.snap index 50ef26bbe56ac..82d0190ad54cc 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges.test.tsx.snap @@ -1,56 +1,58 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` renders without crashing 1`] = ` - - + + - + /> + + `; diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_callout_warning.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_callout_warning.test.tsx.snap index 53f3fc716d65e..bdce226863ef3 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_callout_warning.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_callout_warning.test.tsx.snap @@ -3,13 +3,101 @@ exports[`PrivilegeCalloutWarning renders without crashing 1`] = ` + } >
- Minimum privilege is too high to customize individual spaces + + Minimum privilege is too high to customize individual spaces +

- Setting the minimum privilege to - - all - - grants full access to all spaces. To customize privileges for individual spaces, the minimum privilege must be either - - read - - or - - none - - . + + + , + "noneText": + + , + "readText": + + , + } + } + > + Setting the minimum privilege to + + + all + + + grants full access to all + spaces. To customize privileges for individual spaces, the minimum privilege must be + either + + + read + + + or + + + none + + + . +

diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_space_form.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_space_form.test.tsx.snap index c24b2d596ff22..a435e7c43ceb1 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_space_form.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/privilege_space_form.test.tsx.snap @@ -19,7 +19,13 @@ exports[` renders without crashing 1`] = ` fullWidth={false} hasEmptyLabelSpace={false} isInvalid={false} - label="Spaces" + label={ + + } > renders without crashing 1`] = ` fullWidth={false} hasEmptyLabelSpace={false} isInvalid={false} - label="Privilege" + label={ + + } > renders without crashing 1`] = ` - Specifies the Kibana privilege for this role. +

} fullWidth={false} gutterSize="l" title={

- Kibana privileges +

} titleSize="xs" diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/space_aware_privilege_form.test.tsx.snap b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/space_aware_privilege_form.test.tsx.snap index c032aec950064..da21290b11e24 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/space_aware_privilege_form.test.tsx.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/space_aware_privilege_form.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` hides the space table if there are no existing space privileges 1`] = ` - hides the space table if there are no existin }, ] } -/> +> + + `; exports[` renders without crashing 1`] = ` @@ -47,14 +169,22 @@ exports[` renders without crashing 1`] = ` - Specify the minimum actions users can perform in your spaces. +

} fullWidth={false} gutterSize="l" title={

- Minimum privileges for all spaces +

} titleSize="xs" @@ -89,7 +219,11 @@ exports[` renders without crashing 1`] = ` textTransform="none" >

- Higher privileges for individual spaces +

renders without crashing 1`] = ` size="s" >

- Grant more privileges on a per space basis. For example, if the privileges are - - - read - - for all spaces, you can set the privileges to - - all - - - for an individual space. + + + , + "read": + + , + } + } + />

- renders without crashing 1`] = ` size="s" type="button" > - Add space privilege + - with user profile disabling "manageSpaces" re size="m" title={

- Insufficient Privileges +

} >

- You are not authorized to view all available spaces. +

- Please ensure your account has all privileges granted by the - - - kibana_user - - role, and try again. + + + , + } + } + />

`; diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.test.tsx index 721fcffeb5b1c..8a103ff493165 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.test.tsx @@ -52,16 +52,24 @@ const buildProps = (customProps = {}) => { describe('', () => { it('renders without crashing', () => { - expect(shallowWithIntl()).toMatchSnapshot(); + expect( + shallowWithIntl( + + ) + ).toMatchSnapshot(); }); it('does not immediately show the flyout', () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); expect(wrapper.find(EuiFlyout)).toHaveLength(0); }); it('shows the flyout after clicking the link', () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); wrapper.find(EuiLink).simulate('click'); expect(wrapper.find(EuiFlyout)).toHaveLength(1); }); @@ -82,7 +90,9 @@ describe('', () => { }, }); - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl( + + ); wrapper.find(EuiLink).simulate('click'); const table = wrapper.find(PrivilegeSpaceTable); @@ -112,7 +122,9 @@ describe('', () => { }, }); - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl( + + ); wrapper.find(EuiLink).simulate('click'); const table = wrapper.find(PrivilegeSpaceTable); @@ -141,7 +153,9 @@ describe('', () => { }, }); - const wrapper = shallowWithIntl(); + const wrapper = shallowWithIntl( + + ); wrapper.find(EuiLink).simulate('click'); const table = wrapper.find(PrivilegeSpaceTable); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.tsx index 1636bf14a484a..f811912e6148f 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/impacted_spaces_flyout.tsx @@ -12,6 +12,7 @@ import { EuiLink, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; import { PrivilegeSpaceTable } from './privilege_space_table'; @@ -26,13 +27,14 @@ interface Props { role: Role; spaces: Space[]; userProfile: UserProfile; + intl: InjectedIntl; } interface State { showImpactedSpaces: boolean; } -export class ImpactedSpacesFlyout extends Component { +class ImpactedSpacesFlyoutUI extends Component { constructor(props: Props) { super(props); this.state = { @@ -46,7 +48,10 @@ export class ImpactedSpacesFlyout extends Component {
- View summary of spaces privileges +
{flyout} @@ -61,13 +66,23 @@ export class ImpactedSpacesFlyout extends Component { }; public getHighestPrivilege(...privileges: KibanaPrivilege[]): KibanaPrivilege { + const { intl } = this.props; if (privileges.indexOf('all') >= 0) { - return 'all'; + return intl.formatMessage({ + id: 'xpack.security.management.editRoles.impactedSpacesFlyout.allLabel', + defaultMessage: 'all', + }) as KibanaPrivilege; } if (privileges.indexOf('read') >= 0) { - return 'read'; + return intl.formatMessage({ + id: 'xpack.security.management.editRoles.impactedSpacesFlyout.readLabel', + defaultMessage: 'read', + }) as KibanaPrivilege; } - return 'none'; + return intl.formatMessage({ + id: 'xpack.security.management.editRoles.impactedSpacesFlyout.noneLabel', + defaultMessage: 'none', + }) as KibanaPrivilege; } public getFlyout = () => { @@ -106,7 +121,12 @@ export class ImpactedSpacesFlyout extends Component { > -

Summary of space privileges

+

+ +

@@ -125,3 +145,5 @@ export class ImpactedSpacesFlyout extends Component { ); }; } + +export const ImpactedSpacesFlyout = injectI18n(ImpactedSpacesFlyoutUI); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/kibana_privileges.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/kibana_privileges.tsx index 80d848b5893d5..12783ecd150bf 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/kibana_privileges.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/kibana_privileges.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { I18nProvider } from '@kbn/i18n/react'; import React, { Component } from 'react'; import { Space } from '../../../../../../../../spaces/common/model/space'; import { UserProfile } from '../../../../../../../../xpack_main/public/services/user_profile'; @@ -28,9 +29,11 @@ interface Props { export class KibanaPrivileges extends Component { public render() { return ( - - {this.getForm()} - + + + {this.getForm()} + + ); } diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.test.tsx index 1e8d3f3c39158..4ee2640ed1c9e 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.test.tsx @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount } from 'enzyme'; import React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { PrivilegeCalloutWarning } from './privilege_callout_warning'; describe('PrivilegeCalloutWarning', () => { it('renders without crashing', () => { expect( - mount() + mountWithIntl() ).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.tsx index 0b5666f391573..ed24e61e5f1fd 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_callout_warning.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { EuiCallOut } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component } from 'react'; import { KibanaPrivilege } from '../../../../../../../common/model/kibana_privilege'; import { NO_PRIVILEGE_VALUE } from '../../../lib/constants'; @@ -33,11 +34,19 @@ export class PrivilegeCalloutWarning extends Component { + } >

- This role always grants full access to all spaces. To customize privileges for - individual spaces, you must create a new role. +

); @@ -46,12 +55,46 @@ export class PrivilegeCalloutWarning extends Component { + } >

- Setting the minimum privilege to all grants full access to all - spaces. To customize privileges for individual spaces, the minimum privilege must be - either read or none. + + + + ), + readText: ( + + + + ), + noneText: ( + + + + ), + }} + />

); @@ -64,11 +107,19 @@ export class PrivilegeCalloutWarning extends Component { + } >

- This role always grants read access to all spaces. To customize privileges for - individual spaces, you must create a new role. +

); @@ -79,7 +130,20 @@ export class PrivilegeCalloutWarning extends Component { iconType="iInCircle" title={ - The minimal possible privilege is read. + + + + ), + }} + /> } /> @@ -92,11 +156,19 @@ export class PrivilegeCalloutWarning extends Component { + } >

- This role never grants access to any spaces within Kibana. To customize privileges for - individual spaces, you must create a new role. +

); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.test.tsx index 95494567446b7..800c628b17243 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { KibanaPrivilege } from '../../../../../../../common/model/kibana_privilege'; import { RoleValidator } from '../../../lib/validate_role'; import { PrivilegeSpaceForm } from './privilege_space_form'; @@ -40,6 +40,6 @@ const buildProps = (customProps = {}) => { describe('', () => { it('renders without crashing', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallowWithIntl()).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.tsx index cf7bcf8287b9d..4907a5b41a53c 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/privilege_space_form.tsx @@ -5,6 +5,7 @@ */ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component } from 'react'; import { Space } from '../../../../../../../../spaces/common/model/space'; import { KibanaPrivilege } from '../../../../../../../common/model/kibana_privilege'; @@ -41,7 +42,12 @@ export class PrivilegeSpaceForm extends Component { + } {...validator.validateSelectedSpaces(selectedSpaceIds, selectedPrivilege)} > { + } {...validator.validateSelectedPrivilege(selectedSpaceIds, selectedPrivilege)} > void; readonly?: boolean; + intl: InjectedIntl; } interface State { @@ -35,13 +37,13 @@ interface DeletedSpace extends Space { deleted: boolean; } -export class PrivilegeSpaceTable extends Component { +class PrivilegeSpaceTableUI extends Component { public state = { searchTerm: '', }; public render() { - const { role, spaces, availablePrivileges, spacePrivileges } = this.props; + const { role, spaces, availablePrivileges, spacePrivileges, intl } = this.props; const { searchTerm } = this.state; @@ -74,7 +76,10 @@ export class PrivilegeSpaceTable extends Component { search={{ box: { incremental: true, - placeholder: 'Filter', + placeholder: intl.formatMessage({ + id: 'xpack.security.management.editRoles.privilegeSpaceTable.filterPlaceholder', + defaultMessage: 'Filter', + }), }, onChange: (search: any) => { this.setState({ @@ -88,6 +93,7 @@ export class PrivilegeSpaceTable extends Component { } public getTableColumns = (role: Role, availablePrivileges: KibanaPrivilege[] = []) => { + const { intl } = this.props; const columns: any[] = [ { field: 'space', @@ -103,11 +109,22 @@ export class PrivilegeSpaceTable extends Component { }, { field: 'space', - name: 'Space', + name: intl.formatMessage({ + id: 'xpack.security.management.editRoles.privilegeSpaceTable.spaceName', + defaultMessage: 'Space', + }), width: this.props.readonly ? '75%' : '50%', render: (space: Space | DeletedSpace) => { if ('deleted' in space) { - return {space.id} (deleted); + return ( + + + + ); } else { return {space.name}; } @@ -115,7 +132,10 @@ export class PrivilegeSpaceTable extends Component { }, { field: 'privilege', - name: 'Privilege', + name: intl.formatMessage({ + id: 'xpack.security.management.editRoles.privilegeSpaceTable.privilegeName', + defaultMessage: 'Privilege', + }), width: this.props.readonly ? '25%' : undefined, render: (privilege: KibanaPrivilege, record: any) => { if (this.props.readonly || record.space.deleted) { @@ -137,7 +157,10 @@ export class PrivilegeSpaceTable extends Component { ]; if (!this.props.readonly) { columns.push({ - name: 'Actions', + name: intl.formatMessage({ + id: 'xpack.security.management.editRoles.privilegeSpaceTable.actionsName', + defaultMessage: 'Actions', + }), actions: [ { render: (record: any) => { @@ -182,3 +205,5 @@ export class PrivilegeSpaceTable extends Component { } }; } + +export const PrivilegeSpaceTable = injectI18n(PrivilegeSpaceTableUI); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.test.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.test.tsx index d6ecbdb705b74..00221e2cd144f 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.test.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.test.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount, shallow } from 'enzyme'; import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { PrivilegeSelector } from './privilege_selector'; import { SimplePrivilegeForm } from './simple_privilege_form'; @@ -32,12 +32,12 @@ const buildProps = (customProps?: any) => { describe('', () => { it('renders without crashing', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallowWithIntl()).toMatchSnapshot(); }); it('displays "none" when no privilege is selected', () => { const props = buildProps(); - const wrapper = shallow(); + const wrapper = shallowWithIntl(); const selector = wrapper.find(PrivilegeSelector); expect(selector.props()).toMatchObject({ value: 'none', @@ -53,7 +53,7 @@ describe('', () => { }, }, }); - const wrapper = shallow(); + const wrapper = shallowWithIntl(); const selector = wrapper.find(PrivilegeSelector); expect(selector.props()).toMatchObject({ value: 'read', @@ -62,7 +62,7 @@ describe('', () => { it('fires its onChange callback when the privilege changes', () => { const props = buildProps(); - const wrapper = mount(); + const wrapper = mountWithIntl(); const selector = wrapper.find(PrivilegeSelector).find('select'); selector.simulate('change', { target: { value: 'all' } }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.tsx index 71b881c4a85ef..ceec0d2124889 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_form.tsx @@ -9,6 +9,7 @@ import { EuiDescribedFormGroup, EuiFormRow, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; import { KibanaPrivilege } from '../../../../../../../common/model/kibana_privilege'; import { Role } from '../../../../../../../common/model/role'; @@ -35,11 +36,28 @@ export class SimplePrivilegeForm extends Component { ? (assignedPrivileges.global[0] as KibanaPrivilege) : NO_PRIVILEGE_VALUE; - const description =

Specifies the Kibana privilege for this role.

; + const description = ( +

+ +

+ ); return ( - Kibana privileges} description={description}> + + + + } + description={description} + > { describe('', () => { it('renders without crashing', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallowWithIntl() + ).toMatchSnapshot(); }); it('shows the space table if exisitng space privileges are declared', () => { @@ -66,7 +68,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const table = wrapper.find(PrivilegeSpaceTable); expect(table).toHaveLength(1); @@ -75,7 +77,7 @@ describe('', () => { it('hides the space table if there are no existing space privileges', () => { const props = buildProps(); - const wrapper = mount(); + const wrapper = mountWithIntl(); const table = wrapper.find(PrivilegeSpaceTable); expect(table).toMatchSnapshot(); @@ -96,7 +98,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); expect(wrapper.find(PrivilegeSpaceForm)).toHaveLength(0); wrapper.find('button[data-test-subj="addSpacePrivilegeButton"]').simulate('click'); @@ -120,7 +122,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const warning = wrapper.find(PrivilegeCalloutWarning); expect(warning.props()).toMatchObject({ @@ -151,7 +153,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const warning = wrapper.find(PrivilegeCalloutWarning); expect(warning.props()).toMatchObject({ @@ -174,7 +176,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const table = wrapper.find(PrivilegeSpaceTable); expect(table).toHaveLength(1); @@ -200,7 +202,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const warning = wrapper.find(PrivilegeCalloutWarning); expect(warning).toHaveLength(0); @@ -221,7 +223,7 @@ describe('', () => { }, }); - const wrapper = mount(); + const wrapper = mountWithIntl(); const table = wrapper.find(PrivilegeSpaceTable); expect(table).toHaveLength(1); @@ -244,7 +246,7 @@ describe('', () => { }, }); - const wrapper = shallow(); + const wrapper = shallowWithIntl(); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_form.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_form.tsx index 6928d46565e66..cd4bdb2f41b44 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_form.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_form.tsx @@ -16,6 +16,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; import { Space } from '../../../../../../../../spaces/common/model/space'; import { UserProfile } from '../../../../../../../../xpack_main/public/services/user_profile'; @@ -40,6 +41,7 @@ interface Props { editable: boolean; validator: RoleValidator; userProfile: UserProfile; + intl: InjectedIntl; } interface PrivilegeForm { @@ -56,7 +58,7 @@ interface State { privilegeForms: PrivilegeForm[]; } -export class SpaceAwarePrivilegeForm extends Component { +class SpaceAwarePrivilegeFormUI extends Component { constructor(props: Props) { super(props); const { role } = props; @@ -73,15 +75,44 @@ export class SpaceAwarePrivilegeForm extends Component { } public render() { - const { kibanaAppPrivileges, role, userProfile } = this.props; + const { kibanaAppPrivileges, role, userProfile, intl } = this.props; if (!userProfile.hasCapability('manageSpaces')) { return ( - Insufficient Privileges

} iconType="alert" color="danger"> -

You are not authorized to view all available spaces.

+ + +

+ } + iconType="alert" + color="danger" + >

- Please ensure your account has all privileges granted by the{' '} - kibana_user role, and try again. + +

+

+ + + + ), + }} + />

); @@ -92,21 +123,46 @@ export class SpaceAwarePrivilegeForm extends Component { const basePrivilege = assignedPrivileges.global.length > 0 ? assignedPrivileges.global[0] : NO_PRIVILEGE_VALUE; - const description =

Specify the minimum actions users can perform in your spaces.

; + const description = ( +

+ +

+ ); let helptext; if (basePrivilege === NO_PRIVILEGE_VALUE) { - helptext = 'No access to spaces'; + helptext = intl.formatMessage({ + id: 'xpack.security.management.editRoles.spaceAwarePrivilegeForm.noAccessToSpacesHelpText', + defaultMessage: 'No access to spaces', + }); } else if (basePrivilege === 'all') { - helptext = 'View, edit, and share objects and apps within all spaces'; + helptext = intl.formatMessage({ + id: + 'xpack.security.management.editRoles.spaceAwarePrivilegeForm.viewEditShareAppsWithinAllSpacesHelpText', + defaultMessage: 'View, edit, and share objects and apps within all spaces', + }); } else if (basePrivilege === 'read') { - helptext = 'View objects and apps within all spaces'; + helptext = intl.formatMessage({ + id: + 'xpack.security.management.editRoles.spaceAwarePrivilegeForm.viewObjectsAndAppsWithinAllSpacesHelpText', + defaultMessage: 'View objects and apps within all spaces', + }); } return ( Minimum privileges for all spaces} + title={ +

+ +

+ } description={description} > @@ -147,7 +203,12 @@ export class SpaceAwarePrivilegeForm extends Component { return ( -

Higher privileges for individual spaces

+

+ +

{ color={'subdued'} >

- Grant more privileges on a per space basis. For example, if the privileges are{' '} - read for all spaces, you can set the privileges to all{' '} - for an individual space. + + + + ), + all: ( + + + + ), + }} + />

@@ -200,7 +282,10 @@ export class SpaceAwarePrivilegeForm extends Component { iconType={'plusInCircle'} onClick={this.addSpacePrivilege} > - Add space privilege +
)} @@ -367,3 +452,5 @@ export class SpaceAwarePrivilegeForm extends Component { this.props.onChange(role); }; } + +export const SpaceAwarePrivilegeForm = injectI18n(SpaceAwarePrivilegeFormUI); diff --git a/x-pack/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx b/x-pack/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx index 2966c78d2d92a..77f6bc85cf073 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx +++ b/x-pack/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { EuiIcon, EuiToolTip } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { Role } from '../../../../../common/model/role'; import { isReservedRole } from '../../../../lib/role'; @@ -19,7 +20,14 @@ export const ReservedRoleBadge = (props: Props) => { if (isReservedRole(role)) { return ( - + + } + > ); diff --git a/x-pack/plugins/security/public/views/management/edit_role/index.js b/x-pack/plugins/security/public/views/management/edit_role/index.js index 4d2e83a6f8072..2377542834ed7 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/index.js +++ b/x-pack/plugins/security/public/views/management/edit_role/index.js @@ -28,6 +28,7 @@ import { EditRolePage } from './components'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { KibanaAppPrivileges } from '../../../../common/model/kibana_privilege'; +import { I18nProvider } from '@kbn/i18n/react'; routes.when(`${EDIT_ROLES_PATH}/:name?`, { template, @@ -126,20 +127,23 @@ routes.when(`${EDIT_ROLES_PATH}/:name?`, { $scope.$$postDigest(() => { const domNode = document.getElementById('editRoleReactRoot'); - render(, domNode); + render( + + + , domNode); // unmount react on controller destroy $scope.$on('$destroy', () => { diff --git a/x-pack/plugins/security/public/views/management/edit_role/lib/__snapshots__/validate_role.test.ts.snap b/x-pack/plugins/security/public/views/management/edit_role/lib/__snapshots__/validate_role.test.ts.snap index 1f4837b07d0b9..faf1f4704ce0d 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/lib/__snapshots__/validate_role.test.ts.snap +++ b/x-pack/plugins/security/public/views/management/edit_role/lib/__snapshots__/validate_role.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`validateIndexPrivileges it throws when indices is not an array 1`] = `"Expected role.elasticsearch.indices to be an array"`; +exports[`validateIndexPrivileges it throws when indices is not an array 1`] = `"Expected \\"role.elasticsearch.indices\\" to be an array"`; diff --git a/x-pack/plugins/security/public/views/management/edit_role/lib/validate_role.ts b/x-pack/plugins/security/public/views/management/edit_role/lib/validate_role.ts index f4ada14fde8ef..133d901b6e166 100644 --- a/x-pack/plugins/security/public/views/management/edit_role/lib/validate_role.ts +++ b/x-pack/plugins/security/public/views/management/edit_role/lib/validate_role.ts @@ -10,6 +10,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { IndexPrivilege } from '../../../../../common/model/index_privilege'; import { KibanaPrivilege } from '../../../../../common/model/kibana_privilege'; import { Role } from '../../../../../common/model/role'; @@ -52,14 +53,34 @@ export class RoleValidator { } if (!role.name) { - return invalid(`Please provide a role name`); + return invalid( + i18n.translate( + 'xpack.security.management.editRoles.validateRole.provideRoleNameWarningMessage', + { + defaultMessage: 'Please provide a role name', + } + ) + ); } if (role.name.length > 1024) { - return invalid(`Name must not exceed 1024 characters`); + return invalid( + i18n.translate( + 'xpack.security.management.editRoles.validateRole.nameLengthWarningMessage', + { + defaultMessage: 'Name must not exceed 1024 characters', + } + ) + ); } if (!role.name.match(/^[a-zA-Z_][a-zA-Z0-9_@\-\$\.]*$/)) { return invalid( - `Name must begin with a letter or underscore and contain only letters, underscores, and numbers.` + i18n.translate( + 'xpack.security.management.editRoles.validateRole.nameAllowedCharactersWarningMessage', + { + defaultMessage: + 'Name must begin with a letter or underscore and contain only letters, underscores, and numbers.', + } + ) ); } return valid(); @@ -71,7 +92,14 @@ export class RoleValidator { } if (!Array.isArray(role.elasticsearch.indices)) { - throw new TypeError(`Expected role.elasticsearch.indices to be an array`); + throw new TypeError( + i18n.translate('xpack.security.management.editRoles.validateRole.indicesTypeErrorMessage', { + defaultMessage: 'Expected {elasticIndices} to be an array', + values: { + elasticIndices: '"role.elasticsearch.indices"', + }, + }) + ); } const areIndicesValid = @@ -91,7 +119,14 @@ export class RoleValidator { } if (indexPrivilege.names.length && !indexPrivilege.privileges.length) { - return invalid(`At least one privilege is required`); + return invalid( + i18n.translate( + 'xpack.security.management.editRoles.validateRole.onePrivilegeRequiredWarningMessage', + { + defaultMessage: 'At least one privilege is required', + } + ) + ); } return valid(); } @@ -112,7 +147,14 @@ export class RoleValidator { if (Array.isArray(spaceIds) && spaceIds.length > 0) { return valid(); } - return invalid('At least one space is required'); + return invalid( + i18n.translate( + 'xpack.security.management.editRoles.validateRole.oneSpaceRequiredWarningMessage', + { + defaultMessage: 'At least one space is required', + } + ) + ); } public validateSelectedPrivilege( @@ -131,7 +173,14 @@ export class RoleValidator { if (privilege) { return valid(); } - return invalid('Privilege is required'); + return invalid( + i18n.translate( + 'xpack.security.management.editRoles.validateRole.privilegeRequiredWarningMessage', + { + defaultMessage: 'Privilege is required', + } + ) + ); } public setInProgressSpacePrivileges(inProgressSpacePrivileges: any[]) { diff --git a/x-pack/plugins/security/public/views/management/management.js b/x-pack/plugins/security/public/views/management/management.js index f06b59a29c061..1637b35d3e55b 100644 --- a/x-pack/plugins/security/public/views/management/management.js +++ b/x-pack/plugins/security/public/views/management/management.js @@ -16,6 +16,7 @@ import '../../services/shield_user'; import { ROLES_PATH, USERS_PATH } from './management_urls'; import { management } from 'ui/management'; +import { i18n } from '@kbn/i18n'; routes.defaults(/\/management/, { resolve: { @@ -30,7 +31,10 @@ routes.defaults(/\/management/, { function ensureSecurityRegistered() { const registerSecurity = () => management.register('security', { - display: 'Security', + display: i18n.translate( + 'xpack.security.management.securityTitle', { + defaultMessage: 'Security', + }), order: 10, icon: 'securityApp', }); @@ -42,7 +46,10 @@ routes.defaults(/\/management/, { security.register('users', { name: 'securityUsersLink', order: 10, - display: 'Users', + display: i18n.translate( + 'xpack.security.management.usersTitle', { + defaultMessage: 'Users', + }), url: esDataIsTribe ? undefined : `#${USERS_PATH}`, tooltip: esDataIsTribe ? tribeTooltip : undefined }); @@ -52,7 +59,10 @@ routes.defaults(/\/management/, { security.register('roles', { name: 'securityRolesLink', order: 20, - display: 'Roles', + display: i18n.translate( + 'xpack.security.management.rolesTitle', { + defaultMessage: 'Roles', + }), url: esDataIsTribe ? undefined : `#${ROLES_PATH}`, tooltip: esDataIsTribe ? tribeTooltip : undefined }); diff --git a/x-pack/plugins/security/public/views/management/roles.html b/x-pack/plugins/security/public/views/management/roles.html index 941ab6ed331b2..a7b77228c0376 100644 --- a/x-pack/plugins/security/public/views/management/roles.html +++ b/x-pack/plugins/security/public/views/management/roles.html @@ -3,15 +3,19 @@
- - You do not have permission to manage roles. - +
-
- Please contact your administrator. -
+
@@ -30,7 +34,7 @@ aria-label="Filter" ng-model="query" > - +
@@ -42,7 +46,10 @@ > - Delete + @@ -54,7 +61,11 @@ ng-if="!selectedRoles.length" data-test-subj="createRoleButton" > - Create role + +
@@ -65,8 +76,23 @@
-
- No matching roles found. +
+ + +
@@ -97,7 +123,10 @@ aria-label="{{sort.reverse ? 'Sort role ascending' : 'Sort role descending'}}" > - Role +
@@ -175,9 +212,13 @@
-
- {{ selectedRoles.length }} roles selected -
+
diff --git a/x-pack/plugins/security/public/views/management/roles.js b/x-pack/plugins/security/public/views/management/roles.js index 7771cee0906de..903d92a99da6e 100644 --- a/x-pack/plugins/security/public/views/management/roles.js +++ b/x-pack/plugins/security/public/views/management/roles.js @@ -25,25 +25,34 @@ routes.when(ROLES_PATH, { roles(ShieldRole, kbnUrl, Promise, Private) { // $promise is used here because the result is an ngResource, not a promise itself - return ShieldRole.query().$promise - .catch(checkLicenseError(kbnUrl, Promise, Private)) + return ShieldRole.query() + .$promise.catch(checkLicenseError(kbnUrl, Promise, Private)) .catch(_.identity); // Return the error if there is one - } + }, }, - controller($scope, $route, $q, confirmModal) { + controller($scope, $route, $q, confirmModal, i18n) { $scope.roles = $route.current.locals.roles; $scope.forbidden = !_.isArray($scope.roles); $scope.selectedRoles = []; $scope.sort = { orderBy: 'name', reverse: false }; $scope.editRolesHref = `#${EDIT_ROLES_PATH}`; - $scope.getEditRoleHref = (role) => `#${EDIT_ROLES_PATH}/${role}`; + $scope.getEditRoleHref = role => `#${EDIT_ROLES_PATH}/${role}`; $scope.deleteRoles = () => { const doDelete = () => { - $q.all($scope.selectedRoles.map((role) => role.$delete())) - .then(() => toastNotifications.addSuccess(`Deleted ${$scope.selectedRoles.length > 1 ? 'roles' : 'role'}`)) + $q.all($scope.selectedRoles.map(role => role.$delete())) + .then(() => + toastNotifications.addSuccess( + i18n('xpack.security.management.roles.deleteRoleTitle', { + defaultMessage: 'Deleted {value, plural, one {role} other {roles}}', + values: { + value: $scope.selectedRoles.length, + }, + }) + ) + ) .then(() => { - $scope.selectedRoles.map((role) => { + $scope.selectedRoles.map(role => { const i = $scope.roles.indexOf(role); $scope.roles.splice(i, 1); }); @@ -51,12 +60,17 @@ routes.when(ROLES_PATH, { }); }; const confirmModalOptions = { - confirmButtonText: 'Delete role(s)', - onConfirm: doDelete + confirmButtonText: i18n('xpack.security.management.roles.deleteRoleConfirmButtonLabel', { + defaultMessage: 'Delete role(s)', + }), + onConfirm: doDelete, }; - confirmModal(` - Are you sure you want to delete the selected role(s)? This action is irreversible!`, - confirmModalOptions + confirmModal( + i18n('xpack.security.management.roles.deletingRolesWarningMessage', { + defaultMessage: + 'Are you sure you want to delete the selected role(s)? This action is irreversible!', + }), + confirmModalOptions ); }; @@ -89,7 +103,16 @@ routes.when(ROLES_PATH, { $scope.toggleSort = toggleSort; function getActionableRoles() { - return $scope.roles.filter((role) => !role.metadata._reserved); + return $scope.roles.filter(role => !role.metadata._reserved); } - } + + $scope.reversedTooltip = i18n('xpack.security.management.roles.reversedTooltip', { + defaultMessage: 'Reserved roles are built-in and cannot be removed or modified. Only the password may be changed.', + }); + + $scope.reversedAriaLabel = i18n('xpack.security.management.roles.reversedAriaLabel', { + defaultMessage: 'Reserved roles are built-in and cannot be removed or modified. Only the password may be changed.', + }); + + }, });