[Alerting UI] Fixed display permissions for edit/delete buttons when user has read only access. (#107996) (#108130)

* [Alerting UI] Fixed display permissions for Edit/delete buttons when user has read only access

* fixed due to comments
This commit is contained in:
Yuliia Naumenko 2021-08-10 19:37:15 -07:00 committed by GitHub
parent d08b49f313
commit 331a27c6f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 25 deletions

View file

@ -434,10 +434,10 @@ describe('alerts_list component with items', () => {
expect(wrapper.find('[data-test-subj="alertSidebarDeleteAction"]').exists()).toBeTruthy();
});
it('does not render edit button when rule type does not allow editing in rules management', async () => {
it('does not render edit and delete button when rule type does not allow editing in rules management', async () => {
await setup(false);
expect(wrapper.find('[data-test-subj="alertSidebarEditAction"]').exists()).toBeFalsy();
expect(wrapper.find('[data-test-subj="alertSidebarDeleteAction"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="alertSidebarDeleteAction"]').exists()).toBeFalsy();
});
});
@ -567,11 +567,18 @@ describe('alerts_list with show only capability', () => {
});
}
it('renders table of alerts with edit button disabled', async () => {
await setup();
expect(wrapper.find('EuiBasicTable')).toHaveLength(1);
expect(wrapper.find('EuiTableRow')).toHaveLength(2);
expect(wrapper.find('[data-test-subj="editActionHoverButton"]')).toHaveLength(0);
});
it('renders table of alerts with delete button disabled', async () => {
await setup();
expect(wrapper.find('EuiBasicTable')).toHaveLength(1);
expect(wrapper.find('EuiTableRow')).toHaveLength(2);
// TODO: check delete button
expect(wrapper.find('[data-test-subj="deleteActionHoverButton"]')).toHaveLength(0);
});
});

View file

@ -464,28 +464,27 @@ export const AlertsList: React.FunctionComponent = () => {
name: '',
width: '10%',
render(item: AlertTableItem) {
return (
return item.isEditable && isRuleTypeEditableInContext(item.alertTypeId) ? (
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false} className="alertSidebarItem">
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
{item.isEditable && isRuleTypeEditableInContext(item.alertTypeId) && (
<EuiFlexItem grow={false} data-test-subj="alertSidebarEditAction">
<EuiButtonIcon
color={'primary'}
title={i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.editButtonTooltip',
{ defaultMessage: 'Edit' }
)}
className="alertSidebarItem__action"
onClick={() => onRuleEdit(item)}
iconType={'pencil'}
aria-label={i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.editAriaLabel',
{ defaultMessage: 'Edit' }
)}
/>
</EuiFlexItem>
)}
<EuiFlexItem grow={false} data-test-subj="alertSidebarEditAction">
<EuiButtonIcon
color={'primary'}
title={i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.editButtonTooltip',
{ defaultMessage: 'Edit' }
)}
className="alertSidebarItem__action"
data-test-subj="editActionHoverButton"
onClick={() => onRuleEdit(item)}
iconType={'pencil'}
aria-label={i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.editAriaLabel',
{ defaultMessage: 'Edit' }
)}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} data-test-subj="alertSidebarDeleteAction">
<EuiButtonIcon
color={'danger'}
@ -494,6 +493,7 @@ export const AlertsList: React.FunctionComponent = () => {
{ defaultMessage: 'Delete' }
)}
className="alertSidebarItem__action"
data-test-subj="deleteActionHoverButton"
onClick={() => setAlertsToDelete([item.id])}
iconType={'trash'}
aria-label={i18n.translate(
@ -504,6 +504,7 @@ export const AlertsList: React.FunctionComponent = () => {
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<CollapsedItemActions
key={item.id}
@ -514,7 +515,7 @@ export const AlertsList: React.FunctionComponent = () => {
/>
</EuiFlexItem>
</EuiFlexGroup>
);
) : null;
},
},
];

View file

