From 5de735763a685a10034d79d9d4a6146d4e6d8b79 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Fri, 23 Apr 2021 11:56:18 -0400 Subject: [PATCH] [Security solution][Endpoint] New Event Filters sub-section under Administration area (#97903) * Add Event Filters section to the Admin area (behind feature flag) * new `PaginatedContent` generic component * Refactor Trusted Apps grid view to use PaginatedContent * Refactor usages of `getTestId()` to use new hook --- .../components/item_details_card/index.tsx | 5 +- .../public/common/mock/global_state.ts | 4 + .../public/management/common/constants.ts | 1 + .../public/management/common/routing.ts | 12 + .../public/management/common/translations.ts | 4 + .../components/administration_list_page.tsx | 27 +- .../components/hooks/use_test_id_generator.ts | 36 + .../components/paginated_content/index.ts | 8 + .../paginated_content.test.tsx | 148 ++ .../paginated_content/paginated_content.tsx | 230 +++ .../management/pages/event_filters/index.tsx | 21 + .../management/pages/event_filters/types.ts | 11 + .../view/event_filters_list_page.tsx | 32 + .../public/management/pages/index.tsx | 17 +- .../condition_entry_input/index.tsx | 5 +- .../view/components/condition_group/index.tsx | 13 +- .../components/create_trusted_app_flyout.tsx | 10 +- .../components/create_trusted_app_form.tsx | 10 +- .../effected_policy_select.tsx | 10 +- .../logical_condition_builder.tsx | 13 +- .../__snapshots__/index.test.tsx.snap | 1742 +++++++++++------ .../trusted_apps_grid/index.test.tsx | 11 +- .../components/trusted_apps_grid/index.tsx | 126 +- .../pages/trusted_apps/view/translations.ts | 4 - .../public/management/types.ts | 1 + .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 27 files changed, 1752 insertions(+), 751 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/components/hooks/use_test_id_generator.ts create mode 100644 x-pack/plugins/security_solution/public/management/components/paginated_content/index.ts create mode 100644 x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.test.tsx create mode 100644 x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/event_filters/index.tsx create mode 100644 x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts create mode 100644 x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.tsx b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.tsx index c9fb5029560539c..47fe9dc175ce639 100644 --- a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.tsx @@ -102,16 +102,17 @@ ItemDetailsAction.displayName = 'ItemDetailsAction'; export type ItemDetailsCardProps = PropsWithChildren<{ 'data-test-subj'?: string; + className?: string; }>; export const ItemDetailsCard = memo( - ({ children, 'data-test-subj': dataTestSubj }) => { + ({ children, 'data-test-subj': dataTestSubj, className }) => { const childElements = useMemo( () => groupChildrenByType(children, [ItemDetailsPropertySummary, ItemDetailsAction]), [children] ); return ( - + diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index eac8fb7f6813e4d..538765e9fafa3ea 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -39,6 +39,10 @@ export const mockGlobalState: State = { { id: 'error-id-1', title: 'title-1', message: ['error-message-1'] }, { id: 'error-id-2', title: 'title-2', message: ['error-message-2'] }, ], + enableExperimental: { + eventFilteringEnabled: false, + trustedAppsByPolicyEnabled: false, + }, }, hosts: { page: { diff --git a/x-pack/plugins/security_solution/public/management/common/constants.ts b/x-pack/plugins/security_solution/public/management/common/constants.ts index 1b5ddd28d328f13..2ed00309992a8be 100644 --- a/x-pack/plugins/security_solution/public/management/common/constants.ts +++ b/x-pack/plugins/security_solution/public/management/common/constants.ts @@ -16,6 +16,7 @@ export const MANAGEMENT_ROUTING_ENDPOINTS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH export const MANAGEMENT_ROUTING_POLICIES_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.policies})`; export const MANAGEMENT_ROUTING_POLICY_DETAILS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId`; export const MANAGEMENT_ROUTING_TRUSTED_APPS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.trustedApps})`; +export const MANAGEMENT_ROUTING_EVENT_FILTERS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.eventFilters})`; // --[ STORE ]--------------------------------------------------------------------------- /** The SIEM global store namespace where the management state will be mounted */ diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts index 82aa96714d70eb4..d9da1d95dce9641 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.ts @@ -15,6 +15,7 @@ import { MANAGEMENT_DEFAULT_PAGE_SIZE, MANAGEMENT_PAGE_SIZE_OPTIONS, MANAGEMENT_ROUTING_ENDPOINTS_PATH, + MANAGEMENT_ROUTING_EVENT_FILTERS_PATH, MANAGEMENT_ROUTING_POLICIES_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_PATH, MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, @@ -23,6 +24,7 @@ import { AdministrationSubTab } from '../types'; import { appendSearch } from '../../common/components/link_to/helpers'; import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types'; import { TrustedAppsListPageLocation } from '../pages/trusted_apps/state'; +import { EventFiltersListPageUrlSearchParams } from '../pages/event_filters/types'; // Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150 type ExactKeys = Exclude extends never ? T1 : never; @@ -178,3 +180,13 @@ export const getTrustedAppsListPath = (location?: Partial +): string => { + const path = generatePath(MANAGEMENT_ROUTING_EVENT_FILTERS_PATH, { + tabName: AdministrationSubTab.eventFilters, + }); + + return `${path}${appendSearch(querystring.stringify(location))}`; +}; diff --git a/x-pack/plugins/security_solution/public/management/common/translations.ts b/x-pack/plugins/security_solution/public/management/common/translations.ts index 063750e96963060..d79771df6ff3956 100644 --- a/x-pack/plugins/security_solution/public/management/common/translations.ts +++ b/x-pack/plugins/security_solution/public/management/common/translations.ts @@ -21,6 +21,10 @@ export const TRUSTED_APPS_TAB = i18n.translate('xpack.securitySolution.trustedAp defaultMessage: 'Trusted applications', }); +export const EVENT_FILTERS_TAB = i18n.translate('xpack.securitySolution.eventFiltersTab', { + defaultMessage: 'Event filters', +}); + export const BETA_BADGE_LABEL = i18n.translate('xpack.securitySolution.administration.list.beta', { defaultMessage: 'Beta', }); diff --git a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx index d4358d54d553155..02fbb4f4b029625 100644 --- a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx +++ b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx @@ -14,8 +14,18 @@ import { HeaderPage } from '../../common/components/header_page'; import { SiemNavigation } from '../../common/components/navigation'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { AdministrationSubTab } from '../types'; -import { ENDPOINTS_TAB, TRUSTED_APPS_TAB, BETA_BADGE_LABEL } from '../common/translations'; -import { getEndpointListPath, getTrustedAppsListPath } from '../common/routing'; +import { + ENDPOINTS_TAB, + TRUSTED_APPS_TAB, + BETA_BADGE_LABEL, + EVENT_FILTERS_TAB, +} from '../common/translations'; +import { + getEndpointListPath, + getEventFiltersListPath, + getTrustedAppsListPath, +} from '../common/routing'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; /** Ensure that all flyouts z-index in Administation area show the flyout header */ const EuiPanelStyled = styled(EuiPanel)` @@ -34,6 +44,7 @@ interface AdministrationListPageProps { export const AdministrationListPage: FC = memo( ({ beta, title, subtitle, actions, children, headerBackComponent, ...otherProps }) => { + const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const badgeOptions = !beta ? undefined : { beta: true, text: BETA_BADGE_LABEL }; return ( @@ -66,6 +77,18 @@ export const AdministrationListPage: FC diff --git a/x-pack/plugins/security_solution/public/management/components/hooks/use_test_id_generator.ts b/x-pack/plugins/security_solution/public/management/components/hooks/use_test_id_generator.ts new file mode 100644 index 000000000000000..35ba460b7e876c5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/hooks/use_test_id_generator.ts @@ -0,0 +1,36 @@ +/* + * 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 { useCallback } from 'react'; + +/** + * Returns a callback that can be used to generate new test ids (values for `data-test-subj`) that + * are prefix with a standard string. Will only generate test ids if a prefix is defiened. + * Use it in complex component where you might want to expose a `data-test-subj` prop and use that + * as a prefix to several other test ids inside of the complex component. + * + * @example + * // `props['data-test-subj'] = 'abc'; + * const getTestId = useTestIdGenerator(props['data-test-subj']); + * getTestId('body'); // abc-body + * getTestId('some-other-ui-section'); // abc-some-other-ui-section + * + * @example + * // `props['data-test-subj'] = undefined; + * const getTestId = useTestIdGenerator(props['data-test-subj']); + * getTestId('body'); // undefined + */ +export const useTestIdGenerator = (prefix?: string): ((suffix: string) => string | undefined) => { + return useCallback( + (suffix: string): string | undefined => { + if (prefix) { + return `${prefix}-${suffix}`; + } + }, + [prefix] + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/components/paginated_content/index.ts b/x-pack/plugins/security_solution/public/management/components/paginated_content/index.ts new file mode 100644 index 000000000000000..c3fdcae31e12a43 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/paginated_content/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './paginated_content'; diff --git a/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.test.tsx b/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.test.tsx new file mode 100644 index 000000000000000..fc5c19e95fb770e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.test.tsx @@ -0,0 +1,148 @@ +/* + * 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, { FC } from 'react'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../../common/mock/endpoint'; +import { PaginatedContentProps, PaginatedContent } from './paginated_content'; +import { act, fireEvent } from '@testing-library/react'; + +describe('when using PaginatedContent', () => { + interface Foo { + id: string; + } + + interface ItemComponentProps { + item: Foo; + } + + type ItemComponentType = FC; + + type PropsForPaginatedContent = PaginatedContentProps>; + + const ItemComponent: ItemComponentType = jest.fn((props) => ( +
{'hi'}
+ )); + + const getPropsToRenderItem: PropsForPaginatedContent['itemComponentProps'] = jest.fn( + (item: Foo) => { + return { item }; + } + ); + + let render: ( + additionalProps?: Partial + ) => ReturnType; + let renderResult: ReturnType; + let onChangeHandler: PropsForPaginatedContent['onChange']; + + beforeEach(() => { + const mockedContext = createAppRootMockRenderer(); + + onChangeHandler = jest.fn(); + + render = (additionalProps) => { + const props: PropsForPaginatedContent = { + items: Array.from({ length: 10 }, (v, i) => ({ id: String(i) })), + ItemComponent, + onChange: onChangeHandler, + itemComponentProps: getPropsToRenderItem, + pagination: { + pageIndex: 0, + pageSizeOptions: [5, 10, 20], + pageSize: 5, + totalItemCount: 10, + }, + 'data-test-subj': 'test', + ...(additionalProps ?? {}), + }; + renderResult = mockedContext.render( {...props} />); + return renderResult; + }; + }); + + it('should render items using provided component', () => { + render({ itemId: 'id' }); // Using `itemsId` prop just to ensure that branch of code is executed + + expect(renderResult.baseElement.querySelectorAll('.foo-item').length).toBe(10); + expect(getPropsToRenderItem).toHaveBeenNthCalledWith(1, { id: '0' }); + expect(ItemComponent).toHaveBeenNthCalledWith(1, { item: { id: '0' } }, {}); + expect(renderResult.getByTestId('test-footer')).not.toBeNull(); + }); + + it('should show default "no items found message" when no data to display', () => { + render({ items: [] }); + + expect(renderResult.getByText('No items found')).not.toBeNull(); + }); + + it('should allow for a custom no items found message to be displayed', () => { + render({ items: [], noItemsMessage: 'no Foo found!' }); + + expect(renderResult.getByText('no Foo found!')).not.toBeNull(); + }); + + it('should show error if one is defined (even if `items` is not empty)', () => { + render({ error: 'something is wrong with foo' }); + + expect(renderResult.getByText('something is wrong with foo')).not.toBeNull(); + expect(renderResult.baseElement.querySelectorAll('.foo-item').length).toBe(0); + }); + + it('should show a progress bar if `loading` is set to true', () => { + render({ loading: true }); + + expect(renderResult.baseElement.querySelector('.euiProgress')).not.toBeNull(); + }); + + it('should NOT show a pagination footer if no props are defined for `pagination`', () => { + render({ pagination: undefined }); + + expect(renderResult.queryByTestId('test-footer')).toBeNull(); + }); + + it('should apply `contentClassName` if one is defined', () => { + render({ contentClassName: 'foo-content' }); + + expect(renderResult.baseElement.querySelector('.foo-content')).not.toBeNull(); + }); + + it('should call onChange when pagination is changed', () => { + render(); + + act(() => { + fireEvent.click(renderResult.getByTestId('pagination-button-next')); + }); + + expect(onChangeHandler).toHaveBeenCalledWith({ + pageIndex: 1, + pageSize: 5, + }); + }); + + it('should call onChange when page size is changed', () => { + render(); + + act(() => { + fireEvent.click(renderResult.getByTestId('tablePaginationPopoverButton')); + }); + + act(() => { + fireEvent.click(renderResult.getByTestId('tablePagination-10-rows')); + }); + + expect(onChangeHandler).toHaveBeenCalledWith({ + pageIndex: 0, + pageSize: 10, + }); + }); + + it('should ignore items, error, noItemsMessage when `children` is used', () => { + render({ children:
{'children being used here'}
}); + expect(renderResult.getByTestId('custom-content')).not.toBeNull(); + expect(renderResult.baseElement.querySelectorAll('.foo-item').length).toBe(0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.tsx b/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.tsx new file mode 100644 index 000000000000000..ce5d26feb3e753a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/paginated_content/paginated_content.tsx @@ -0,0 +1,230 @@ +/* + * 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, { + ComponentProps, + ComponentType, + FunctionComponent, + Key, + memo, + ReactElement, + ReactNode, + useCallback, + useMemo, + useState, +} from 'react'; +import { + CommonProps, + EuiEmptyPrompt, + EuiIcon, + EuiProgress, + EuiSpacer, + EuiTablePagination, + EuiTablePaginationProps, + EuiText, + Pagination, +} from '@elastic/eui'; +import styled from 'styled-components'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { v4 as generateUUI } from 'uuid'; +import { useTestIdGenerator } from '../hooks/use_test_id_generator'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ComponentWithAnyProps = ComponentType; + +export interface PaginatedContentProps extends CommonProps { + items: T[]; + onChange: (changes: { pageIndex: number; pageSize: number }) => void; + /** + * The React Component that will be used to render the `items`. use `itemComponentProps` below to + * define the props that will be given to this component + */ + ItemComponent: C; + /** A callback that will be used to retrieve the props for the `ItemComponent` */ + itemComponentProps: (item: T) => ComponentProps; + /** The item attribute that holds its unique value */ + itemId?: keyof T; + loading?: boolean; + pagination?: Pagination; + noItemsMessage?: ReactNode; + /** Error to be displayed in the component's body area. Used when `items` is empty and `children` is not used */ + error?: ReactNode; + /** Classname applied to the area that holds the content items */ + contentClassName?: string; + /** + * Children can be used to define custom content if the default creation of items is not sufficient + * to accommodate a use case. + * + * **IMPORTANT** If defined several input props will be ignored, like `items`, `noItemsMessage` + * and `error` among others + */ + children?: ReactNode; +} + +// Using `memo()` on generic typed Functional component is not supported (generic is lost), +// Work around below was created based on this discussion: +// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37087#issuecomment-568218789 +interface TypedGenericComponentMemo { + (p: PaginatedContentProps): ReactElement< + PaginatedContentProps, + FunctionComponent> + >; + + displayName: string; +} + +const RootContainer = styled.div` + position: relative; + + .body { + min-height: ${({ theme }) => theme.eui.gutterTypes.gutterExtraLarge}; + + &-content { + position: relative; + } + } +`; + +const DefaultNoItemsFound = memo(() => { + return ( + + } + /> + ); +}); + +DefaultNoItemsFound.displayName = 'DefaultNoItemsFound'; + +const ErrorMessage = memo<{ message: string }>(({ message }) => { + return ( + + + {message} + + + ); +}); + +ErrorMessage.displayName = 'ErrorMessage'; + +/** + * A generic component to display paginated content. Provides "Items per Page" as well as pagination + * controls similar to the BasicTable of EUI. The props supported by this component (for the most part) + * support those that BasicTable accept. + */ +// eslint-disable-next-line react/display-name +export const PaginatedContent = memo( + ({ + items, + ItemComponent, + itemComponentProps, + itemId, + onChange, + pagination, + loading, + noItemsMessage, + error, + contentClassName, + 'data-test-subj': dataTestSubj, + 'aria-label': ariaLabel, + className, + children, + }: PaginatedContentProps) => { + const [itemKeys] = useState>(new WeakMap()); + + const getTestId = useTestIdGenerator(dataTestSubj); + + const pageCount = useMemo( + () => Math.ceil((pagination?.totalItemCount || 1) / (pagination?.pageSize || 1)), + [pagination?.pageSize, pagination?.totalItemCount] + ); + + const handleItemsPerPageChange: EuiTablePaginationProps['onChangeItemsPerPage'] = useCallback( + (pageSize) => { + onChange({ pageSize, pageIndex: pagination?.pageIndex || 0 }); + }, + [onChange, pagination?.pageIndex] + ); + + const handlePageChange: EuiTablePaginationProps['onChangePage'] = useCallback( + (pageIndex) => { + onChange({ pageIndex, pageSize: pagination?.pageSize || 10 }); + }, + [onChange, pagination?.pageSize] + ); + + const generatedBodyItemContent = useMemo(() => { + if (error) { + return 'string' === typeof error ? : error; + } + + // This casting here is needed in order to avoid the following a TS error (TS2322) + // stating that the attributes given to the `ItemComponent` are not assignable to + // type 'LibraryManagedAttributes' + // @see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34553 + const Item = ItemComponent as ComponentType>; + + if (items.length) { + return items.map((item) => { + let key: Key; + + if (itemId) { + key = (item[itemId] as unknown) as Key; + } else { + if (itemKeys.has(item)) { + key = itemKeys.get(item)!; + } else { + key = generateUUI(); + itemKeys.set(item, key); + } + } + + return ; + }); + } + + return noItemsMessage || ; + }, [ItemComponent, error, itemComponentProps, itemId, itemKeys, items, noItemsMessage]); + + return ( + + {loading && } + +
+ +
+ {children ? children : generatedBodyItemContent} +
+
+ + {pagination && ( +
+ + + +
+ )} +
+ ); + } + // See type description above to understand why this casting is needed +) as TypedGenericComponentMemo; + +PaginatedContent.displayName = 'PaginatedContent'; diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/index.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/index.tsx new file mode 100644 index 000000000000000..86c2f2364961d5a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/index.tsx @@ -0,0 +1,21 @@ +/* + * 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 { Route, Switch } from 'react-router-dom'; +import React from 'react'; +import { NotFoundPage } from '../../../app/404'; +import { MANAGEMENT_ROUTING_EVENT_FILTERS_PATH } from '../../common/constants'; +import { EventFiltersListPage } from './view/event_filters_list_page'; + +export const EventFiltersContainer = () => { + return ( + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts new file mode 100644 index 000000000000000..0aceca88efbc7a4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/types.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export interface EventFiltersListPageUrlSearchParams { + page_index: number; + page_size: number; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.tsx new file mode 100644 index 000000000000000..a1a31f692749055 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.tsx @@ -0,0 +1,32 @@ +/* + * 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 } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AdministrationListPage } from '../../../components/administration_list_page'; + +export const EventFiltersListPage = memo(() => { + return ( + + } + subtitle={i18n.translate('xpack.securitySolution.eventFilters.aboutInfo', { + defaultMessage: 'Something here about Event Filtering....', + })} + > + {/* */} + + ); +}); + +EventFiltersListPage.displayName = 'EventFiltersListPage'; diff --git a/x-pack/plugins/security_solution/public/management/pages/index.tsx b/x-pack/plugins/security_solution/public/management/pages/index.tsx index b9cb3e72c7ec4f7..9e1a90a031d9973 100644 --- a/x-pack/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/index.tsx @@ -14,6 +14,7 @@ import { EuiText, EuiEmptyPrompt } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { MANAGEMENT_ROUTING_ENDPOINTS_PATH, + MANAGEMENT_ROUTING_EVENT_FILTERS_PATH, MANAGEMENT_ROUTING_POLICIES_PATH, MANAGEMENT_ROUTING_ROOT_PATH, MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, @@ -28,14 +29,22 @@ import { GetUrlForApp } from '../../common/components/navigation/types'; import { AdministrationRouteSpyState } from '../../common/utils/route/types'; import { ADMINISTRATION } from '../../app/home/translations'; import { AdministrationSubTab } from '../types'; -import { ENDPOINTS_TAB, POLICIES_TAB, TRUSTED_APPS_TAB } from '../common/translations'; +import { + ENDPOINTS_TAB, + EVENT_FILTERS_TAB, + POLICIES_TAB, + TRUSTED_APPS_TAB, +} from '../common/translations'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { useIngestEnabledCheck } from '../../common/hooks/endpoint/ingest_enabled'; +import { EventFiltersContainer } from './event_filters'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; const TabNameMappedToI18nKey: Record = { [AdministrationSubTab.endpoints]: ENDPOINTS_TAB, [AdministrationSubTab.policies]: POLICIES_TAB, [AdministrationSubTab.trustedApps]: TRUSTED_APPS_TAB, + [AdministrationSubTab.eventFilters]: EVENT_FILTERS_TAB, }; export function getBreadcrumbs( @@ -88,6 +97,7 @@ NoPermissions.displayName = 'NoPermissions'; export const ManagementContainer = memo(() => { const history = useHistory(); + const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const { allEnabled: isIngestEnabled } = useIngestEnabledCheck(); if (!isIngestEnabled) { @@ -99,6 +109,11 @@ export const ManagementContainer = memo(() => { + + {isEventFilteringEnabled && ( + + )} + ( onVisited, 'data-test-subj': dataTestSubj, }) => { - const getTestId = useCallback((suffix: string) => dataTestSubj && `${dataTestSubj}-${suffix}`, [ - dataTestSubj, - ]); + const getTestId = useTestIdGenerator(dataTestSubj); const fieldOptions = useMemo>>(() => { const getDropdownDisplay = (field: ConditionEntryField) => ( diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_group/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_group/index.tsx index 8b558da6790e4a6..0fa3560670a0c92 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_group/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/condition_group/index.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React, { memo, useCallback } from 'react'; +import React, { memo } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiHideFor, EuiSpacer } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import { ConditionEntry, OperatingSystem } from '../../../../../../../common/endpoint/types'; import { AndOrBadge } from '../../../../../../common/components/and_or_badge'; import { ConditionEntryInput, ConditionEntryInputProps } from '../condition_entry_input'; +import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; const ConditionGroupFlexGroup = styled(EuiFlexGroup)` // The positioning of the 'and-badge' is done by using the EuiButton's height and adding on to it @@ -63,14 +64,8 @@ export const ConditionGroup = memo( onVisited, 'data-test-subj': dataTestSubj, }) => { - const getTestId = useCallback( - (suffix: string): string | undefined => { - if (dataTestSubj) { - return `${dataTestSubj}-${suffix}`; - } - }, - [dataTestSubj] - ); + const getTestId = useTestIdGenerator(dataTestSubj); + return ( {entries.length > 1 && ( diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx index 8a0d60275bcfedc..8078a21ccb33946 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_flyout.tsx @@ -44,6 +44,7 @@ import { ABOUT_TRUSTED_APPS, CREATE_TRUSTED_APP_ERROR } from '../translations'; import { defaultNewTrustedApp } from '../../store/builders'; import { getTrustedAppsListPath } from '../../../../common/routing'; import { useToasts } from '../../../../../common/lib/kibana'; +import { useTestIdGenerator } from '../../../../components/hooks/use_test_id_generator'; type CreateTrustedAppFlyoutProps = Omit; export const CreateTrustedAppFlyout = memo( @@ -81,14 +82,7 @@ export const CreateTrustedAppFlyout = memo( }; }, [isLoadingPolicies, policyList]); - const getTestId = useCallback( - (suffix: string): string | undefined => { - if (dataTestSubj) { - return `${dataTestSubj}-${suffix}`; - } - }, - [dataTestSubj] - ); + const getTestId = useTestIdGenerator(dataTestSubj); const handleCancelClick = useCallback(() => { if (creationInProgress) { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx index e03c2aad7621e07..fe1b40aac232293 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx @@ -42,6 +42,7 @@ import { EffectedPolicySelection, EffectedPolicySelectProps, } from './effected_policy_select'; +import { useTestIdGenerator } from '../../../../components/hooks/use_test_id_generator'; const OPERATING_SYSTEMS: readonly OperatingSystem[] = [ OperatingSystem.MAC, @@ -212,14 +213,7 @@ export const CreateTrustedAppForm = memo( > >({}); - const getTestId = useCallback( - (suffix: string): string | undefined => { - if (dataTestSubj) { - return `${dataTestSubj}-${suffix}`; - } - }, - [dataTestSubj] - ); + const getTestId = useTestIdGenerator(dataTestSubj); const notifyOfChange = useCallback( (updatedFormValues: TrustedAppFormState['item']) => { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx index 30c259b47c7bad3..7ec8d311a9156e4 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx @@ -26,6 +26,7 @@ import { getPolicyDetailPath } from '../../../../../common/routing'; import { useFormatUrl } from '../../../../../../common/components/link_to'; import { SecurityPageName } from '../../../../../../../common/constants'; import { LinkToApp } from '../../../../../../common/components/endpoint/link_to_app'; +import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; const NOOP = () => {}; const DEFAULT_LIST_PROPS: EuiSelectableProps['listProps'] = { bordered: true, showIcons: false }; @@ -69,14 +70,7 @@ export const EffectedPolicySelect = memo( }) => { const { formatUrl } = useFormatUrl(SecurityPageName.administration); - const getTestId = useCallback( - (suffix): string | undefined => { - if (dataTestSubj) { - return `${dataTestSubj}-${suffix}`; - } - }, - [dataTestSubj] - ); + const getTestId = useTestIdGenerator(dataTestSubj); const selectableOptions: EffectedPolicyOption[] = useMemo(() => { const isPolicySelected = new Set(selected.map((policy) => policy.id)); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/logical_condition_builder.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/logical_condition_builder.tsx index 180115fcfc0da9a..d0a31bff2b638d6 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/logical_condition_builder.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/logical_condition/logical_condition_builder.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { memo, useCallback } from 'react'; +import React, { memo } from 'react'; import { CommonProps, EuiText, EuiPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { ConditionGroup, ConditionGroupProps } from '../condition_group'; +import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; export type LogicalConditionBuilderProps = CommonProps & ConditionGroupProps; export const LogicalConditionBuilder = memo( @@ -23,14 +24,8 @@ export const LogicalConditionBuilder = memo( onVisited, 'data-test-subj': dataTestSubj, }) => { - const getTestId = useCallback( - (suffix: string): string | undefined => { - if (dataTestSubj) { - return `${dataTestSubj}-${suffix}`; - } - }, - [dataTestSubj] - ); + const getTestId = useTestIdGenerator(dataTestSubj); + return (
diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap index 220494b3a56944e..c4a58a3b99d3f43 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap @@ -1,27 +1,155 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`TrustedAppsGrid renders correctly initially 1`] = ` +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
- No items found +
+ + + No items found + +
+ +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
@@ -29,28 +157,161 @@ exports[`TrustedAppsGrid renders correctly initially 1`] = ` `; exports[`TrustedAppsGrid renders correctly when failed loading data for the first time 1`] = ` +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
- - - Intenal Server Error
+
+
+
+ + + Intenal Server Error +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
@@ -58,28 +319,266 @@ exports[`TrustedAppsGrid renders correctly when failed loading data for the firs `; exports[`TrustedAppsGrid renders correctly when failed loading data for the second time 1`] = ` +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
- - - Intenal Server Error
+
+
+
+ + + Intenal Server Error +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
@@ -87,57 +586,74 @@ exports[`TrustedAppsGrid renders correctly when failed loading data for the seco `; exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` -.c0 { +.c2 { + background-color: #f5f7fa; padding: 16px; } -.c3 { +.c5 { padding: 16px; } -.c1.c1.c1 { +.c3.c3.c3 { width: 40%; } -.c2.c2.c2 { +.c4.c4.c4 { width: 60%; } +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
-
+
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
-
+
@@ -3064,34 +3540,158 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` `; exports[`TrustedAppsGrid renders correctly when loading data for the first time 1`] = ` +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
-
-
- No items found +
+ + + No items found + +
+ +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
@@ -3099,64 +3699,77 @@ exports[`TrustedAppsGrid renders correctly when loading data for the first time `; exports[`TrustedAppsGrid renders correctly when loading data for the second time 1`] = ` -.c0 { +.c2 { + background-color: #f5f7fa; padding: 16px; } -.c3 { +.c5 { padding: 16px; } -.c1.c1.c1 { +.c3.c3.c3 { width: 40%; } -.c2.c2.c2 { +.c4.c4.c4 { width: 60%; } +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
-
-
-
+
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
-
+
@@ -6083,57 +6656,74 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time `; exports[`TrustedAppsGrid renders correctly when new page and page size set (not loading yet) 1`] = ` -.c0 { +.c2 { + background-color: #f5f7fa; padding: 16px; } -.c3 { +.c5 { padding: 16px; } -.c1.c1.c1 { +.c3.c3.c3 { width: 40%; } -.c2.c2.c2 { +.c4.c4.c4 { width: 60%; } +.c1 { + position: relative; +} + +.c1 .body { + min-height: 40px; +} + +.c1 .body-content { + position: relative; +} + +.c0 .trusted-app + .trusted-app { + margin-top: 24px; +} +
-
+
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
Name
OS
Date Created
1 minute ago
Created By
Description
-
-
-
+
diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.test.tsx index 8a98903dd998348..4ed9a3c5a0119b9 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.test.tsx @@ -8,7 +8,6 @@ import { render } from '@testing-library/react'; import React from 'react'; import { Provider } from 'react-redux'; -import { ThemeProvider } from 'styled-components'; import { createSampleTrustedApp, @@ -21,13 +20,7 @@ import { } from '../../../test_utils'; import { TrustedAppsGrid } from '.'; -import { getMockTheme } from '../../../../../../common/lib/kibana/kibana_react.mock'; - -const mockTheme = getMockTheme({ - eui: { - euiSize: '16px', - }, -}); +import { EuiThemeProvider } from '../../../../../../../../../../src/plugins/kibana_react/common'; jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ htmlIdGenerator: () => () => 'mockId', @@ -38,7 +31,7 @@ const now = 111111; const renderList = (store: ReturnType) => { const Wrapper: React.FC = ({ children }) => ( - {children} + {children} ); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.tsx index b1be9ba295dd943..8d8b52ac62358b5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.tsx @@ -5,18 +5,10 @@ * 2.0. */ -import React, { FC, memo, useCallback, useEffect } from 'react'; -import { - EuiTablePagination, - EuiFlexGroup, - EuiFlexItem, - EuiProgress, - EuiIcon, - EuiText, - EuiSpacer, -} from '@elastic/eui'; +import React, { memo, useCallback } from 'react'; import { useHistory } from 'react-router-dom'; +import styled from 'styled-components'; import { Pagination } from '../../../state'; import { @@ -33,49 +25,26 @@ import { useTrustedAppsStoreActionCallback, } from '../../hooks'; -import { NO_RESULTS_MESSAGE } from '../../translations'; - import { TrustedAppCard, TrustedAppCardProps } from '../trusted_app_card'; import { getTrustedAppsListPath } from '../../../../../common/routing'; +import { + PaginatedContent, + PaginatedContentProps, +} from '../../../../../components/paginated_content'; +import { TrustedApp } from '../../../../../../../common/endpoint/types'; export interface PaginationBarProps { pagination: Pagination; onChange: (pagination: { size: number; index: number }) => void; } -const PaginationBar = ({ pagination, onChange }: PaginationBarProps) => { - const pageCount = Math.ceil(pagination.totalItemCount / pagination.pageSize); +type TrustedAppCardType = typeof TrustedAppCard; - useEffect(() => { - if (pageCount > 0 && pageCount < pagination.pageIndex + 1) { - onChange({ index: pageCount - 1, size: pagination.pageSize }); - } - }, [pageCount, onChange, pagination]); - - return ( -
- onChange({ index: 0, size }), [onChange])} - onChangePage={useCallback((index) => onChange({ index, size: pagination.pageSize }), [ - pagination.pageSize, - onChange, - ])} - /> -
- ); -}; - -const GridMessage: FC = ({ children }) => ( -
- - {children} - -
-); +const RootWrapper = styled.div` + .trusted-app + .trusted-app { + margin-top: ${({ theme }) => theme.eui.spacerSizes.l}; + } +`; export const TrustedAppsGrid = memo(() => { const history = useHistory(); @@ -103,55 +72,32 @@ export const TrustedAppsGrid = memo(() => { [history, location] ); - const handlePaginationChange = useTrustedAppsNavigateCallback(({ index, size }) => ({ - page_index: index, - page_size: size, + const handlePaginationChange: PaginatedContentProps< + TrustedApp, + TrustedAppCardType + >['onChange'] = useTrustedAppsNavigateCallback(({ pageIndex, pageSize }) => ({ + page_index: pageIndex, + page_size: pageSize, })); return ( - - {isLoading && ( - - - - )} - - {error && ( - - {error} - - )} - {!error && listItems.length === 0 && ( - - {NO_RESULTS_MESSAGE} - - )} - {!error && listItems.length > 0 && ( - <> - - - - {listItems.map((item) => ( - - - - ))} - - - )} - - {!error && pagination.totalItemCount > 0 && ( - - - - - - )} - + + + items={listItems as TrustedApp[]} + onChange={handlePaginationChange} + ItemComponent={TrustedAppCard} + itemComponentProps={(ta) => ({ + trustedApp: ta, + onDelete: handleTrustedAppDelete, + onEdit: handleTrustedAppEdit, + className: 'trusted-app', + })} + loading={isLoading} + itemId="id" + error={error} + pagination={pagination} + /> + ); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts index 57ca80930ad7d98..c3e2a372fd6dc07 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/translations.ts @@ -150,10 +150,6 @@ export const LIST_VIEW_TOGGLE_LABEL = i18n.translate( } ); -export const NO_RESULTS_MESSAGE = i18n.translate('xpack.securitySolution.trustedapps.noResults', { - defaultMessage: 'No items found', -}); - export const CREATE_TRUSTED_APP_ERROR: { [K in string]: string } = { [`duplicatedEntry.${ConditionEntryField.HASH}`]: i18n.translate( 'xpack.securitySolution.trustedapps.logicalConditionBuilder.entry.field.error.duplicated.hash', diff --git a/x-pack/plugins/security_solution/public/management/types.ts b/x-pack/plugins/security_solution/public/management/types.ts index 902010a97603c94..460a30eaca7839d 100644 --- a/x-pack/plugins/security_solution/public/management/types.ts +++ b/x-pack/plugins/security_solution/public/management/types.ts @@ -32,6 +32,7 @@ export enum AdministrationSubTab { endpoints = 'endpoints', policies = 'policy', trustedApps = 'trusted_apps', + eventFilters = 'event_filters', } /** diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8819b7e1bf1e1f7..bde4e24ecd96442 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -20354,7 +20354,6 @@ "xpack.securitySolution.trustedapps.logicalConditionBuilder.entry.removeLabel": "エントリを削除", "xpack.securitySolution.trustedapps.logicalConditionBuilder.group.andOperator": "AND", "xpack.securitySolution.trustedapps.logicalConditionBuilder.noEntries": "条件が定義されていません", - "xpack.securitySolution.trustedapps.noResults": "項目が見つかりません", "xpack.securitySolution.trustedapps.trustedapp.createdAt": "作成日", "xpack.securitySolution.trustedapps.trustedapp.createdBy": "作成者", "xpack.securitySolution.trustedapps.trustedapp.description": "説明", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f7a51c240bf2c9a..43d537ad560cde7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -20680,7 +20680,6 @@ "xpack.securitySolution.trustedapps.logicalConditionBuilder.entry.removeLabel": "移除条目", "xpack.securitySolution.trustedapps.logicalConditionBuilder.group.andOperator": "AND", "xpack.securitySolution.trustedapps.logicalConditionBuilder.noEntries": "未定义条件", - "xpack.securitySolution.trustedapps.noResults": "找不到项目", "xpack.securitySolution.trustedapps.trustedapp.createdAt": "创建日期", "xpack.securitySolution.trustedapps.trustedapp.createdBy": "创建者", "xpack.securitySolution.trustedapps.trustedapp.description": "描述",