[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(); 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); await setup(false);
expect(wrapper.find('[data-test-subj="alertSidebarEditAction"]').exists()).toBeFalsy(); 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 () => { it('renders table of alerts with delete button disabled', async () => {
await setup(); await setup();
expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiBasicTable')).toHaveLength(1);
expect(wrapper.find('EuiTableRow')).toHaveLength(2); expect(wrapper.find('EuiTableRow')).toHaveLength(2);
// TODO: check delete button expect(wrapper.find('[data-test-subj="deleteActionHoverButton"]')).toHaveLength(0);
}); });
}); });

View file

@ -464,11 +464,10 @@ export const AlertsList: React.FunctionComponent = () => {
name: '', name: '',
width: '10%', width: '10%',
render(item: AlertTableItem) { render(item: AlertTableItem) {
return ( return item.isEditable && isRuleTypeEditableInContext(item.alertTypeId) ? (
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="s"> <EuiFlexGroup justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false} className="alertSidebarItem"> <EuiFlexItem grow={false} className="alertSidebarItem">
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s"> <EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
{item.isEditable && isRuleTypeEditableInContext(item.alertTypeId) && (
<EuiFlexItem grow={false} data-test-subj="alertSidebarEditAction"> <EuiFlexItem grow={false} data-test-subj="alertSidebarEditAction">
<EuiButtonIcon <EuiButtonIcon
color={'primary'} color={'primary'}
@ -477,6 +476,7 @@ export const AlertsList: React.FunctionComponent = () => {
{ defaultMessage: 'Edit' } { defaultMessage: 'Edit' }
)} )}
className="alertSidebarItem__action" className="alertSidebarItem__action"
data-test-subj="editActionHoverButton"
onClick={() => onRuleEdit(item)} onClick={() => onRuleEdit(item)}
iconType={'pencil'} iconType={'pencil'}
aria-label={i18n.translate( aria-label={i18n.translate(
@ -485,7 +485,6 @@ export const AlertsList: React.FunctionComponent = () => {
)} )}
/> />
</EuiFlexItem> </EuiFlexItem>
)}
<EuiFlexItem grow={false} data-test-subj="alertSidebarDeleteAction"> <EuiFlexItem grow={false} data-test-subj="alertSidebarDeleteAction">
<EuiButtonIcon <EuiButtonIcon
color={'danger'} color={'danger'}
@ -494,6 +493,7 @@ export const AlertsList: React.FunctionComponent = () => {
{ defaultMessage: 'Delete' } { defaultMessage: 'Delete' }
)} )}
className="alertSidebarItem__action" className="alertSidebarItem__action"
data-test-subj="deleteActionHoverButton"
onClick={() => setAlertsToDelete([item.id])} onClick={() => setAlertsToDelete([item.id])}
iconType={'trash'} iconType={'trash'}
aria-label={i18n.translate( aria-label={i18n.translate(
@ -504,6 +504,7 @@ export const AlertsList: React.FunctionComponent = () => {
</EuiFlexItem> </EuiFlexItem>
</EuiFlexGroup> </EuiFlexGroup>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<CollapsedItemActions <CollapsedItemActions
key={item.id} key={item.id}
@ -514,7 +515,7 @@ export const AlertsList: React.FunctionComponent = () => {
/> />
</EuiFlexItem> </EuiFlexItem>
</EuiFlexGroup> </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; you may not use this file except in compliance with the Elastic License
* 2.0. * 2.0.
*/ */
import * as React from 'react'; import * as React from 'react';
import { mountWithIntl, nextTick } from '@kbn/test/jest'; 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 () => { test('renders closed popover initially and opens on click with all actions enabled', async () => {
await setup(); await setup();
const wrapper = mountWithIntl(<CollapsedItemActions {...getPropsWithRule()} />); 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="editAlert"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="deleteAlert"]').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`).prop('disabled')).toBeFalsy();
expect(wrapper.find(`[data-test-subj="muteButton"] button`).text()).toEqual('Mute'); expect(wrapper.find(`[data-test-subj="muteButton"] button`).text()).toEqual('Mute');
expect(wrapper.find(`[data-test-subj="disableButton"] button`).prop('disabled')).toBeFalsy(); 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'; import { Alert, AlertTableItem } from '../../../../types';
interface ComponentOpts { export interface ComponentOpts {
item: AlertTableItem; item: AlertTableItem;
onAlertChanged: () => void; onAlertChanged: () => void;
enableAlert: (alert: Alert) => Promise<void>; enableAlert: (alert: Alert) => Promise<void>;