@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as React from 'react';
import { mountWithIntl, nextTick } from '@kbn/test/jest';
@ -95,6 +94,20 @@ describe('CollapsedItemActions', () => {
};
};
test('renders panel items as disabled', async () => {
await setup();
const wrapper = mountWithIntl(
<CollapsedItemActions {...getPropsWithRule({ isEditable: false })} />
);
await act(async () => {
await nextTick();
wrapper.update();
});
expect(
wrapper.find('[data-test-subj="selectActionButton"]').first().props().disabled
).toBeTruthy();
});
test('renders closed popover initially and opens on click with all actions enabled', async () => {
await setup();
const wrapper = mountWithIntl(<CollapsedItemActions {...getPropsWithRule()} />);
@ -118,6 +131,10 @@ describe('CollapsedItemActions', () => {
expect(wrapper.find('[data-test-subj="editAlert"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="deleteAlert"]').exists()).toBeTruthy();
expect(
wrapper.find('[data-test-subj="selectActionButton"]').first().props().disabled
).toBeFalsy();
expect(wrapper.find(`[data-test-subj="muteButton"] button`).prop('disabled')).toBeFalsy();
expect(wrapper.find(`[data-test-subj="muteButton"] button`).text()).toEqual('Mute');
expect(wrapper.find(`[data-test-subj="disableButton"] button`).prop('disabled')).toBeFalsy();

View file

@ -0,0 +1,95 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { mountWithIntl } from '@kbn/test/jest';
import { RuleEnabledSwitch, ComponentOpts } from './rule_enabled_switch';
describe('RuleEnabledSwitch', () => {
const enableAlert = jest.fn();
const props: ComponentOpts = {
disableAlert: jest.fn(),
enableAlert,
item: {
id: '1',
name: 'test alert',
tags: ['tag1'],
enabled: true,
alertTypeId: 'test_alert_type',
schedule: { interval: '5d' },
actions: [],
params: { name: 'test alert type name' },
createdBy: null,
updatedBy: null,
apiKeyOwner: null,
throttle: '1m',
muteAll: false,
mutedInstanceIds: [],
executionStatus: {
status: 'active',
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
},
consumer: 'test',
actionsCount: 0,
alertType: 'test_alert_type',
createdAt: new Date('2020-08-20T19:23:38Z'),
enabledInLicense: true,
isEditable: false,
notifyWhen: null,
tagsText: 'test',
updatedAt: new Date('2020-08-20T19:23:38Z'),
},
onAlertChanged: jest.fn(),
};
beforeEach(() => jest.resetAllMocks());
test('renders switch control as disabled when rule is not editable', () => {
const wrapper = mountWithIntl(<RuleEnabledSwitch {...props} />);
expect(wrapper.find('[data-test-subj="enableSwitch"]').first().props().disabled).toBeTruthy();
});
test('renders switch control', () => {
const wrapper = mountWithIntl(
<RuleEnabledSwitch
{...{
...props,
item: {
id: '1',
name: 'test alert',
tags: ['tag1'],
enabled: false,
alertTypeId: 'test_alert_type',
schedule: { interval: '5d' },
actions: [],
params: { name: 'test alert type name' },
createdBy: null,
updatedBy: null,
apiKeyOwner: null,
throttle: '1m',
muteAll: false,
mutedInstanceIds: [],
executionStatus: {
status: 'active',
lastExecutionDate: new Date('2020-08-20T19:23:38Z'),
},
consumer: 'test',
actionsCount: 0,
alertType: 'test_alert_type',
createdAt: new Date('2020-08-20T19:23:38Z'),
enabledInLicense: true,
isEditable: true,
notifyWhen: null,
tagsText: 'test',
updatedAt: new Date('2020-08-20T19:23:38Z'),
},
}}
/>
);
expect(wrapper.find('[data-test-subj="enableSwitch"]').first().props().checked).toBeFalsy();
});
});

View file

@ -10,7 +10,7 @@ import { EuiSwitch, EuiLoadingSpinner } from '@elastic/eui';
import { Alert, AlertTableItem } from '../../../../types';
interface ComponentOpts {
export interface ComponentOpts {
item: AlertTableItem;
onAlertChanged: () => void;
enableAlert: (alert: Alert) => Promise<void>;