mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[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:
parent
d08b49f313
commit
331a27c6f5
5 changed files with 145 additions and 25 deletions
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
|
@ -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>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue