mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Endpoint] Assign and remove Event Filters by policy based on user license (#122434)
* use licence info to show assign to policy button fixes elastic/security-team/issues/2032 * use license info to show remove event filter from policy button fixes elastic/security-team/issues/2032 * use license info to show assign event filter button on empty state fixes elastic/security-team/issues/2032 * Use license info to show the assign event filter to policy flyout fixes elastic/security-team/issues/2032 * minor typo Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f9c6259b47
commit
33af3fca56
5 changed files with 113 additions and 44 deletions
|
@ -5,11 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { EuiEmptyPrompt, EuiPageTemplate, EuiLink } from '@elastic/eui';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { EuiButton, EuiEmptyPrompt, EuiPageTemplate, EuiLink } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
// TODO: Uncomment this when assign functionality through the flyout is done
|
||||
// import { usePolicyDetailsNavigateCallback } from '../../policy_hooks';
|
||||
import { usePolicyDetailsNavigateCallback } from '../../policy_hooks';
|
||||
import { useGetLinkTo } from './use_policy_event_filters_empty_hooks';
|
||||
import { useUserPrivileges } from '../../../../../../common/components/user_privileges';
|
||||
|
||||
|
@ -22,15 +21,14 @@ export const PolicyEventFiltersEmptyUnassigned = memo<CommonProps>(({ policyId,
|
|||
const { canCreateArtifactsByPolicy } = useUserPrivileges().endpointPrivileges;
|
||||
const { onClickHandler, toRouteUrl } = useGetLinkTo(policyId, policyName);
|
||||
|
||||
// TODO: Uncomment this when assign functionality through the flyout is done
|
||||
// const navigateCallback = usePolicyDetailsNavigateCallback();
|
||||
// const onClickPrimaryButtonHandler = useCallback(
|
||||
// () =>
|
||||
// navigateCallback({
|
||||
// show: 'list',
|
||||
// }),
|
||||
// [navigateCallback]
|
||||
// );
|
||||
const navigateCallback = usePolicyDetailsNavigateCallback();
|
||||
const onClickPrimaryButtonHandler = useCallback(
|
||||
() =>
|
||||
navigateCallback({
|
||||
show: 'list',
|
||||
}),
|
||||
[navigateCallback]
|
||||
);
|
||||
return (
|
||||
<EuiPageTemplate template="centeredContent">
|
||||
<EuiEmptyPrompt
|
||||
|
@ -54,18 +52,17 @@ export const PolicyEventFiltersEmptyUnassigned = memo<CommonProps>(({ policyId,
|
|||
actions={[
|
||||
...(canCreateArtifactsByPolicy
|
||||
? [
|
||||
// TODO: Uncomment this when assign functionality through the flyout is done
|
||||
// <EuiButton
|
||||
// color="primary"
|
||||
// fill
|
||||
// onClick={onClickPrimaryButtonHandler}
|
||||
// data-test-subj="assign-ta-button"
|
||||
// >
|
||||
// <FormattedMessage
|
||||
// id="xpack.securitySolution.endpoint.policy.eventFilters.empty.unassigned.primaryAction"
|
||||
// defaultMessage="Assign event filters"
|
||||
// />
|
||||
// </EuiButton>,
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill
|
||||
onClick={onClickPrimaryButtonHandler}
|
||||
data-test-subj="assign-event-filter-button"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.endpoint.policy.eventFilters.empty.unassigned.primaryAction"
|
||||
defaultMessage="Assign event filters"
|
||||
/>
|
||||
</EuiButton>,
|
||||
]
|
||||
: []),
|
||||
// eslint-disable-next-line @elastic/eui/href-or-on-click
|
||||
|
|
|
@ -11,12 +11,14 @@ import {
|
|||
AppContextTestRender,
|
||||
createAppRootMockRenderer,
|
||||
} from '../../../../../../common/mock/endpoint';
|
||||
import { getPolicyDetailsArtifactsListPath } from '../../../../../common/routing';
|
||||
import { EndpointDocGenerator } from '../../../../../../../common/endpoint/generate_data';
|
||||
|
||||
import { ImmutableObject, PolicyData } from '../../../../../../../common/endpoint/types';
|
||||
import { parsePoliciesAndFilterToKql } from '../../../../../common/utils';
|
||||
import { eventFiltersListQueryHttpMock } from '../../../../event_filters/test_utils';
|
||||
import { getFoundExceptionListItemSchemaMock } from '../../../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock';
|
||||
import { getEndpointPrivilegesInitialStateMock } from '../../../../../../common/components/user_privileges/endpoint/mocks';
|
||||
|
||||
let render: () => ReturnType<AppContextTestRender['render']>;
|
||||
let mockedContext: AppContextTestRender;
|
||||
|
@ -34,12 +36,12 @@ describe('Policy event filters layout', () => {
|
|||
|
||||
afterEach(() => reactTestingLibrary.cleanup());
|
||||
|
||||
it('should renders layout with a loader', async () => {
|
||||
it('should render layout with a loader', async () => {
|
||||
const component = render();
|
||||
expect(component.getByTestId('policy-event-filters-loading-spinner')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should renders layout with no assigned event filters data when there are not event filters', async () => {
|
||||
it('should render layout with no assigned event filters data when there are not event filters', async () => {
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock(0)
|
||||
);
|
||||
|
@ -48,7 +50,7 @@ describe('Policy event filters layout', () => {
|
|||
expect(await component.findByTestId('policy-event-filters-empty-unexisting')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should renders layout with no assigned event filters data when there are event filters', async () => {
|
||||
it('should render layout with no assigned event filters data when there are event filters', async () => {
|
||||
mockedApi.responseProvider.eventFiltersList.mockImplementation(
|
||||
// @ts-expect-error
|
||||
(args) => {
|
||||
|
@ -69,7 +71,7 @@ describe('Policy event filters layout', () => {
|
|||
expect(await component.findByTestId('policy-event-filters-empty-unassigned')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should renders layout with data', async () => {
|
||||
it('should render layout with data', async () => {
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock(3)
|
||||
);
|
||||
|
@ -80,4 +82,47 @@ describe('Policy event filters layout', () => {
|
|||
'3 event filters'
|
||||
);
|
||||
});
|
||||
|
||||
it('should hide `Assign event filters to policy` on empty state with unassigned policies when downgraded to a gold or below license', () => {
|
||||
getEndpointPrivilegesInitialStateMock({
|
||||
canCreateArtifactsByPolicy: false,
|
||||
});
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock(0)
|
||||
);
|
||||
|
||||
const component = render();
|
||||
mockedContext.history.push(getPolicyDetailsArtifactsListPath(policyItem.id));
|
||||
expect(component.queryByTestId('assign-event-filter-button')).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the `Assign event filters to policy` button license is downgraded to gold or below', () => {
|
||||
getEndpointPrivilegesInitialStateMock({
|
||||
canCreateArtifactsByPolicy: false,
|
||||
});
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock(5)
|
||||
);
|
||||
|
||||
const component = render();
|
||||
mockedContext.history.push(getPolicyDetailsArtifactsListPath(policyItem.id));
|
||||
|
||||
expect(component.queryByTestId('eventFilters-assign-button')).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the `Assign event filters` flyout when license is downgraded to gold or below', () => {
|
||||
getEndpointPrivilegesInitialStateMock({
|
||||
canCreateArtifactsByPolicy: false,
|
||||
});
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock(2)
|
||||
);
|
||||
|
||||
const component = render();
|
||||
mockedContext.history.push(
|
||||
`${getPolicyDetailsArtifactsListPath(policyItem.id)}/eventFilters?show=list`
|
||||
);
|
||||
|
||||
expect(component.queryByTestId('eventFilters-assign-flyout')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,6 +24,7 @@ import { ImmutableObject, PolicyData } from '../../../../../../../common/endpoin
|
|||
import { getEventFiltersListPath } from '../../../../../common/routing';
|
||||
import { useGetAllAssignedEventFilters, useGetAllEventFilters } from '../hooks';
|
||||
import { ManagementPageLoader } from '../../../../../components/management_page_loader';
|
||||
import { useUserPrivileges } from '../../../../../../common/components/user_privileges';
|
||||
import { PolicyEventFiltersEmptyUnassigned, PolicyEventFiltersEmptyUnexisting } from '../empty';
|
||||
import {
|
||||
usePolicyDetailsSelector,
|
||||
|
@ -40,6 +41,7 @@ export const PolicyEventFiltersLayout = React.memo<PolicyEventFiltersLayoutProps
|
|||
({ policyItem }) => {
|
||||
const { getAppUrl } = useAppUrl();
|
||||
const navigateCallback = usePolicyDetailsEventFiltersNavigateCallback();
|
||||
const { canCreateArtifactsByPolicy } = useUserPrivileges().endpointPrivileges;
|
||||
const urlParams = usePolicyDetailsSelector(getCurrentArtifactsLocation);
|
||||
|
||||
const { data: allAssigned, isLoading: isLoadingAllAssigned } = useGetAllAssignedEventFilters(
|
||||
|
@ -56,6 +58,25 @@ export const PolicyEventFiltersLayout = React.memo<PolicyEventFiltersLayoutProps
|
|||
navigateCallback({ show: undefined });
|
||||
}, [navigateCallback]);
|
||||
|
||||
const assignToPolicyButton = useMemo(
|
||||
() => (
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="plusInCircle"
|
||||
data-test-subj="eventFilters-assign-button"
|
||||
onClick={handleOnClickAssignButton}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.securitySolution.endpoint.policy.eventFilters.layout.assignToPolicy',
|
||||
{
|
||||
defaultMessage: 'Assign event filters to policy',
|
||||
}
|
||||
)}
|
||||
</EuiButton>
|
||||
),
|
||||
[handleOnClickAssignButton]
|
||||
);
|
||||
|
||||
const aboutInfo = useMemo(() => {
|
||||
const link = (
|
||||
<EuiLink
|
||||
|
@ -122,22 +143,10 @@ export const PolicyEventFiltersLayout = React.memo<PolicyEventFiltersLayoutProps
|
|||
</EuiText>
|
||||
</EuiPageHeaderSection>
|
||||
<EuiPageHeaderSection>
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="plusInCircle"
|
||||
data-test-subj="eventFilters-assign-button"
|
||||
onClick={handleOnClickAssignButton}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.securitySolution.endpoint.policy.eventFilters.layout.assignToPolicy',
|
||||
{
|
||||
defaultMessage: 'Assign event filters to policy',
|
||||
}
|
||||
)}
|
||||
</EuiButton>
|
||||
{canCreateArtifactsByPolicy && assignToPolicyButton}
|
||||
</EuiPageHeaderSection>
|
||||
</EuiPageHeader>
|
||||
{urlParams.show === 'list' && (
|
||||
{canCreateArtifactsByPolicy && urlParams.show === 'list' && (
|
||||
<PolicyEventFiltersFlyout policyItem={policyItem} onClose={handleOnCloseFlyout} />
|
||||
)}
|
||||
<EuiSpacer size="l" />
|
||||
|
|
|
@ -20,6 +20,7 @@ import { eventFiltersListQueryHttpMock } from '../../../../event_filters/test_ut
|
|||
import { PolicyEventFiltersList } from './policy_event_filters_list';
|
||||
import { parseQueryFilterToKQL, parsePoliciesAndFilterToKql } from '../../../../../common/utils';
|
||||
import { SEARCHABLE_FIELDS } from '../../../../event_filters/constants';
|
||||
import { getEndpointPrivilegesInitialStateMock } from '../../../../../../common/components/user_privileges/endpoint/mocks';
|
||||
|
||||
const endpointGenerator = new EndpointDocGenerator('seed');
|
||||
const getDefaultQueryParameters = (customFilter: string | undefined = '') => ({
|
||||
|
@ -133,4 +134,19 @@ describe('Policy details event filters list', () => {
|
|||
);
|
||||
expect(renderResult.queryByTestId('view-full-details-action')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not show remove option in actions menu if license is downgraded to gold or below', async () => {
|
||||
getEndpointPrivilegesInitialStateMock({
|
||||
canCreateArtifactsByPolicy: false,
|
||||
});
|
||||
mockedApi.responseProvider.eventFiltersList.mockReturnValue(
|
||||
getFoundExceptionListItemSchemaMock()
|
||||
);
|
||||
await render();
|
||||
userEvent.click(
|
||||
renderResult.getByTestId('eventFilters-collapsed-list-card-header-actions-button')
|
||||
);
|
||||
|
||||
expect(renderResult.queryByTestId('remove-from-policy-action')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,12 +32,14 @@ import { ImmutableObject, PolicyData } from '../../../../../../../common/endpoin
|
|||
import { PolicyEventFiltersDeleteModal } from '../delete_modal';
|
||||
import { isGlobalPolicyEffected } from '../../../../../components/effected_policy_select/utils';
|
||||
import { getEventFiltersListPath } from '../../../../../common/routing';
|
||||
import { useUserPrivileges } from '../../../../../../common/components/user_privileges';
|
||||
|
||||
interface PolicyEventFiltersListProps {
|
||||
policy: ImmutableObject<PolicyData>;
|
||||
}
|
||||
export const PolicyEventFiltersList = React.memo<PolicyEventFiltersListProps>(({ policy }) => {
|
||||
const { getAppUrl } = useAppUrl();
|
||||
const { canCreateArtifactsByPolicy } = useUserPrivileges().endpointPrivileges;
|
||||
const policiesRequest = useGetEndpointSpecificPolicies();
|
||||
const navigateCallback = usePolicyDetailsEventFiltersNavigateCallback();
|
||||
const urlParams = usePolicyDetailsSelector(getCurrentArtifactsLocation);
|
||||
|
@ -142,7 +144,7 @@ export const PolicyEventFiltersList = React.memo<PolicyEventFiltersListProps>(({
|
|||
};
|
||||
return {
|
||||
expanded: expandedItemsMap.get(item.id) || false,
|
||||
actions: [fullDetailsAction, deleteAction],
|
||||
actions: canCreateArtifactsByPolicy ? [fullDetailsAction, deleteAction] : [fullDetailsAction],
|
||||
policies: artifactCardPolicies,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue