Skip to content

Commit

Permalink
[7.x] Convert role listing page React/EUI (#30970) (#35803)
Browse files Browse the repository at this point in the history
  • Loading branch information
legrego authored Apr 30, 2019
1 parent 4addad7 commit 614ff20
Show file tree
Hide file tree
Showing 27 changed files with 932 additions and 442 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
EuiButton,
EuiIcon,
EuiLink,
EuiFlexGroup,
EuiInMemoryTable,
EuiPageContent,
EuiTitle,
Expand Down Expand Up @@ -91,28 +92,29 @@ class UsersUI extends Component {
const { intl } = this.props;
if (permissionDenied) {
return (
<div className="secUsersListingPage">
<EuiFlexGroup gutterSize="none">
<EuiPageContent horizontalPosition="center">
<EuiEmptyPrompt
iconType="securityApp"
iconColor={null}
title={
<h2>
<FormattedMessage
id="xpack.security.management.users.deniedPermissionTitle"
defaultMessage="Permission denied"
defaultMessage="You need permission to manage users"
/>
</h2>}
</h2>
}
body={
<p data-test-subj="permissionDeniedMessage">
<FormattedMessage
id="xpack.security.management.users.permissionDeniedToManageUsersDescription"
defaultMessage="You do not have permission to manage users."
defaultMessage="Contact your system administrator."
/>
</p>}
</p>
}
/>
</EuiPageContent>
</div>
</EuiFlexGroup>
);
}
const path = '#/management/security/';
Expand Down Expand Up @@ -241,7 +243,7 @@ class UsersUI extends Component {
>
<FormattedMessage
id="xpack.security.management.users.createNewUserButtonLabel"
defaultMessage="Create new user"
defaultMessage="Create user"
/>
</EuiButton>
</EuiPageContentHeaderSection>
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/security/public/lib/role_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ describe('role', () => {
expect(isReadOnlyRole(testRole)).toBe(true);
});

test('returns false for disabled roles', () => {
const testRole = {
transient_metadata: {
enabled: false,
},
};
expect(isReadOnlyRole(testRole)).toBe(false);
});

test('returns false for all other roles', () => {
const testRole = {};
expect(isReadOnlyRole(testRole)).toBe(false);
Expand Down
25 changes: 25 additions & 0 deletions x-pack/plugins/security/public/lib/roles_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { kfetch } from 'ui/kfetch';
import { Role } from '../../common/model/role';

export class RolesApi {
public static async getRoles(): Promise<Role[]> {
return kfetch({ pathname: '/api/security/role' });
}

public static async getRole(roleName: string): Promise<Role> {
return kfetch({ pathname: `/api/security/role/${encodeURIComponent(roleName)}` });
}

public static async deleteRole(roleName: string) {
return kfetch({
pathname: `/api/security/role/${encodeURIComponent(roleName)}`,
method: 'DELETE',
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class EditRolePageUI extends Component<Props, State> {
);
}

public getFormTitle = () => {
private getFormTitle = () => {
let titleText;
const props: HTMLProps<HTMLDivElement> = {
tabIndex: 0,
Expand Down Expand Up @@ -156,7 +156,7 @@ class EditRolePageUI extends Component<Props, State> {
);
};

public getActionButton = () => {
private getActionButton = () => {
if (this.editingExistingRole() && !isReadOnlyRole(this.props.role)) {
return (
<EuiFlexItem grow={false}>
Expand All @@ -168,7 +168,7 @@ class EditRolePageUI extends Component<Props, State> {
return null;
};

public getRoleName = () => {
private getRoleName = () => {
return (
<EuiPanel>
<EuiFormRow
Expand Down Expand Up @@ -202,7 +202,7 @@ class EditRolePageUI extends Component<Props, State> {
);
};

public onNameChange = (e: ChangeEvent<HTMLInputElement>) => {
private onNameChange = (e: ChangeEvent<HTMLInputElement>) => {
const rawValue = e.target.value;
const name = rawValue.replace(/\s/g, '_');

Expand All @@ -214,7 +214,7 @@ class EditRolePageUI extends Component<Props, State> {
});
};

public getElasticsearchPrivileges() {
private getElasticsearchPrivileges() {
return (
<div>
<EuiSpacer />
Expand All @@ -233,13 +233,13 @@ class EditRolePageUI extends Component<Props, State> {
);
}

public onRoleChange = (role: Role) => {
private onRoleChange = (role: Role) => {
this.setState({
role,
});
};

public getKibanaPrivileges = () => {
private getKibanaPrivileges = () => {
return (
<div>
<EuiSpacer />
Expand All @@ -259,18 +259,33 @@ class EditRolePageUI extends Component<Props, State> {
);
};

public getFormButtons = () => {
private getFormButtons = () => {
if (isReadOnlyRole(this.props.role)) {
return (
<EuiButton onClick={this.backToRoleList} data-test-subj="roleFormReturnButton">
<FormattedMessage
id="xpack.security.management.editRole.returnToRoleListButtonLabel"
defaultMessage="Return to role list"
/>
</EuiButton>
);
return this.getReturnToRoleListButton();
}

return (
<EuiFlexGroup responsive={false}>
<EuiFlexItem grow={false}>{this.getSaveButton()}</EuiFlexItem>
<EuiFlexItem grow={false}>{this.getCancelButton()}</EuiFlexItem>
<EuiFlexItem grow={true} />
{this.getActionButton()}
</EuiFlexGroup>
);
};

private getReturnToRoleListButton = () => {
return (
<EuiButton onClick={this.backToRoleList} data-test-subj="roleFormReturnButton">
<FormattedMessage
id="xpack.security.management.editRole.returnToRoleListButtonLabel"
defaultMessage="Return to role list"
/>
</EuiButton>
);
};

private getSaveButton = () => {
const saveText = this.editingExistingRole() ? (
<FormattedMessage
id="xpack.security.management.editRole.updateRoleText"
Expand All @@ -284,36 +299,33 @@ class EditRolePageUI extends Component<Props, State> {
);

return (
<EuiFlexGroup responsive={false}>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj={`roleFormSaveButton`}
fill
onClick={this.saveRole}
disabled={isReservedRole(this.props.role)}
>
{saveText}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty data-test-subj={`roleFormCancelButton`} onClick={this.backToRoleList}>
<FormattedMessage
id="xpack.security.management.editRole.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={true} />
{this.getActionButton()}
</EuiFlexGroup>
<EuiButton
data-test-subj={`roleFormSaveButton`}
fill
onClick={this.saveRole}
disabled={isReservedRole(this.props.role)}
>
{saveText}
</EuiButton>
);
};

private getCancelButton = () => {
return (
<EuiButtonEmpty data-test-subj={`roleFormCancelButton`} onClick={this.backToRoleList}>
<FormattedMessage
id="xpack.security.management.editRole.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
);
};

public editingExistingRole = () => {
private editingExistingRole = () => {
return !!this.props.role.name;
};

public saveRole = () => {
private saveRole = () => {
this.validator.enableValidation();

const result = this.validator.validateForSave(this.state.role);
Expand Down Expand Up @@ -344,7 +356,7 @@ class EditRolePageUI extends Component<Props, State> {
}
};

public handleDeleteRole = () => {
private handleDeleteRole = () => {
const { httpClient, role, intl } = this.props;

deleteRole(httpClient, role.name)
Expand All @@ -362,7 +374,7 @@ class EditRolePageUI extends Component<Props, State> {
});
};

public backToRoleList = () => {
private backToRoleList = () => {
window.location.hash = ROLES_PATH;
};
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class ElasticsearchPrivileges extends Component<Props, {}> {
httpClient,
validator,
onChange,
editable,
indexPatterns,
allowDocumentLevelSecurity,
allowFieldLevelSecurity,
Expand Down Expand Up @@ -135,7 +136,7 @@ export class ElasticsearchPrivileges extends Component<Props, {}> {
selectedOptions={this.props.role.elasticsearch.run_as.map(u => ({ label: u }))}
onCreateOption={this.onCreateRunAsOption}
onChange={this.onRunAsUserChange}
isDisabled={!this.props.editable}
isDisabled={!editable}
/>
</EuiFormRow>
</EuiDescribedFormGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ test('it renders without crashing', () => {
indexPatterns: [],
availableFields: [],
isReadOnlyRole: false,
allowDelete: true,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
Expand All @@ -50,7 +49,6 @@ describe('delete button', () => {
indexPatterns: [],
availableFields: [],
isReadOnlyRole: false,
allowDelete: true,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
Expand All @@ -59,19 +57,19 @@ describe('delete button', () => {
intl: {} as any,
};

test('it is hidden when allowDelete is false', () => {
test('it is hidden when isReadOnlyRole is true', () => {
const testProps = {
...props,
allowDelete: false,
isReadOnlyRole: true,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
expect(wrapper.find(EuiButtonIcon)).toHaveLength(0);
});

test('it is shown when allowDelete is true', () => {
test('it is shown when isReadOnlyRole is false', () => {
const testProps = {
...props,
allowDelete: true,
isReadOnlyRole: false,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
expect(wrapper.find(EuiButtonIcon)).toHaveLength(1);
Expand All @@ -80,7 +78,7 @@ describe('delete button', () => {
test('it invokes onDelete when clicked', () => {
const testProps = {
...props,
allowDelete: true,
isReadOnlyRole: false,
};
const wrapper = mountWithIntl(<IndexPrivilegeForm {...testProps} />);
wrapper.find(EuiButtonIcon).simulate('click');
Expand All @@ -102,7 +100,6 @@ describe(`document level security`, () => {
indexPatterns: [],
availableFields: [],
isReadOnlyRole: false,
allowDelete: true,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
Expand Down Expand Up @@ -161,7 +158,6 @@ describe('field level security', () => {
indexPatterns: [],
availableFields: [],
isReadOnlyRole: false,
allowDelete: true,
allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true,
validator: new RoleValidator(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ interface Props {
onChange: (indexPrivilege: RoleIndexPrivilege) => void;
onDelete: () => void;
isReadOnlyRole: boolean;
allowDelete: boolean;
allowDocumentLevelSecurity: boolean;
allowFieldLevelSecurity: boolean;
validator: RoleValidator;
Expand Down Expand Up @@ -70,7 +69,7 @@ export class IndexPrivilegeForm extends Component<Props, State> {
<EuiHorizontalRule />
<EuiFlexGroup className="index-privilege-form">
<EuiFlexItem>{this.getPrivilegeForm()}</EuiFlexItem>
{this.props.allowDelete && (
{!this.props.isReadOnlyRole && (
<EuiFlexItem grow={false}>
<EuiFormRow hasEmptyLabelSpace>
<EuiButtonIcon
Expand Down Expand Up @@ -251,7 +250,7 @@ export class IndexPrivilegeForm extends Component<Props, State> {
};

private getGrantedDocumentsControl = () => {
const { allowDocumentLevelSecurity, indexPrivilege } = this.props;
const { allowDocumentLevelSecurity, indexPrivilege, isReadOnlyRole } = this.props;

if (!allowDocumentLevelSecurity) {
return null;
Expand All @@ -275,6 +274,7 @@ export class IndexPrivilegeForm extends Component<Props, State> {
compressed={true}
checked={this.state.queryExpanded}
onChange={this.toggleDocumentQuery}
disabled={isReadOnlyRole}
/>
}
</EuiFlexItem>
Expand Down
Loading

0 comments on commit 614ff20

Please sign in to comment.