Skip to content

Commit

Permalink
Add artifact event filters card to policy edit view on endpoint integ…
Browse files Browse the repository at this point in the history
  • Loading branch information
ashokaditya committed Dec 22, 2021
1 parent 38d25e6 commit 505ac94
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { I18nProvider } from '@kbn/i18n-react';
import { FleetEventFiltersCard } from './fleet_event_filters_card';
import { FleetEventFiltersCardWrapper } from './fleet_event_filters_card_wrapper';
import * as reactTestingLibrary from '@testing-library/react';
import { EventFiltersHttpService } from '../../../../../event_filters/service';
import { useToasts } from '../../../../../../../common/lib/kibana';
Expand Down Expand Up @@ -67,7 +67,9 @@ describe('Fleet event filters card', () => {
</I18nProvider>
);
// @ts-expect-error TS2739
const component = reactTestingLibrary.render(<FleetEventFiltersCard />, { wrapper: Wrapper });
const component = reactTestingLibrary.render(<FleetEventFiltersCardWrapper />, {
wrapper: Wrapper,
});
try {
// @ts-expect-error TS2769
await reactTestingLibrary.act(() => promise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,36 @@
*/

import React, { memo, useMemo, useState, useEffect, useRef } from 'react';
import { EuiPanel, EuiText } from '@elastic/eui';
import { EuiPanel, EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
PackageCustomExtensionComponentProps,
pagePathGetters,
} from '../../../../../../../../../fleet/public';
import { getEventFiltersListPath } from '../../../../../../common/routing';
import {
GetExceptionSummaryResponse,
ListPageRouteState,
} from '../../../../../../../../common/endpoint/types';
import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../../../fleet/common';
import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types';
import { useKibana, useToasts } from '../../../../../../../common/lib/kibana';
import { useAppUrl } from '../../../../../../../common/lib/kibana/hooks';
import { LinkWithIcon } from './link_with_icon';
import { ExceptionItemsSummary } from './exception_items_summary';
import { EventFiltersHttpService } from '../../../../../event_filters/service';
import { StyledEuiFlexGridGroup, StyledEuiFlexGridItem } from './styled_components';
import {
StyledEuiFlexGridGroup,
StyledEuiFlexGridItem,
StyledEuiFlexItem,
} from './styled_components';

export const FleetEventFiltersCard = memo<PackageCustomExtensionComponentProps>(({ pkgkey }) => {
const { getAppUrl } = useAppUrl();
export const FleetEventFiltersCard = memo<{
customLink: React.ReactNode;
cardSize?: 'm' | 'l';
}>(({ customLink, cardSize = 'l' }) => {
const {
services: { http },
} = useKibana();
const toasts = useToasts();
const [stats, setStats] = useState<GetExceptionSummaryResponse | undefined>();
const eventFiltersListUrlPath = getEventFiltersListPath();
const eventFiltersApi = useMemo(() => new EventFiltersHttpService(http), [http]);
const eventFiltersService = useMemo(() => new EventFiltersHttpService(http), [http]);
const isMounted = useRef<boolean>();

useEffect(() => {
isMounted.current = true;
const fetchStats = async () => {
try {
const summary = await eventFiltersApi.getSummary();
const summary = await eventFiltersService.getSummary();
if (isMounted.current) {
setStats(summary);
}
Expand All @@ -63,64 +57,57 @@ export const FleetEventFiltersCard = memo<PackageCustomExtensionComponentProps>(
return () => {
isMounted.current = false;
};
}, [eventFiltersApi, toasts]);
}, [eventFiltersService, toasts]);

const eventFiltersRouteState = useMemo<ListPageRouteState>(() => {
const fleetPackageCustomUrlPath = `#${
pagePathGetters.integration_details_custom({ pkgkey })[1]
}`;
return {
backButtonLabel: i18n.translate(
'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel',
{ defaultMessage: 'Back to Endpoint Integration' }
),
onBackButtonNavigateTo: [
INTEGRATIONS_PLUGIN_ID,
{
path: fleetPackageCustomUrlPath,
},
],
backButtonUrl: getAppUrl({
appId: INTEGRATIONS_PLUGIN_ID,
path: fleetPackageCustomUrlPath,
}),
};
}, [getAppUrl, pkgkey]);
const getTitle = () => (
<FormattedMessage
id="xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersLabel"
defaultMessage="Event filters"
/>
);

return (
<EuiPanel hasShadow={false} paddingSize="l" hasBorder data-test-subj="fleedEventFiltersCard">
const cardGrid = useMemo(() => {
if (cardSize === 'm') {
return (
<EuiFlexGroup
alignItems="baseline"
justifyContent="flexStart"
gutterSize="s"
direction="row"
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiText>
<h5>{getTitle()}</h5>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ExceptionItemsSummary stats={stats} isSmall={true} />
</EuiFlexItem>
<StyledEuiFlexItem grow={1}>{customLink}</StyledEuiFlexItem>
</EuiFlexGroup>
);
}
return (
<StyledEuiFlexGridGroup alignItems="baseline" justifyContent="center">
<StyledEuiFlexGridItem gridarea="title" alignitems="flex-start">
<EuiText>
<h4>
<FormattedMessage
id="xpack.securitySolution.endpoint.fleetCustomExtension.eventFiltersLabel"
defaultMessage="Event filters"
/>
</h4>
<h4>{getTitle()}</h4>
</EuiText>
</StyledEuiFlexGridItem>
<StyledEuiFlexGridItem gridarea="summary">
<ExceptionItemsSummary stats={stats} />
<StyledEuiFlexGridItem gridarea="summary" alignitems={'center'}>
<ExceptionItemsSummary stats={stats} isSmall={false} />
</StyledEuiFlexGridItem>
<StyledEuiFlexGridItem gridarea="link" alignitems="flex-end">
<>
<LinkWithIcon
href={getAppUrl({
path: eventFiltersListUrlPath,
})}
appPath={eventFiltersListUrlPath}
appState={eventFiltersRouteState}
data-test-subj="linkToEventFilters"
>
<FormattedMessage
id="xpack.securitySolution.endpoint.fleetCustomExtension.manageEventFiltersLinkLabel"
defaultMessage="Manage"
/>
</LinkWithIcon>
</>
{customLink}
</StyledEuiFlexGridItem>
</StyledEuiFlexGridGroup>
);
}, [cardSize, customLink, stats]);

return (
<EuiPanel hasShadow={false} paddingSize="l" hasBorder data-test-subj="fleetEventFiltersCard">
{cardGrid}
</EuiPanel>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
PackageCustomExtensionComponentProps,
pagePathGetters,
} from '../../../../../../../../../fleet/public';
import { getEventFiltersListPath } from '../../../../../../common/routing';
import { ListPageRouteState } from '../../../../../../../../common/endpoint/types';
import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../../../fleet/common';

import { useAppUrl } from '../../../../../../../common/lib/kibana/hooks';
import { LinkWithIcon } from './link_with_icon';

import { FleetEventFiltersCard } from './fleet_event_filters_card';

export const FleetEventFiltersCardWrapper = memo<PackageCustomExtensionComponentProps>(
({ pkgkey }) => {
const { getAppUrl } = useAppUrl();
const eventFiltersListUrlPath = getEventFiltersListPath();

const eventFiltersRouteState = useMemo<ListPageRouteState>(() => {
const fleetPackageCustomUrlPath = `#${
pagePathGetters.integration_details_custom({ pkgkey })[1]
}`;
return {
backButtonLabel: i18n.translate(
'xpack.securitySolution.endpoint.fleetCustomExtension.backButtonLabel',
{ defaultMessage: 'Back to Endpoint Integration' }
),
onBackButtonNavigateTo: [
INTEGRATIONS_PLUGIN_ID,
{
path: fleetPackageCustomUrlPath,
},
],
backButtonUrl: getAppUrl({
appId: INTEGRATIONS_PLUGIN_ID,
path: fleetPackageCustomUrlPath,
}),
};
}, [getAppUrl, pkgkey]);

const customLink = useMemo(
() => (
<LinkWithIcon
href={getAppUrl({
path: eventFiltersListUrlPath,
})}
appPath={eventFiltersListUrlPath}
appState={eventFiltersRouteState}
data-test-subj="linkToEventFilters"
>
<FormattedMessage
id="xpack.securitySolution.endpoint.fleetCustomExtension.manageEventFiltersLinkLabel"
defaultMessage="Manage"
/>
</LinkWithIcon>
),
[getAppUrl, eventFiltersListUrlPath, eventFiltersRouteState]
);

return <FleetEventFiltersCard customLink={customLink} />;
}
);

FleetEventFiltersCardWrapper.displayName = 'FleetEventFiltersCardWrapper';
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { EuiSpacer } from '@elastic/eui';
import React, { memo } from 'react';
import { PackageCustomExtensionComponentProps } from '../../../../../../../../fleet/public';
import { FleetEventFiltersCard } from './components/fleet_event_filters_card';
import { FleetEventFiltersCardWrapper } from './components/fleet_event_filters_card_wrapper';
import { FleetHostIsolationExceptionsCard } from './components/fleet_host_isolation_exceptions_card';
import { FleetTrustedAppsCardWrapper } from './components/fleet_trusted_apps_card_wrapper';

Expand All @@ -18,7 +18,7 @@ export const EndpointPackageCustomExtension = memo<PackageCustomExtensionCompone
<div data-test-subj="fleetEndpointPackageCustomContent">
<FleetTrustedAppsCardWrapper {...props} />
<EuiSpacer />
<FleetEventFiltersCard {...props} />
<FleetEventFiltersCardWrapper {...props} />
<EuiSpacer />
<FleetHostIsolationExceptionsCard {...props} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ import {
import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features';
import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../fleet/common';
import { useAppUrl } from '../../../../../common/lib/kibana/hooks';
import { PolicyDetailsRouteState } from '../../../../../../common/endpoint/types';
import { getPolicyDetailPath, getPolicyTrustedAppsPath } from '../../../../common/routing';
import {
PolicyDetailsRouteState,
ListPageRouteState,
} from '../../../../../../common/endpoint/types';
import {
getPolicyDetailPath,
getPolicyTrustedAppsPath,
getPolicyEventFiltersPath,
} from '../../../../common/routing';
import { PolicyDetailsForm } from '../policy_details_form';
import { AppAction } from '../../../../../common/store/actions';
import { usePolicyDetailsSelector } from '../policy_hooks';
Expand All @@ -29,6 +36,7 @@ import {
policyDetailsForUpdate,
} from '../../store/policy_details/selectors';
import { FleetTrustedAppsCard } from './endpoint_package_custom_extension/components/fleet_trusted_apps_card';
import { FleetEventFiltersCard } from './endpoint_package_custom_extension/components/fleet_event_filters_card';
import { LinkWithIcon } from './endpoint_package_custom_extension/components/link_with_icon';
import { FleetIntegrationHostIsolationExceptionsCard } from './endpoint_package_custom_extension/components/fleet_integration_host_isolation_exceptions_card';
/**
Expand Down Expand Up @@ -122,7 +130,7 @@ const WrappedPolicyDetailsForm = memo<{
return {
backLink: {
label: i18n.translate(
'xpack.securitySolution.endpoint.fleetCustomExtension.artifacts.backButtonLabel',
'xpack.securitySolution.endpoint.fleetCustomExtension.artifacts.trustedApps.backButtonLabel',
{
defaultMessage: `Back to Fleet integration policy`,
}
Expand Down Expand Up @@ -161,6 +169,49 @@ const WrappedPolicyDetailsForm = memo<{
[getAppUrl, policyTrustedAppsPath, policyTrustedAppRouteState]
);

const policyEventFiltersPath = useMemo(() => getPolicyEventFiltersPath(policyId), [policyId]);
const policyEventFiltersRouteState = useMemo<ListPageRouteState>(() => {
const fleetPackageIntegrationCustomUrlPath = `#${
pagePathGetters.integration_policy_edit({ packagePolicyId: policyId })[1]
}`;
return {
backButtonLabel: i18n.translate(
'xpack.securitySolution.endpoint.fleetCustomExtension.artifacts.eventFilters.backButtonLabel',
{ defaultMessage: 'Back to Fleet integration policy' }
),
onBackButtonNavigateTo: [
INTEGRATIONS_PLUGIN_ID,
{
path: fleetPackageIntegrationCustomUrlPath,
},
],
backButtonUrl: getAppUrl({
appId: INTEGRATIONS_PLUGIN_ID,
path: fleetPackageIntegrationCustomUrlPath,
}),
};
}, [getAppUrl, policyId]);

const policyEventFiltersLink = useMemo(
() => (
<LinkWithIcon
href={getAppUrl({
path: policyEventFiltersPath,
})}
appPath={policyEventFiltersPath}
appState={policyEventFiltersRouteState}
data-test-subj="linkToEventFilters"
size="m"
>
<FormattedMessage
id="xpack.securitySolution.endpoint.fleetCustomExtension.manageEventFiltersLabel"
defaultMessage="Manage event filters"
/>
</LinkWithIcon>
),
[getAppUrl, policyEventFiltersRouteState, policyEventFiltersPath]
);

return (
<div data-test-subj="endpointIntegrationPolicyForm">
{isTrustedAppsByPolicyEnabled ? (
Expand All @@ -181,6 +232,8 @@ const WrappedPolicyDetailsForm = memo<{
customLink={policyTrustedAppsLink}
/>
<EuiSpacer size="s" />
<FleetEventFiltersCard customLink={policyEventFiltersLink} cardSize="m" />
<EuiSpacer size="s" />
<FleetIntegrationHostIsolationExceptionsCard policyId={policyId} />
</div>
<EuiSpacer size="l" />
Expand All @@ -204,7 +257,7 @@ const WrappedPolicyDetailsForm = memo<{
}
iconType="alert"
color="warning"
data-test-subj="endpiontPolicySettingsLoadingError"
data-test-subj="endpointPolicySettingsLoadingError"
>
{endpointDetailsLoadingError.message}
</EuiCallOut>
Expand Down

0 comments on commit 505ac94

Please sign in to comment.