diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 03e1d324494f4..1b4e23d83211b 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -105,11 +105,6 @@ export const allowedExperimentalValues = Object.freeze({ */ alertTypeEnabled: false, - /** - * Disables expandable flyout - */ - expandableFlyoutDisabled: false, - /** * Enables new notes */ @@ -132,7 +127,6 @@ export const allowedExperimentalValues = Object.freeze({ /** * Enables the Managed User section inside the new user details flyout. - * To see this section you also need expandableFlyoutDisabled flag set to false. */ newUserDetailsFlyoutManagedUser: false, diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx index 54ece0123738f..8609cdbd991e4 100644 --- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx @@ -11,7 +11,6 @@ import type { CaseViewRefreshPropInterface } from '@kbn/cases-plugin/common'; import { CaseMetricsFeature } from '@kbn/cases-plugin/common'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { CaseDetailsRefreshContext } from '../../common/components/endpoint'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/shared/constants/panel_keys'; import { useTourContext } from '../../common/components/guided_onboarding_tour'; import { @@ -58,7 +57,6 @@ const CaseContainerComponent: React.FC = () => { SecurityPageName.rules ); const { openFlyout } = useExpandableFlyoutApi(); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const getDetectionsRuleDetailsHref = useCallback( (ruleId) => detectionsFormatUrl(getRuleDetailsUrl(ruleId ?? '', detectionsUrlSearch)), @@ -69,38 +67,22 @@ const CaseContainerComponent: React.FC = () => { const showAlertDetails = useCallback( (alertId: string, index: string) => { - if (!expandableFlyoutDisabled) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: alertId, - indexName: index, - scopeId: TimelineId.casePage, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: alertId, + indexName: index, + scopeId: TimelineId.casePage, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: TimelineId.casePage, - panel: 'right', - }); - } - // TODO remove when https://github.com/elastic/security-team/issues/7462 is merged - // support of old flyout in cases page - else { - dispatch( - timelineActions.toggleDetailPanel({ - panelView: 'eventDetail', - id: TimelineId.casePage, - params: { - eventId: alertId, - indexName: index, - }, - }) - ); - } + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: TimelineId.casePage, + panel: 'right', + }); }, - [dispatch, expandableFlyoutDisabled, openFlyout, telemetry] + [openFlyout, telemetry] ); const endpointDetailsHref = (endpointId: string) => diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx index 416dfcae71c99..5c61900876aae 100644 --- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx @@ -7,14 +7,9 @@ import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; -import { useDispatch } from 'react-redux'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { dataTableActions, TableId } from '@kbn/securitysolution-data-table'; import { LeftPanelNotesTab } from '../../../../flyout/document_details/left'; -import { useRouteSpy } from '../../../utils/route/use_route_spy'; import { useKibana } from '../../../lib/kibana'; -import { timelineActions } from '../../../../timelines/store'; -import { SecurityPageName } from '../../../../../common/constants'; import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey, @@ -23,12 +18,10 @@ import type { SetEventsDeleted, SetEventsLoading, ControlColumnProps, - ExpandedDetailType, } from '../../../../../common/types'; import { getMappedNonEcsValue } from '../../../../timelines/components/timeline/body/data_driven_columns'; import type { TimelineItem, TimelineNonEcsData } from '../../../../../common/search_strategy'; import type { ColumnHeaderOptions, OnRowSelected } from '../../../../../common/types/timeline'; -import { TimelineId } from '../../../../../common/types'; import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { useTourContext } from '../../guided_onboarding_tour'; import { AlertsCasesTourSteps, SecurityStepId } from '../../guided_onboarding_tour/tour_config'; @@ -79,8 +72,6 @@ const RowActionComponent = ({ const { telemetry } = useKibana().services; const { openFlyout } = useExpandableFlyoutApi(); - const dispatch = useDispatch(); - const [{ pageName }] = useRouteSpy(); const { activeStep, isTourShown } = useTourContext(); const shouldFocusOnOverviewTab = (activeStep === AlertsCasesTourSteps.expandEvent || @@ -102,72 +93,27 @@ const RowActionComponent = ({ [columnHeaders, timelineNonEcsData] ); - // TODO remove when https://github.com/elastic/security-team/issues/7462 is merged - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' ); - const showExpandableFlyout = - pageName === SecurityPageName.attackDiscovery ? true : !expandableFlyoutDisabled; const handleOnEventDetailPanelOpened = useCallback(() => { - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'eventDetail', - params: { - eventId: eventId ?? '', - indexName: indexName ?? '', - }, - }; - - if (showExpandableFlyout) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - path: shouldFocusOnOverviewTab ? { tab: 'overview' } : undefined, - params: { - id: eventId, - indexName, - scopeId: tableId, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + path: shouldFocusOnOverviewTab ? { tab: 'overview' } : undefined, + params: { + id: eventId, + indexName, + scopeId: tableId, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: tableId, - panel: 'right', - }); - } - // TODO remove when https://github.com/elastic/security-team/issues/7462 is merged - // support of old flyout in cases page - else if (tableId === TableId.alertsOnCasePage) { - dispatch( - timelineActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: TimelineId.casePage, - }) - ); - } - // TODO remove when https://github.com/elastic/security-team/issues/7462 is merged - // support of old flyout - else { - dispatch( - dataTableActions.toggleDetailPanel({ - ...updatedExpandedDetail, - tabType, - id: tableId, - }) - ); - } - }, [ - eventId, - indexName, - showExpandableFlyout, - tableId, - openFlyout, - shouldFocusOnOverviewTab, - telemetry, - dispatch, - tabType, - ]); + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: tableId, + panel: 'right', + }); + }, [eventId, indexName, tableId, openFlyout, shouldFocusOnOverviewTab, telemetry]); const toggleShowNotes = useCallback(() => { openFlyout({ @@ -229,14 +175,12 @@ const RowActionComponent = ({ showCheckboxes={showCheckboxes} tabType={tabType} timelineId={tableId} - toggleShowNotes={ - !expandableFlyoutDisabled && securitySolutionNotesEnabled ? toggleShowNotes : undefined - } + toggleShowNotes={securitySolutionNotesEnabled ? toggleShowNotes : undefined} width={width} setEventsLoading={setEventsLoading} setEventsDeleted={setEventsDeleted} refetch={refetch} - showNotes={!expandableFlyoutDisabled && securitySolutionNotesEnabled ? true : false} + showNotes={securitySolutionNotesEnabled ? true : false} /> )} diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx index 9ae3f3adfed80..e8ba1e8c22d05 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx @@ -220,8 +220,6 @@ const ActionsComponent: React.FC = ({ 'securitySolutionNotesEnabled' ); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); - /* only applicable for new event based notes */ const documentBasedNotes = useSelector((state: State) => selectNotesByDocumentId(state, eventId)); @@ -232,18 +230,15 @@ const ActionsComponent: React.FC = ({ ); const notesCount = useMemo( - () => - securitySolutionNotesEnabled && !expandableFlyoutDisabled - ? documentBasedNotes.length - : timelineNoteIds.length, - [documentBasedNotes, timelineNoteIds, securitySolutionNotesEnabled, expandableFlyoutDisabled] + () => (securitySolutionNotesEnabled ? documentBasedNotes.length : timelineNoteIds.length), + [documentBasedNotes, timelineNoteIds, securitySolutionNotesEnabled] ); const noteIds = useMemo(() => { - return securitySolutionNotesEnabled && !expandableFlyoutDisabled + return securitySolutionNotesEnabled ? documentBasedNotes.map((note) => note.noteId) : timelineNoteIds; - }, [documentBasedNotes, timelineNoteIds, securitySolutionNotesEnabled, expandableFlyoutDisabled]); + }, [documentBasedNotes, timelineNoteIds, securitySolutionNotesEnabled]); return ( diff --git a/x-pack/plugins/security_solution/public/common/hooks/flyout/types.ts b/x-pack/plugins/security_solution/public/common/hooks/flyout/types.ts deleted file mode 100644 index 09fd6a25cc53e..0000000000000 --- a/x-pack/plugins/security_solution/public/common/hooks/flyout/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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 type { ExpandedDetailType } from '../../../../common/types'; - -export type FlyoutUrlState = ExpandedDetailType; diff --git a/x-pack/plugins/security_solution/public/common/hooks/flyout/use_init_flyout_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/flyout/use_init_flyout_url_param.ts deleted file mode 100644 index 659fc15ca5ea5..0000000000000 --- a/x-pack/plugins/security_solution/public/common/hooks/flyout/use_init_flyout_url_param.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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, useEffect, useState } from 'react'; -import { useDispatch } from 'react-redux'; -import { useLocation } from 'react-router-dom'; -import { - dataTableSelectors, - TableId, - tableDefaults, - dataTableActions, -} from '@kbn/securitysolution-data-table'; -import { useIsExperimentalFeatureEnabled } from '../use_experimental_features'; -import { useInitializeUrlParam } from '../../utils/global_query_string'; -import { URL_PARAM_KEY } from '../use_url_state'; -import type { FlyoutUrlState } from './types'; -import { useShallowEqualSelector } from '../use_selector'; -import { getQueryStringKeyValue } from '../timeline/use_query_timeline_by_id_on_url_change'; - -/** - * The state of the old flyout of the table in the Alerts page is stored in local storage. - * This hook was created to initialize things and populate the url with the correct param and its value. - * This is only be needed with the old flyout. - * // TODO remove this hook entirely when we delete the old flyout code - */ - -export const useInitFlyoutFromUrlParam = () => { - const { search } = useLocation(); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); - const [urlDetails, setUrlDetails] = useState(null); - const [hasLoadedUrlDetails, updateHasLoadedUrlDetails] = useState(false); - const dispatch = useDispatch(); - const getDataTable = dataTableSelectors.getTableByIdSelector(); - - // Only allow the alerts page for now to be saved in the url state. - // Allowing only one makes the transition to the expanded flyout much easier as well - const dataTableCurrent = useShallowEqualSelector( - (state) => getDataTable(state, TableId.alertsOnAlertsPage) ?? tableDefaults - ); - - const onInitialize = useCallback( - (initialState: FlyoutUrlState | null) => { - if (expandableFlyoutDisabled && initialState != null && initialState.panelView) { - setUrlDetails(initialState); - } - }, - [expandableFlyoutDisabled] - ); - - const loadExpandedDetailFromUrl = useCallback(() => { - if (!expandableFlyoutDisabled) return; - - const { initialized, isLoading, totalCount, additionalFilters } = dataTableCurrent; - const isTableLoaded = initialized && !isLoading && totalCount > 0; - if (urlDetails) { - if (!additionalFilters || !additionalFilters.showBuildingBlockAlerts) { - // We want to show building block alerts when loading the flyout in case the alert is a building block alert - dispatch( - dataTableActions.updateShowBuildingBlockAlertsFilter({ - id: TableId.alertsOnAlertsPage, - showBuildingBlockAlerts: true, - }) - ); - } - - if (isTableLoaded) { - updateHasLoadedUrlDetails(true); - dispatch( - dataTableActions.toggleDetailPanel({ - id: TableId.alertsOnAlertsPage, - ...urlDetails, - }) - ); - } - } - }, [dataTableCurrent, dispatch, expandableFlyoutDisabled, urlDetails]); - - // The alert page creates a default dataTable slice in redux initially that is later overriden when data is retrieved - // We use the below to store the urlDetails on app load, and then set it when the table is done loading and has data - useEffect(() => { - if (expandableFlyoutDisabled && !hasLoadedUrlDetails) { - loadExpandedDetailFromUrl(); - } - }, [hasLoadedUrlDetails, expandableFlyoutDisabled, loadExpandedDetailFromUrl]); - - // We check the url for the presence of the old `evenFlyout` parameter. If it exists replace it with the new `flyout` key. - const eventFlyoutKey = getQueryStringKeyValue({ urlKey: URL_PARAM_KEY.eventFlyout, search }); - let currentKey = ''; - let newKey = ''; - if (expandableFlyoutDisabled) { - if (eventFlyoutKey) { - currentKey = URL_PARAM_KEY.eventFlyout; - newKey = URL_PARAM_KEY.flyout; - } else { - currentKey = URL_PARAM_KEY.flyout; - } - } - useInitializeUrlParam(currentKey, onInitialize, newKey); -}; diff --git a/x-pack/plugins/security_solution/public/common/hooks/flyout/use_sync_flyout_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/flyout/use_sync_flyout_url_param.ts deleted file mode 100644 index a6f4904d37cd9..0000000000000 --- a/x-pack/plugins/security_solution/public/common/hooks/flyout/use_sync_flyout_url_param.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; -import { - dataTableActions, - dataTableSelectors, - tableDefaults, - TableId, -} from '@kbn/securitysolution-data-table'; -import { useIsExperimentalFeatureEnabled } from '../use_experimental_features'; -import { ALERTS_PATH } from '../../../../common/constants'; -import { useUpdateUrlParam } from '../../utils/global_query_string'; -import { useShallowEqualSelector } from '../use_selector'; -import { URL_PARAM_KEY } from '../use_url_state'; -import type { FlyoutUrlState } from './types'; - -/** - * The state of the old flyout of the table in the Alerts page is stored in local storage. - * This hook was created to sync the data stored in local storage to the url. - * This is only be needed with the old flyout. - * // TODO remove this hook entirely when we delete the old flyout code - */ -export const useSyncFlyoutUrlParam = () => { - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); - const updateUrlParam = useUpdateUrlParam(URL_PARAM_KEY.flyout); - const { pathname } = useLocation(); - const dispatch = useDispatch(); - const getDataTable = dataTableSelectors.getTableByIdSelector(); - - // Only allow the alerts page for now to be saved in the url state - const { expandedDetail } = useShallowEqualSelector( - (state) => getDataTable(state, TableId.alertsOnAlertsPage) ?? tableDefaults - ); - - useEffect(() => { - if (!expandableFlyoutDisabled) return; - - const isOnAlertsPage = pathname === ALERTS_PATH; - if (isOnAlertsPage && expandedDetail != null && expandedDetail?.query) { - updateUrlParam(expandedDetail.query.panelView ? expandedDetail.query : null); - } else if (!isOnAlertsPage && expandedDetail?.query?.panelView) { - // Close the detail panel as it's stored in a top level redux store maintained across views - dispatch( - dataTableActions.toggleDetailPanel({ - id: TableId.alertsOnAlertsPage, - }) - ); - // Clear the reference from the url - updateUrlParam(null); - } - }, [dispatch, expandedDetail, expandableFlyoutDisabled, pathname, updateUrlParam]); -}; diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts b/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts index 597a87f6844d2..47168d76e8ec3 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts @@ -12,8 +12,6 @@ import { useUpdateTimerangeOnPageChange } from './search_bar/use_update_timerang import { useInitTimelineFromUrlParam } from './timeline/use_init_timeline_url_param'; import { useSyncTimelineUrlParam } from './timeline/use_sync_timeline_url_param'; import { useQueryTimelineByIdOnUrlChange } from './timeline/use_query_timeline_by_id_on_url_change'; -import { useInitFlyoutFromUrlParam } from './flyout/use_init_flyout_url_param'; -import { useSyncFlyoutUrlParam } from './flyout/use_sync_flyout_url_param'; export const useUrlState = () => { useSyncGlobalQueryString(); @@ -23,8 +21,6 @@ export const useUrlState = () => { useInitTimelineFromUrlParam(); useSyncTimelineUrlParam(); useQueryTimelineByIdOnUrlChange(); - useInitFlyoutFromUrlParam(); - useSyncFlyoutUrlParam(); }; export const URL_PARAM_KEY = { diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx index 2e838e9f2ba23..4f2c995b163d5 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_actions_column.tsx @@ -29,11 +29,10 @@ export const getUseActionColumnHook = // we only want to show the note icon if the expandable flyout and the new notes system are enabled // TODO delete most likely in 8.16 - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' ); - if (expandableFlyoutDisabled || !securitySolutionNotesEnabled) { + if (!securitySolutionNotesEnabled) { ACTION_BUTTON_COUNT--; } diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx index 509d59338fe4d..d1f3bfea2aafe 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx @@ -11,9 +11,6 @@ import { AlertDetailsRedirect } from './alert_details_redirect'; import { TestProviders } from '../../../common/mock'; import { ALERTS_PATH, ALERT_DETAILS_REDIRECT_PATH } from '../../../../common/constants'; import { mockHistory } from '../../../common/utils/route/mocks'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; - -jest.mock('../../../common/hooks/use_experimental_features'); jest.mock('../../../common/lib/kibana'); @@ -149,37 +146,4 @@ describe('AlertDetailsRedirect', () => { }); }); }); - - describe('When expandable flyout is enabled', () => { - beforeEach(() => { - jest.mocked(useIsExperimentalFeatureEnabled).mockReturnValue(true); - }); - - describe('when eventFlyout or flyout are not in the query', () => { - it('redirects to the expected path with the correct query parameters', () => { - const testSearch = `?index=${testIndex}×tamp=${testTimestamp}`; - const historyMock = { - ...mockHistory, - location: { - hash: '', - pathname: mockPathname, - search: testSearch, - state: '', - }, - }; - render( - - - - - - ); - - const [{ search, pathname }] = historyMock.replace.mock.lastCall; - - expect(search as string).toMatch(/flyout.*/); - expect(pathname).toEqual(ALERTS_PATH); - }); - }); - }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx index 9655e6fb84f92..01e52d3ab7505 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx @@ -13,7 +13,6 @@ import moment from 'moment'; import { encode } from '@kbn/rison'; import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; import type { FilterControlConfig } from '@kbn/alerts-ui-shared'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { ALERTS_PATH, DEFAULT_ALERTS_INDEX } from '../../../../common/constants'; import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; import { inputsSelectors } from '../../../common/store'; @@ -69,16 +68,11 @@ export const AlertDetailsRedirect = () => { const currentFlyoutParams = searchParams.get(URL_PARAM_KEY.flyout); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); - const urlParams = new URLSearchParams({ [URL_PARAM_KEY.appQuery]: kqlAppQuery, [URL_PARAM_KEY.timerange]: timerange, [URL_PARAM_KEY.pageFilter]: pageFiltersQuery, - [URL_PARAM_KEY.flyout]: resolveFlyoutParams( - { index, alertId, expandableFlyoutDisabled }, - currentFlyoutParams - ), + [URL_PARAM_KEY.flyout]: resolveFlyoutParams({ index, alertId }, currentFlyoutParams), }); const url = `${ALERTS_PATH}?${urlParams.toString()}`; diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts b/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts index ac1d2a862b92c..4bbb386bc86dd 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts @@ -11,7 +11,6 @@ import { expandableFlyoutStateFromEventMeta } from '../../../flyout/document_det export interface ResolveFlyoutParamsConfig { index: string; alertId: string; - expandableFlyoutDisabled: boolean; } /** @@ -21,27 +20,14 @@ export interface ResolveFlyoutParamsConfig { * with Share Button on the Expandable Flyout */ export const resolveFlyoutParams = ( - { index, alertId, expandableFlyoutDisabled }: ResolveFlyoutParamsConfig, + { index, alertId }: ResolveFlyoutParamsConfig, currentParamsString: string | null ) => { - if (expandableFlyoutDisabled) { - const legacyFlyoutString = encode({ - panelView: 'eventDetail', - params: { - eventId: alertId, - indexName: index, - }, - }); - return legacyFlyoutString; - } - if (currentParamsString) { return currentParamsString; } - const modernFlyoutString = encode( + return encode( expandableFlyoutStateFromEventMeta({ index, eventId: alertId, scopeId: 'alerts-page' }) ); - - return modernFlyoutString; }; diff --git a/x-pack/plugins/security_solution/public/explore/users/containers/users/observed_details/index.tsx b/x-pack/plugins/security_solution/public/explore/users/containers/users/observed_details/index.tsx index d1148af03a41a..1d337e9116556 100644 --- a/x-pack/plugins/security_solution/public/explore/users/containers/users/observed_details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/containers/users/observed_details/index.tsx @@ -13,7 +13,6 @@ import { UsersQueries } from '../../../../../../common/search_strategy/security_ import type { UserItem } from '../../../../../../common/search_strategy/security_solution/users/common'; import { NOT_EVENT_KIND_ASSET_FILTER } from '../../../../../../common/search_strategy/security_solution/users/common'; import { useSearchStrategy } from '../../../../../common/containers/use_search_strategy'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; export const OBSERVED_USER_QUERY_ID = 'observedUsersDetailsQuery'; @@ -43,7 +42,6 @@ export const useObservedUserDetails = ({ skip = false, startDate, }: UseUserDetails): [boolean, UserDetailsArgs] => { - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { loading, result: response, @@ -81,9 +79,9 @@ export const useObservedUserDetails = ({ from: startDate, to: endDate, }, - filterQuery: !expandableFlyoutDisabled ? NOT_EVENT_KIND_ASSET_FILTER : undefined, + filterQuery: NOT_EVENT_KIND_ASSET_FILTER, }), - [endDate, indexNames, startDate, userName, expandableFlyoutDisabled] + [endDate, indexNames, startDate, userName] ); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx index 116cddf36f5f5..1921dfe190420 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx @@ -20,7 +20,6 @@ import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { useDispatch } from 'react-redux'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useKibana } from '../../../../common/lib/kibana'; import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/shared/constants/panel_keys'; import type { TimelineResultNote } from '../types'; @@ -29,7 +28,7 @@ import { MarkdownRenderer } from '../../../../common/components/markdown_editor' import { timelineActions, timelineSelectors } from '../../../store'; import { NOTE_CONTENT_CLASS_NAME } from '../../timeline/body/helpers'; import * as i18n from './translations'; -import { TimelineTabs, TimelineId } from '../../../../../common/types/timeline'; +import { TimelineId } from '../../../../../common/types/timeline'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../../sourcerer/containers'; @@ -51,53 +50,27 @@ const ToggleEventDetailsButtonComponent: React.FC eventId, timelineId, }) => { - const dispatch = useDispatch(); const { selectedPatterns } = useSourcererDataView(SourcererScopeName.timeline); const { telemetry } = useKibana().services; const { openFlyout } = useExpandableFlyoutApi(); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const handleClick = useCallback(() => { - const indexName = selectedPatterns.join(','); - - if (!expandableFlyoutDisabled) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventId, - indexName, - scopeId: timelineId, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: eventId, + indexName: selectedPatterns.join(','), + scopeId: timelineId, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: timelineId, - panel: 'right', - }); - } else { - dispatch( - timelineActions.toggleDetailPanel({ - panelView: 'eventDetail', - tabType: TimelineTabs.notes, - id: timelineId, - params: { - eventId, - indexName, - }, - }) - ); - } - }, [ - dispatch, - eventId, - expandableFlyoutDisabled, - openFlyout, - selectedPatterns, - telemetry, - timelineId, - ]); + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: timelineId, + panel: 'right', + }); + }, [eventId, openFlyout, selectedPatterns, telemetry, timelineId]); return ( { jest.mock('../../../../common/hooks/use_selector'); jest.mock('../../../store'); -const mockDispatch = jest.fn(); -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - return { - ...original, - useDispatch: () => mockDispatch, - }; -}); jest.mock('../../../../sourcerer/containers', () => { const mockSourcererReturn = { browserFields: {}, @@ -88,18 +79,6 @@ describe('useDetailPanel', () => { }); }); - test('should fire redux action to open event details panel', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderUseDetailPanel(); - await waitForNextUpdate(); - - result.current?.openEventDetailsPanel('123'); - - expect(mockDispatch).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - }); - }); - test('should show the details panel', async () => { mockGetExpandedDetail.mockImplementation(() => ({ [TimelineTabs.session]: { diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx index d66053c1128e4..4d76510c12b77 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx @@ -5,15 +5,12 @@ * 2.0. */ -import React, { useMemo, useCallback, useRef } from 'react'; -import { useDispatch } from 'react-redux'; +import React, { useMemo, useCallback } from 'react'; import type { EntityType } from '@kbn/timelines-plugin/common'; import { dataTableSelectors } from '@kbn/securitysolution-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useKibana } from '../../../../common/lib/kibana'; -import type { ExpandedDetailType } from '../../../../../common/types'; -import { getScopedActions, isInTableScope, isTimelineScope } from '../../../../helpers'; +import { isInTableScope, isTimelineScope } from '../../../../helpers'; import { timelineSelectors } from '../../../store'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import type { SourcererScopeName } from '../../../../sourcerer/store/model'; @@ -45,10 +42,8 @@ export const useDetailPanel = ({ }: UseDetailPanelConfig): UseDetailPanelReturn => { const { telemetry } = useKibana().services; const { browserFields, selectedPatterns, runtimeMappings } = useSourcererDataView(sourcererScope); - const dispatch = useDispatch(); const { openFlyout } = useExpandableFlyoutApi(); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const getScope = useMemo(() => { if (isTimelineScope(scopeId)) { @@ -62,8 +57,6 @@ export const useDetailPanel = ({ const expandedDetail = useDeepEqualSelector( (state) => ((getScope && getScope(state, scopeId)) ?? timelineDefaults)?.expandedDetail ); - const onPanelClose = useRef(() => {}); - const noopPanelClose = () => {}; const shouldShowDetailsPanel = useMemo(() => { if ( @@ -76,68 +69,34 @@ export const useDetailPanel = ({ } return false; }, [expandedDetail, tabType]); - const scopedActions = getScopedActions(scopeId); - - // We could just surface load details panel, but rather than have users be concerned - // of the config for a panel, they can just pass the base necessary values to a panel specific function - const loadDetailsPanel = useCallback( - (panelConfig?: ExpandedDetailType) => { - if (panelConfig && scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...panelConfig, - tabType, - id: scopeId, - }) - ); - } - }, - [scopedActions, scopeId, dispatch, tabType] - ); const openEventDetailsPanel = useCallback( (eventId?: string, onClose?: () => void) => { - if (!expandableFlyoutDisabled) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventId, - indexName: eventDetailsIndex, - scopeId, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: eventId, + indexName: eventDetailsIndex, + scopeId, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: scopeId, - panel: 'right', - }); - } else if (eventId) { - loadDetailsPanel({ - panelView: 'eventDetail', - params: { eventId, indexName: eventDetailsIndex }, - }); - onPanelClose.current = onClose ?? noopPanelClose; - } + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: scopeId, + panel: 'right', + }); }, - [expandableFlyoutDisabled, openFlyout, eventDetailsIndex, scopeId, telemetry, loadDetailsPanel] + [openFlyout, eventDetailsIndex, scopeId, telemetry] ); - const handleOnDetailsPanelClosed = useCallback(() => { - if (!expandableFlyoutDisabled) return; - if (onPanelClose.current) onPanelClose.current(); - if (scopedActions) { - dispatch(scopedActions.toggleDetailPanel({ tabType, id: scopeId })); - } - }, [expandableFlyoutDisabled, scopedActions, dispatch, tabType, scopeId]); - const DetailsPanel = useMemo( () => shouldShowDetailsPanel ? ( {}} isFlyoutView={isFlyoutView} runtimeMappings={runtimeMappings} tabType={tabType} @@ -147,7 +106,6 @@ export const useDetailPanel = ({ [ browserFields, entityType, - handleOnDetailsPanelClosed, isFlyoutView, runtimeMappings, shouldShowDetailsPanel, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx index 000837ff83500..479d4d0defc1f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx @@ -11,7 +11,6 @@ import React, { useCallback, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { isEventBuildingBlockType } from '@kbn/securitysolution-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { useKibana } from '../../../../../common/lib/kibana'; @@ -43,7 +42,6 @@ import { useGetMappedNonEcsValue } from '../data_driven_columns'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import type { ControlColumnProps, - ExpandedDetailType, SetEventsDeleted, SetEventsLoading, } from '../../../../../../common/types'; @@ -112,7 +110,6 @@ const StatefulEventComponent: React.FC = ({ const trGroupRef = useRef(null); const dispatch = useDispatch(); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { openFlyout } = useExpandableFlyoutApi(); // Store context in state rather than creating object in provider value={} to prevent re-renders caused by a new object being created @@ -206,51 +203,21 @@ const StatefulEventComponent: React.FC = ({ ); const handleOnEventDetailPanelOpened = useCallback(() => { - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'eventDetail', - params: { - eventId, - indexName, - refetch, - }, - }; - - if (!expandableFlyoutDisabled) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventId, - indexName, - scopeId: timelineId, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: eventId, + indexName, + scopeId: timelineId, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: timelineId, - panel: 'right', - }); - } else { - // opens the panel when clicking on the table row action - dispatch( - timelineActions.toggleDetailPanel({ - ...updatedExpandedDetail, - tabType, - id: timelineId, - }) - ); - } - }, [ - eventId, - indexName, - refetch, - expandableFlyoutDisabled, - openFlyout, - timelineId, - telemetry, - dispatch, - tabType, - ]); + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: timelineId, + panel: 'right', + }); + }, [eventId, indexName, openFlyout, timelineId, telemetry]); const setEventsLoading = useCallback( ({ eventIds, isLoading }) => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx index 0a9c53a88d689..d00ad83b9b556 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx @@ -11,17 +11,13 @@ import { waitFor } from '@testing-library/react'; import { HostName } from './host_name'; import { TestProviders } from '../../../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; -import { timelineActions } from '../../../../store'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; -import { dataTableActions, TableId } from '@kbn/securitysolution-data-table'; +import { TableId } from '@kbn/securitysolution-data-table'; const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); -jest.mock('../../../../../common/hooks/use_experimental_features'); - jest.mock('@kbn/expandable-flyout', () => { return { useExpandableFlyoutApi: () => ({ @@ -31,14 +27,6 @@ jest.mock('@kbn/expandable-flyout', () => { }; }); -jest.mock('react-redux', () => { - const origin = jest.requireActual('react-redux'); - return { - ...origin, - useDispatch: jest.fn().mockReturnValue(jest.fn()), - }; -}); - jest.mock('../../../../../common/lib/kibana/kibana_react', () => { return { useKibana: () => ({ @@ -57,28 +45,6 @@ jest.mock('../../../../../common/components/draggables', () => ({ DefaultDraggable: () =>
, })); -jest.mock('../../../../store', () => { - const original = jest.requireActual('../../../../store'); - return { - ...original, - timelineActions: { - ...original.timelineActions, - toggleDetailPanel: jest.fn(), - }, - }; -}); - -jest.mock('@kbn/securitysolution-data-table', () => { - const original = jest.requireActual('@kbn/securitysolution-data-table'); - return { - ...original, - dataTableActions: { - ...original.dataTableActions, - toggleDetailPanel: jest.fn(), - }, - }; -}); - describe('HostName', () => { afterEach(() => { jest.clearAllMocks(); @@ -129,8 +95,6 @@ describe('HostName', () => { wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); expect(mockOpenRightPanel).not.toHaveBeenCalled(); }); }); @@ -153,8 +117,6 @@ describe('HostName', () => { wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); expect(mockOpenRightPanel).not.toHaveBeenCalled(); }); }); @@ -177,82 +139,11 @@ describe('HostName', () => { wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(mockOpenRightPanel).not.toHaveBeenCalled(); - }); - }); - - test('should open old flyout on table', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return true; - }); - const context = { - enableHostDetailsFlyout: true, - enableIpDetailsFlyout: true, - timelineID: TableId.alertsOnAlertsPage, - tabType: TimelineTabs.query, - }; - const wrapper = mount( - - - - - - ); - - wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); - await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).toHaveBeenCalledWith({ - id: context.timelineID, - panelView: 'hostDetail', - params: { - hostName: props.value, - }, - tabType: context.tabType, - }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(mockOpenRightPanel).not.toHaveBeenCalled(); - }); - }); - - test('should open old flyout in timeline', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return true; - }); - const context = { - enableHostDetailsFlyout: true, - enableIpDetailsFlyout: true, - timelineID: TimelineId.active, - tabType: TimelineTabs.query, - }; - const wrapper = mount( - - - - - - ); - - wrapper.find('[data-test-subj="host-details-button"]').last().simulate('click'); - await waitFor(() => { - expect(timelineActions.toggleDetailPanel).toHaveBeenCalledWith({ - id: context.timelineID, - panelView: 'hostDetail', - params: { - hostName: props.value, - }, - tabType: context.tabType, - }); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); expect(mockOpenRightPanel).not.toHaveBeenCalled(); }); }); test('should open expandable flyout on table', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return false; - }); const context = { enableHostDetailsFlyout: true, enableIpDetailsFlyout: true, @@ -278,15 +169,10 @@ describe('HostName', () => { isDraggable: false, }, }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); }); }); test('should open expandable flyout in timeline', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return false; - }); const context = { enableHostDetailsFlyout: true, enableIpDetailsFlyout: true, @@ -312,8 +198,6 @@ describe('HostName', () => { isDraggable: false, }, }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx index 42c5344c7445c..d1a9c3a00bf37 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx @@ -7,16 +7,11 @@ import React, { useCallback, useContext, useMemo } from 'react'; import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; -import { useDispatch } from 'react-redux'; import { isString } from 'lodash/fp'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { HostPanelKey } from '../../../../../flyout/entity_details/host_right'; -import type { ExpandedDetailType } from '../../../../../../common/types'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import { getScopedActions } from '../../../../../helpers'; import { HostDetailsLink } from '../../../../../common/components/links'; -import type { TimelineTabs } from '../../../../../../common/types/timeline'; import { DefaultDraggable } from '../../../../../common/components/draggables'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; import { TruncatableText } from '../../../../../common/components/truncatable_text'; @@ -48,10 +43,8 @@ const HostNameComponent: React.FC = ({ title, value, }) => { - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { openRightPanel } = useExpandableFlyoutApi(); - const dispatch = useDispatch(); const eventContext = useContext(StatefulEventContext); const hostName = `${value}`; const isInTimelineContext = @@ -69,48 +62,19 @@ const HostNameComponent: React.FC = ({ return; } - const { timelineID, tabType } = eventContext; + const { timelineID } = eventContext; - if (!expandableFlyoutDisabled) { - openRightPanel({ - id: HostPanelKey, - params: { - hostName, - contextID: contextId, - scopeId: timelineID, - isDraggable, - }, - }); - } else { - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'hostDetail', - params: { - hostName, - }, - }; - const scopedActions = getScopedActions(timelineID); - if (scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: timelineID, - tabType: tabType as TimelineTabs, - }) - ); - } - } + openRightPanel({ + id: HostPanelKey, + params: { + hostName, + contextID: contextId, + scopeId: timelineID, + isDraggable, + }, + }); }, - [ - contextId, - dispatch, - eventContext, - expandableFlyoutDisabled, - hostName, - isDraggable, - isInTimelineContext, - onClick, - openRightPanel, - ] + [contextId, eventContext, hostName, isDraggable, isInTimelineContext, onClick, openRightPanel] ); // The below is explicitly defined this way as the onClick takes precedence when it and the href are both defined diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx index 16f881fe90130..471d43dcf8462 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx @@ -10,18 +10,14 @@ import { waitFor } from '@testing-library/react'; import { TestProviders } from '../../../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; -import { timelineActions } from '../../../../store'; import { UserName } from './user_name'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; -import { dataTableActions, TableId } from '@kbn/securitysolution-data-table'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; +import { TableId } from '@kbn/securitysolution-data-table'; const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); -jest.mock('../../../../../common/hooks/use_experimental_features'); - jest.mock('@kbn/expandable-flyout', () => { return { useExpandableFlyoutApi: () => ({ @@ -31,14 +27,6 @@ jest.mock('@kbn/expandable-flyout', () => { }; }); -jest.mock('react-redux', () => { - const origin = jest.requireActual('react-redux'); - return { - ...origin, - useDispatch: jest.fn().mockReturnValue(jest.fn()), - }; -}); - jest.mock('../../../../../common/lib/kibana/kibana_react', () => { return { useKibana: () => ({ @@ -57,28 +45,6 @@ jest.mock('../../../../../common/components/draggables', () => ({ DefaultDraggable: () =>
, })); -jest.mock('../../../../store', () => { - const original = jest.requireActual('../../../../store'); - return { - ...original, - timelineActions: { - ...original.timelineActions, - toggleDetailPanel: jest.fn(), - }, - }; -}); - -jest.mock('@kbn/securitysolution-data-table', () => { - const original = jest.requireActual('@kbn/securitysolution-data-table'); - return { - ...original, - dataTableActions: { - ...original.dataTableActions, - toggleDetailPanel: jest.fn(), - }, - }; -}); - describe('UserName', () => { afterEach(() => { jest.clearAllMocks(); @@ -127,8 +93,6 @@ describe('UserName', () => { wrapper.find('[data-test-subj="users-link-anchor"]').last().simulate('click'); await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); expect(mockOpenRightPanel).not.toHaveBeenCalled(); }); }); @@ -151,82 +115,11 @@ describe('UserName', () => { wrapper.find('[data-test-subj="users-link-anchor"]').last().simulate('click'); await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(mockOpenRightPanel).not.toHaveBeenCalled(); - }); - }); - - test('should open old flyout on table', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return true; - }); - const context = { - enableHostDetailsFlyout: true, - enableIpDetailsFlyout: true, - timelineID: TableId.alertsOnAlertsPage, - tabType: TimelineTabs.query, - }; - const wrapper = mount( - - - - - - ); - - wrapper.find('[data-test-subj="users-link-anchor"]').last().simulate('click'); - await waitFor(() => { - expect(dataTableActions.toggleDetailPanel).toHaveBeenCalledWith({ - id: context.timelineID, - panelView: 'userDetail', - params: { - userName: props.value, - }, - tabType: context.tabType, - }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(mockOpenRightPanel).not.toHaveBeenCalled(); - }); - }); - - test('should open old flyout in timeline', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return true; - }); - const context = { - enableHostDetailsFlyout: true, - enableIpDetailsFlyout: true, - timelineID: TimelineId.active, - tabType: TimelineTabs.query, - }; - const wrapper = mount( - - - - - - ); - - wrapper.find('[data-test-subj="users-link-anchor"]').last().simulate('click'); - await waitFor(() => { - expect(timelineActions.toggleDetailPanel).toHaveBeenCalledWith({ - id: context.timelineID, - panelView: 'userDetail', - params: { - userName: props.value, - }, - tabType: context.tabType, - }); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); expect(mockOpenRightPanel).not.toHaveBeenCalled(); }); }); test('should open expandable flyout on table', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return false; - }); const context = { enableHostDetailsFlyout: true, enableIpDetailsFlyout: true, @@ -252,15 +145,10 @@ describe('UserName', () => { isDraggable: false, }, }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); }); }); test('should open expandable flyout in timeline', async () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation((feature: string) => { - if (feature === 'expandableFlyoutDisabled') return false; - }); const context = { enableHostDetailsFlyout: true, enableIpDetailsFlyout: true, @@ -286,8 +174,6 @@ describe('UserName', () => { isDraggable: false, }, }); - expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); - expect(dataTableActions.toggleDetailPanel).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx index 78d9ad9c3bdfd..48ce6255725d3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx @@ -7,15 +7,10 @@ import React, { useCallback, useContext, useMemo } from 'react'; import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; -import { useDispatch } from 'react-redux'; import { isString } from 'lodash/fp'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { UserPanelKey } from '../../../../../flyout/entity_details/user_right'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import type { ExpandedDetailType } from '../../../../../../common/types'; -import { getScopedActions } from '../../../../../helpers'; -import type { TimelineTabs } from '../../../../../../common/types/timeline'; import { DefaultDraggable } from '../../../../../common/components/draggables'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; import { UserDetailsLink } from '../../../../../common/components/links'; @@ -48,9 +43,7 @@ const UserNameComponent: React.FC = ({ title, value, }) => { - const dispatch = useDispatch(); const eventContext = useContext(StatefulEventContext); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const userName = `${value}`; const isInTimelineContext = userName && eventContext?.timelineID; const { openRightPanel } = useExpandableFlyoutApi(); @@ -67,48 +60,19 @@ const UserNameComponent: React.FC = ({ return; } - const { timelineID, tabType } = eventContext; + const { timelineID } = eventContext; - if (!expandableFlyoutDisabled) { - openRightPanel({ - id: UserPanelKey, - params: { - userName, - contextID: contextId, - scopeId: timelineID, - isDraggable, - }, - }); - } else { - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'userDetail', - params: { - userName, - }, - }; - const scopedActions = getScopedActions(timelineID); - if (scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: timelineID, - tabType: tabType as TimelineTabs, - }) - ); - } - } + openRightPanel({ + id: UserPanelKey, + params: { + userName, + contextID: contextId, + scopeId: timelineID, + isDraggable, + }, + }); }, - [ - contextId, - dispatch, - eventContext, - expandableFlyoutDisabled, - isDraggable, - isInTimelineContext, - onClick, - openRightPanel, - userName, - ] + [contextId, eventContext, isDraggable, isInTimelineContext, onClick, openRightPanel, userName] ); // The below is explicitly defined this way as the onClick takes precedence when it and the href are both defined diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index 7492a00a4a2de..60ae1682241c8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -145,7 +145,6 @@ export const EqlTabContentComponent: React.FC = ({ timerangeKind, }); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' @@ -168,7 +167,7 @@ export const EqlTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && !expandableFlyoutDisabled && securitySolutionNotesEnabled) { + if (eventId && securitySolutionNotesEnabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -205,7 +204,6 @@ export const EqlTabContentComponent: React.FC = ({ } }, [ - expandableFlyoutDisabled, openFlyout, securitySolutionNotesEnabled, selectedPatterns, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx index 76db7bcde9afe..5b29c180ab9e3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx @@ -181,7 +181,6 @@ export const PinnedTabContentComponent: React.FC = ({ timerangeKind: undefined, }); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' @@ -204,7 +203,7 @@ export const PinnedTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && !expandableFlyoutDisabled && securitySolutionNotesEnabled) { + if (eventId && securitySolutionNotesEnabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -241,7 +240,6 @@ export const PinnedTabContentComponent: React.FC = ({ } }, [ - expandableFlyoutDisabled, openFlyout, securitySolutionNotesEnabled, selectedPatterns, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx index 017031e1ffba6..73c7c91708c6d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx @@ -211,7 +211,6 @@ export const QueryTabContentComponent: React.FC = ({ timerangeKind, }); - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesEnabled' @@ -234,7 +233,7 @@ export const QueryTabContentComponent: React.FC = ({ const onToggleShowNotes = useCallback( (eventId?: string) => { const indexName = selectedPatterns.join(','); - if (eventId && !expandableFlyoutDisabled && securitySolutionNotesEnabled) { + if (eventId && securitySolutionNotesEnabled) { openFlyout({ right: { id: DocumentDetailsRightPanelKey, @@ -271,7 +270,6 @@ export const QueryTabContentComponent: React.FC = ({ } }, [ - expandableFlyoutDisabled, openFlyout, securitySolutionNotesEnabled, selectedPatterns, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx index 9a712a8fbeaf1..20d38f9d047cc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx @@ -776,332 +776,148 @@ describe('query tab with unified timeline', () => { describe('Leading actions - notes', () => { describe('securitySolutionNotesEnabled = true', () => { - describe('expandableFlyoutDisabled = false', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( - jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'unifiedComponentsInTimelineEnabled') { - return true; - } - if (feature === 'securitySolutionNotesEnabled') { - return true; - } - return allowedExperimentalValues[feature]; - }) - ); - }); - - it( - 'should have the notification dot & correct tooltip', - async () => { - renderTestComponents(); - - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - - expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); - - fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); - expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( - '1 Note available. Click to view it & add more.' - ); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - it( - 'should be able to add notes through expandable flyout', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); - - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(mockOpenFlyout).toHaveBeenCalled(); - }); - }, - SPECIAL_TEST_TIMEOUT + beforeEach(() => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( + jest.fn((feature: keyof ExperimentalFeatures) => { + if (feature === 'unifiedComponentsInTimelineEnabled') { + return true; + } + if (feature === 'securitySolutionNotesEnabled') { + return true; + } + return allowedExperimentalValues[feature]; + }) ); }); - describe('expandableFlyoutDisabled = true', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( - jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'unifiedComponentsInTimelineEnabled') { - return true; - } - if (feature === 'expandableFlyoutDisabled') { - return true; - } - if (feature === 'securitySolutionNotesEnabled') { - return true; - } - return allowedExperimentalValues[feature]; - }) - ); - }); - - it( - 'should have the notification dot & correct tooltip', - async () => { - renderTestComponents(); - - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - - expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); - - fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); - expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( - '1 Note available. Click to view it & add more.' - ); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - it( - 'should be able to add notes using EuiFlyout', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); - - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); - }, - SPECIAL_TEST_TIMEOUT - ); + it( + 'should have the notification dot & correct tooltip', + async () => { + renderTestComponents(); - it( - 'should be cancel adding notes', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); + expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); + expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); + expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); + fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); - userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), 'Test Note 1'); + await waitFor(() => { + expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); + expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( + '1 Note available. Click to view it & add more.' + ); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + it( + 'should be able to add notes through expandable flyout', + async () => { + renderTestComponents(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - expect(screen.getByTestId('cancel')).not.toBeDisabled(); + await waitFor(() => { + expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); + }); - fireEvent.click(screen.getByTestId('cancel')); + fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - await waitFor(() => { - expect(screen.queryByTestId('add-note-container')).not.toBeInTheDocument(); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - }); + await waitFor(() => { + expect(mockOpenFlyout).toHaveBeenCalled(); + }); + }, + SPECIAL_TEST_TIMEOUT + ); }); describe('securitySolutionNotesEnabled = false', () => { - describe('expandableFlyoutDisabled = false', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( - jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'unifiedComponentsInTimelineEnabled') { - return true; - } - if (feature === 'securitySolutionNotesEnabled') { - return false; - } - return allowedExperimentalValues[feature]; - }) - ); - }); - - it( - 'should have the notification dot & correct tooltip', - async () => { - renderTestComponents(); - - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - - expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); - - fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); - expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( - '1 Note available. Click to view it & add more.' - ); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - it( - 'should be able to add notes using EuiFlyout', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); - - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - - it( - 'should be cancel adding notes', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); - - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); - - userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), 'Test Note 1'); - - expect(screen.getByTestId('cancel')).not.toBeDisabled(); - - fireEvent.click(screen.getByTestId('cancel')); - - await waitFor(() => { - expect(screen.queryByTestId('add-note-container')).not.toBeInTheDocument(); - }); - }, - SPECIAL_TEST_TIMEOUT + beforeEach(() => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( + jest.fn((feature: keyof ExperimentalFeatures) => { + if (feature === 'unifiedComponentsInTimelineEnabled') { + return true; + } + if (feature === 'securitySolutionNotesEnabled') { + return false; + } + return allowedExperimentalValues[feature]; + }) ); }); - describe('expandableFlyoutDisabled = true', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockImplementation( - jest.fn((feature: keyof ExperimentalFeatures) => { - if (feature === 'unifiedComponentsInTimelineEnabled') { - return true; - } - if (feature === 'expandableFlyoutDisabled') { - return true; - } - if (feature === 'securitySolutionNotesEnabled') { - return true; - } - return allowedExperimentalValues[feature]; - }) - ); - }); - - it( - 'should have the notification dot & correct tooltip', - async () => { - renderTestComponents(); + it( + 'should have the notification dot & correct tooltip', + async () => { + renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); + expect(screen.getAllByTestId('timeline-notes-button-small')).toHaveLength(1); + expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); + expect(screen.getByTestId('timeline-notes-notification-dot')).toBeVisible(); - fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); + fireEvent.mouseOver(screen.getByTestId('timeline-notes-button-small')); - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); - expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( - '1 Note available. Click to view it & add more.' - ); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - it( - 'should be able to add notes using EuiFlyout', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + await waitFor(() => { + expect(screen.getByTestId('timeline-notes-tool-tip')).toBeVisible(); + expect(screen.getByTestId('timeline-notes-tool-tip')).toHaveTextContent( + '1 Note available. Click to view it & add more.' + ); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + it( + 'should be able to add notes using EuiFlyout', + async () => { + renderTestComponents(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); + await waitFor(() => { + expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); + }); - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); + fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); - }, - SPECIAL_TEST_TIMEOUT - ); + await waitFor(() => { + expect(screen.getByTestId('add-note-container')).toBeVisible(); + }); + }, + SPECIAL_TEST_TIMEOUT + ); - it( - 'should be cancel adding notes', - async () => { - renderTestComponents(); - expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + it( + 'should be cancel adding notes', + async () => { + renderTestComponents(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); - await waitFor(() => { - expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); - }); + await waitFor(() => { + expect(screen.getByTestId('timeline-notes-button-small')).not.toBeDisabled(); + }); - fireEvent.click(screen.getByTestId('timeline-notes-button-small')); + fireEvent.click(screen.getByTestId('timeline-notes-button-small')); - await waitFor(() => { - expect(screen.getByTestId('add-note-container')).toBeVisible(); - }); + await waitFor(() => { + expect(screen.getByTestId('add-note-container')).toBeVisible(); + }); - userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), 'Test Note 1'); + userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), 'Test Note 1'); - expect(screen.getByTestId('cancel')).not.toBeDisabled(); + expect(screen.getByTestId('cancel')).not.toBeDisabled(); - fireEvent.click(screen.getByTestId('cancel')); + fireEvent.click(screen.getByTestId('cancel')); - await waitFor(() => { - expect(screen.queryByTestId('add-note-container')).not.toBeInTheDocument(); - }); - }, - SPECIAL_TEST_TIMEOUT - ); - }); + await waitFor(() => { + expect(screen.queryByTestId('add-note-container')).not.toBeInTheDocument(); + }); + }, + SPECIAL_TEST_TIMEOUT + ); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx index 52cc643cbf2e4..b9807e08572b4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx @@ -36,7 +36,6 @@ const onChangePageMock = jest.fn(); const openFlyoutMock = jest.fn(); const closeFlyoutMock = jest.fn(); -const isExpandableFlyoutDisabled = false; jest.mock('../hooks/use_unified_timeline_expandable_flyout'); @@ -99,7 +98,6 @@ describe('unified data table', () => { beforeEach(() => { (useSourcererDataView as jest.Mock).mockReturnValue(mockSourcererScope); (useUnifiedTableExpandableFlyout as jest.Mock).mockReturnValue({ - isExpandableFlyoutDisabled, openFlyout: openFlyoutMock, closeFlyout: closeFlyoutMock, }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx index b1467a4afdf4d..e4433a0fd56a1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx @@ -19,7 +19,7 @@ import { RowRendererCount } from '../../../../../../common/api/timeline'; import { EmptyComponent } from '../../../../../common/lib/cell_actions/helpers'; import { withDataView } from '../../../../../common/components/with_data_view'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import type { ExpandedDetailTimeline, ExpandedDetailType } from '../../../../../../common/types'; +import type { ExpandedDetailTimeline } from '../../../../../../common/types'; import type { TimelineItem } from '../../../../../../common/search_strategy'; import { useKibana } from '../../../../../common/lib/kibana'; import type { @@ -29,12 +29,7 @@ import type { ToggleDetailPanel, TimelineTabs, } from '../../../../../../common/types/timeline'; -import { TimelineId } from '../../../../../../common/types/timeline'; import type { State, inputsModel } from '../../../../../common/store'; -import { SourcererScopeName } from '../../../../../sourcerer/store/model'; -import { useSourcererDataView } from '../../../../../sourcerer/containers'; -import { activeTimeline } from '../../../../containers/active_timeline_context'; -import { DetailsPanel } from '../../../side_panel'; import { SecurityCellActionsTrigger } from '../../../../../app/actions/constants'; import { getFormattedFields } from '../../body/renderers/formatted_field_udt'; import ToolbarAdditionalControls from './toolbar_additional_controls'; @@ -147,13 +142,9 @@ export const TimelineDataTableComponent: React.FC = memo( setExpandedDoc((prev) => (!prev ? prev : undefined)); }, []); - const { openFlyout, closeFlyout, isExpandableFlyoutDisabled } = useUnifiedTableExpandableFlyout( - { - onClose: onCloseExpandableFlyout, - } - ); - - const { browserFields, runtimeMappings } = useSourcererDataView(SourcererScopeName.timeline); + const { openFlyout, closeFlyout } = useUnifiedTableExpandableFlyout({ + onClose: onCloseExpandableFlyout, + }); const showTimeCol = useMemo(() => !!dataView && !!dataView.timeFieldName, [dataView]); @@ -168,57 +159,24 @@ export const TimelineDataTableComponent: React.FC = memo( const handleOnEventDetailPanelOpened = useCallback( (eventData: DataTableRecord & TimelineItem) => { - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'eventDetail', - params: { - eventId: eventData._id, - indexName: eventData.ecs._index ?? '', // TODO: fix type error - refetch, - }, - }; - - if (!isExpandableFlyoutDisabled) { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventData._id, - indexName: eventData.ecs._index ?? '', - scopeId: timelineId, - }, + openFlyout({ + right: { + id: DocumentDetailsRightPanelKey, + params: { + id: eventData._id, + indexName: eventData.ecs._index ?? '', + scopeId: timelineId, }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: timelineId, - panel: 'right', - }); - } else { - dispatch( - timelineActions.toggleDetailPanel({ - ...updatedExpandedDetail, - tabType: activeTab, - id: timelineId, - }) - ); - } - - activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail }); + }, + }); + telemetry.reportDetailsFlyoutOpened({ + location: timelineId, + panel: 'right', + }); }, - [refetch, isExpandableFlyoutDisabled, openFlyout, timelineId, telemetry, dispatch, activeTab] + [openFlyout, timelineId, telemetry] ); - const onTimelineLegacyFlyoutClose = useCallback(() => { - if ( - expandedDetail[activeTab]?.panelView && - timelineId === TimelineId.active && - showExpandedDetails - ) { - activeTimeline.toggleExpandedDetail({}); - } - setExpandedDoc(undefined); - onEventClosed({ tabType: activeTab, id: timelineId }); - }, [expandedDetail, activeTab, timelineId, showExpandedDetails, onEventClosed]); - const onSetExpandedDoc = useCallback( (newDoc?: DataTableRecord) => { if (newDoc) { @@ -228,20 +186,10 @@ export const TimelineDataTableComponent: React.FC = memo( handleOnEventDetailPanelOpened(timelineDoc); } } else { - if (!isExpandableFlyoutDisabled) { - closeFlyout(); - return; - } - onTimelineLegacyFlyoutClose(); + closeFlyout(); } }, - [ - tableRows, - handleOnEventDetailPanelOpened, - onTimelineLegacyFlyoutClose, - closeFlyout, - isExpandableFlyoutDisabled, - ] + [tableRows, handleOnEventDetailPanelOpened, closeFlyout] ); const onColumnResize = useCallback( @@ -468,16 +416,6 @@ export const TimelineDataTableComponent: React.FC = memo( externalControlColumns={leadingControlColumns} cellContext={cellContext} /> - {showExpandedDetails && isExpandableFlyoutDisabled && ( - - )} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx index 54e227c79e86b..a1b89511de6c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx @@ -5,14 +5,12 @@ * 2.0. */ -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { renderHook } from '@testing-library/react-hooks'; import { useUnifiedTableExpandableFlyout } from './use_unified_timeline_expandable_flyout'; import { useLocation } from 'react-router-dom'; import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -jest.mock('../../../../../common/hooks/use_experimental_features'); jest.mock('@kbn/kibana-react-plugin/public'); jest.mock('react-router-dom', () => { return { @@ -24,60 +22,20 @@ jest.mock('@kbn/expandable-flyout'); const onFlyoutCloseMock = jest.fn(); describe('useUnifiedTimelineExpandableFlyout', () => { - it('should disable expandable flyout when expandableFlyoutDisabled flag is true', () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); - (useLocation as jest.Mock).mockReturnValue({ - search: `?${URL_PARAM_KEY.timelineFlyout}=(test:value)`, - }); - (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ - openFlyout: jest.fn(), - closeFlyout: jest.fn(), - }); - - const { result } = renderHook(() => - useUnifiedTableExpandableFlyout({ - onClose: onFlyoutCloseMock, - }) - ); - - expect(result.current.isExpandableFlyoutDisabled).toBe(true); - }); - describe('when expandable flyout is enabled', () => { beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should mark flyout as closed when location is empty', () => { - (useLocation as jest.Mock).mockReturnValue({ - search: '', + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ + openFlyout: jest.fn(), + closeFlyout: jest.fn(), }); - const { result } = renderHook(() => - useUnifiedTableExpandableFlyout({ - onClose: onFlyoutCloseMock, - }) - ); - - expect(result.current.isExpandableFlyoutDisabled).toBe(false); - }); - - it('should mark flyout as open when location has `timelineFlyout`', () => { (useLocation as jest.Mock).mockReturnValue({ search: `${URL_PARAM_KEY.timelineFlyout}=(test:value)`, }); + }); - const { result } = renderHook(() => - useUnifiedTableExpandableFlyout({ - onClose: onFlyoutCloseMock, - }) - ); - - expect(result.current.isExpandableFlyoutDisabled).toBe(false); + afterEach(() => { + jest.clearAllMocks(); }); it('should mark flyout as close when location has empty `timelineFlyout`', () => { @@ -87,8 +45,6 @@ describe('useUnifiedTimelineExpandableFlyout', () => { }) ); - expect(result.current.isExpandableFlyoutDisabled).toBe(false); - (useLocation as jest.Mock).mockReturnValue({ search: `${URL_PARAM_KEY.timelineFlyout}=()`, }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx index 83050110eb090..fb28b6f44f367 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx @@ -8,7 +8,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { useLocation } from 'react-router-dom'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; const EMPTY_TIMELINE_FLYOUT_SEARCH_PARAMS = '()'; @@ -20,8 +19,6 @@ interface UseUnifiedTableExpandableFlyoutArgs { export const useUnifiedTableExpandableFlyout = ({ onClose, }: UseUnifiedTableExpandableFlyoutArgs) => { - const expandableFlyoutDisabled = useIsExperimentalFeatureEnabled('expandableFlyoutDisabled'); - const location = useLocation(); const { openFlyout, closeFlyout } = useExpandableFlyoutApi(); @@ -33,7 +30,7 @@ export const useUnifiedTableExpandableFlyout = ({ const isFlyoutOpen = useMemo(() => { /** - * Currently, if new expanable flyout is closed, there is not way for + * Currently, if new expandable flyout is closed, there is no way for * consumer to trigger an effect `onClose` of flyout. So, we are using * this hack to know if flyout is open or not. * @@ -71,6 +68,5 @@ export const useUnifiedTableExpandableFlyout = ({ isTimelineExpandableFlyoutOpen, openFlyout, closeFlyout: closeFlyoutWithEffect, - isExpandableFlyoutDisabled: expandableFlyoutDisabled, }; }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts index 813560274fcee..8a1be034a444f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts @@ -33,109 +33,95 @@ import { mockRiskEngineEnabled } from '../../tasks/entity_analytics'; const CURRENT_HOST_RISK_LEVEL = 'Current host risk level'; const ORIGINAL_HOST_RISK_LEVEL = 'Original host risk level'; -describe( - 'Enrichment', - { - tags: ['@ess'], - env: { - ftrConfig: { - kbnServerArgs: [ - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'expandableFlyoutDisabled', - ])}`, - ], - }, - }, - }, - () => { - before(() => { - cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); - cy.task('esArchiverUnload', { archiveName: 'risk_scores_new_updated' }); - cy.task('esArchiverLoad', { archiveName: 'risk_users' }); - }); +// this whole suite is failing on main +describe.skip('Enrichment', { tags: ['@ess'] }, () => { + before(() => { + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new_updated' }); + cy.task('esArchiverLoad', { archiveName: 'risk_users' }); + }); - after(() => { - cy.task('esArchiverUnload', { archiveName: 'risk_users' }); - }); + after(() => { + cy.task('esArchiverUnload', { archiveName: 'risk_users' }); + }); - describe('Custom query rule', () => { - // FLAKY: https://github.com/elastic/kibana/issues/176965 - describe.skip('from legacy risk scores', () => { - beforeEach(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); - deleteAlertsAndRules(); - createRule(getNewRule({ rule_id: 'rule1' })); - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - }); + describe('Custom query rule', () => { + // FLAKY: https://github.com/elastic/kibana/issues/176965 + describe.skip('from legacy risk scores', () => { + beforeEach(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'rule1' })); + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); - afterEach(() => { - cy.task('esArchiverUnload', { archiveName: 'risk_hosts' }); - cy.task('esArchiverUnload', { archiveName: 'risk_hosts_updated' }); - }); + afterEach(() => { + cy.task('esArchiverUnload', { archiveName: 'risk_hosts' }); + cy.task('esArchiverUnload', { archiveName: 'risk_hosts_updated' }); + }); - it('Should has enrichment fields from legacy risk', function () { - cy.get(HOST_RISK_HEADER_COLUMN).contains('Host Risk Level'); - cy.get(USER_RISK_HEADER_COLUMN).contains('User Risk Level'); - scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); - cy.get(HOST_RISK_COLUMN).contains('Low'); - scrollAlertTableColumnIntoView(USER_RISK_COLUMN); - cy.get(USER_RISK_COLUMN).contains('Low'); - scrollAlertTableColumnIntoView(ACTION_COLUMN); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Low'); - cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_LEVEL); - cy.get(ENRICHED_DATA_ROW).contains('Critical').should('not.exist'); - cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL).should('not.exist'); + it('Should has enrichment fields from legacy risk', function () { + cy.get(HOST_RISK_HEADER_COLUMN).contains('Host Risk Level'); + cy.get(USER_RISK_HEADER_COLUMN).contains('User Risk Level'); + scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); + cy.get(HOST_RISK_COLUMN).contains('Low'); + scrollAlertTableColumnIntoView(USER_RISK_COLUMN); + cy.get(USER_RISK_COLUMN).contains('Low'); + scrollAlertTableColumnIntoView(ACTION_COLUMN); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Low'); + cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_LEVEL); + cy.get(ENRICHED_DATA_ROW).contains('Critical').should('not.exist'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL).should('not.exist'); - closeAlertFlyout(); - cy.task('esArchiverUnload', { archiveName: 'risk_hosts' }); - cy.task('esArchiverLoad', { archiveName: 'risk_hosts_updated' }); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Critical'); - cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL); - }); + closeAlertFlyout(); + cy.task('esArchiverUnload', { archiveName: 'risk_hosts' }); + cy.task('esArchiverLoad', { archiveName: 'risk_hosts_updated' }); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Critical'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL); }); + }); - describe('from new risk scores', () => { - beforeEach(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); - deleteAlertsAndRules(); - createRule(getNewRule({ rule_id: 'rule1' })); - login(); - mockRiskEngineEnabled(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - }); + describe('from new risk scores', () => { + beforeEach(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'rule1' })); + login(); + mockRiskEngineEnabled(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); - afterEach(() => { - cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); - cy.task('esArchiverUnload', { archiveName: 'risk_scores_new_updated' }); - }); + afterEach(() => { + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new_updated' }); + }); - it('Should has enrichment fields from legacy risk', function () { - cy.get(HOST_RISK_HEADER_COLUMN).contains('Host Risk Level'); - cy.get(USER_RISK_HEADER_COLUMN).contains('User Risk Level'); - scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); - cy.get(HOST_RISK_COLUMN).contains('Critical'); - scrollAlertTableColumnIntoView(USER_RISK_COLUMN); - cy.get(USER_RISK_COLUMN).contains('High'); - scrollAlertTableColumnIntoView(ACTION_COLUMN); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Critical'); - cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_LEVEL); - cy.get(ENRICHED_DATA_ROW).contains('Low').should('not.exist'); - cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL).should('not.exist'); + it('Should has enrichment fields from legacy risk', function () { + cy.get(HOST_RISK_HEADER_COLUMN).contains('Host Risk Level'); + cy.get(USER_RISK_HEADER_COLUMN).contains('User Risk Level'); + scrollAlertTableColumnIntoView(HOST_RISK_COLUMN); + cy.get(HOST_RISK_COLUMN).contains('Critical'); + scrollAlertTableColumnIntoView(USER_RISK_COLUMN); + cy.get(USER_RISK_COLUMN).contains('High'); + scrollAlertTableColumnIntoView(ACTION_COLUMN); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Critical'); + cy.get(ENRICHED_DATA_ROW).contains(CURRENT_HOST_RISK_LEVEL); + cy.get(ENRICHED_DATA_ROW).contains('Low').should('not.exist'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL).should('not.exist'); - closeAlertFlyout(); - cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); - cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_updated' }); - expandFirstAlert(); - cy.get(ENRICHED_DATA_ROW).contains('Low'); - cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL); - }); + closeAlertFlyout(); + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_updated' }); + expandFirstAlert(); + cy.get(ENRICHED_DATA_ROW).contains('Low'); + cy.get(ENRICHED_DATA_ROW).contains(ORIGINAL_HOST_RISK_LEVEL); }); }); - } -); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts deleted file mode 100644 index b9655de8eab03..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 { - ALERT_FLYOUT, - CELL_TEXT, - COPY_ALERT_FLYOUT_LINK, - JSON_TEXT, - OVERVIEW_RULE, - SUMMARY_VIEW, - TABLE_CONTAINER, - TABLE_ROWS, -} from '../../../screens/alerts_details'; -import { closeAlertFlyout, expandFirstAlert } from '../../../tasks/alerts'; -import { - changeAlertStatusTo, - filterBy, - openJsonView, - openTable, -} from '../../../tasks/alerts_details'; -import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; -import { login } from '../../../tasks/login'; -import { visit, visitWithTimeRange } from '../../../tasks/navigation'; -import { getNewRule, getUnmappedRule } from '../../../objects/rule'; -import { ALERTS_URL } from '../../../urls/navigation'; -import { tablePageSelector } from '../../../screens/table_pagination'; -import { ALERTS_TABLE_COUNT } from '../../../screens/timeline'; -import { ALERT_SUMMARY_SEVERITY_DONUT_CHART } from '../../../screens/alerts'; -import { - visitRuleDetailsPage, - waitForPageToBeLoaded as waitForRuleDetailsPageToBeLoaded, -} from '../../../tasks/rule_details'; - -// this functionality is now not used anymore (though still accessible if customers turn the `expandableFlyoutDisabled` feature flag on -// the code will be removed entirely for `8.16 (see https://github.com/elastic/security-team/issues/7462) -describe.skip('Alert details flyout', { tags: ['@ess', '@serverless'] }, () => { - describe('Basic functions', () => { - beforeEach(() => { - deleteAlertsAndRules(); - createRule(getNewRule()); - login(); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlert(); - }); - - it('should update the table when status of the alert is updated', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - cy.get(ALERTS_TABLE_COUNT).should('have.text', '1 alert'); - cy.get(ALERT_SUMMARY_SEVERITY_DONUT_CHART).should('contain.text', '1alert'); - expandFirstAlert(); - changeAlertStatusTo('acknowledged'); - cy.get(ALERTS_TABLE_COUNT).should('have.text', '1 alert'); - cy.get(ALERT_SUMMARY_SEVERITY_DONUT_CHART).should('contain.text', '1alert'); - }); - }); - - describe('With unmapped fields', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'unmapped_fields' }); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - createRule({ ...getUnmappedRule(), investigation_fields: { field_names: ['event.kind'] } }); - login(); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlert(); - }); - - after(() => { - cy.task('esArchiverUnload', { archiveName: 'unmapped_fields' }); - }); - - it.skip('should display user and system defined highlighted fields', () => { - cy.get(SUMMARY_VIEW) - .should('be.visible') - .and('contain.text', 'event.kind') - .and('contain.text', 'Rule type'); - }); - - it('should display the unmapped field on the JSON view', () => { - const expectedUnmappedValue = 'This is the unmapped field'; - - openJsonView(); - - cy.get(JSON_TEXT).then((x) => { - const parsed = JSON.parse(x.text()); - expect(parsed.fields.unmapped[0]).to.equal(expectedUnmappedValue); - }); - }); - - it('should displays the unmapped field on the table', () => { - const expectedUnmappedField = { - field: 'unmapped', - text: 'This is the unmapped field', - }; - - openTable(); - cy.get(ALERT_FLYOUT).find(tablePageSelector(6)).click({ force: true }); - cy.get(ALERT_FLYOUT) - .find(TABLE_ROWS) - .last() - .within(() => { - cy.get(CELL_TEXT).should('contain', expectedUnmappedField.field); - cy.get(CELL_TEXT).should('contain', expectedUnmappedField.text); - }); - }); - - // This test makes sure that the table does not overflow horizontally - it('table should not scroll horizontally', () => { - openTable(); - - cy.get(ALERT_FLYOUT) - .find(TABLE_CONTAINER) - .within(($tableContainer) => { - expect($tableContainer[0].scrollLeft).to.equal(0); - - // Due to the introduction of pagination on the table, a slight horizontal overflow has been introduced. - // scroll ignores the `overflow-x:hidden` attribute and will still scroll the element if there is a hidden overflow - // Updated the below to < 5 to account for this and keep a test to make sure it doesn't grow - $tableContainer[0].scroll({ left: 1000 }); - - expect($tableContainer[0].scrollLeft).to.be.lessThan(5); - }); - }); - }); - - describe('Url state management', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'query_alert', useCreate: true, docsOnly: true }); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - createRule(getNewRule()); - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlert(); - }); - - it('should store the flyout state in the url when it is opened and remove it when closed', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - cy.url().should('include', 'flyout='); - - closeAlertFlyout(); - - cy.url().should('not.include', 'flyout='); - }); - - it.skip('should open the alert flyout when the page is refreshed', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - cy.reload(); - cy.get(OVERVIEW_RULE).should('be.visible'); - cy.get(OVERVIEW_RULE).should('contain', 'Endpoint Security'); - }); - - it('should show the copy link button for the flyout', () => { - cy.get(COPY_ALERT_FLYOUT_LINK).should('be.visible'); - }); - - it.skip('should have the `kibana.alert.url` field set', () => { - openTable(); - filterBy('kibana.alert.url'); - cy.get('[data-test-subj="formatted-field-kibana.alert.url"]').should( - 'have.text', - 'http://localhost:5601/app/security/alerts/redirect/eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1?index=.alerts-security.alerts-default×tamp=2023-04-27T11:03:57.906Z' - ); - }); - }); - - describe('Localstorage management', () => { - const ARCHIVED_RULE_ID = '7015a3e2-e4ea-11ed-8c11-49608884878f'; - const ARCHIVED_RULE_NAME = 'Endpoint Security'; - - before(() => { - deleteAlertsAndRules(); - // It just imports an alert without a rule but rule details page should work anyway - cy.task('esArchiverLoad', { archiveName: 'query_alert', useCreate: true, docsOnly: true }); - }); - - after(() => { - cy.task('esArchiverUnload', { archiveName: 'query_alert' }); - }); - - beforeEach(() => { - createRule(getNewRule()); - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlert(); - }); - - /** - * Localstorage is updated after a delay here x-pack/plugins/security_solution/public/common/store/data_table/epic_local_storage.ts - * We create this config to re-check localStorage 3 times, every 500ms to avoid any potential flakyness from that delay - */ - - it('should store the flyout state in localstorage', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - - cy.window().then((win) => { - const securityDataTableStorage = win.localStorage.getItem('securityDataTable'); - cy.wrap(securityDataTableStorage).should('contain', '"panelView":"eventDetail"'); - }); - }); - - it('should remove the flyout details from local storage when closed', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - closeAlertFlyout(); - - cy.window().then((win) => { - const securityDataTableStorage = win.localStorage.getItem('securityDataTable'); - cy.wrap(securityDataTableStorage).should('not.contain', '"panelView"'); - }); - }); - - it('should remove the flyout state from localstorage when navigating away without closing the flyout', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - - visitRuleDetailsPage(ARCHIVED_RULE_ID); - waitForRuleDetailsPageToBeLoaded(ARCHIVED_RULE_NAME); - - cy.window().then((win) => { - const securityDataTableStorage = win.localStorage.getItem('securityDataTable'); - cy.wrap(securityDataTableStorage).should('not.contain', '"panelView"'); - }); - }); - - it('should not reopen the flyout when navigating away from the alerts page and returning to it', () => { - cy.get(OVERVIEW_RULE).should('be.visible'); - - visitRuleDetailsPage(ARCHIVED_RULE_ID); - waitForRuleDetailsPageToBeLoaded(ARCHIVED_RULE_NAME); - - visit(ALERTS_URL); - cy.get(OVERVIEW_RULE).should('not.exist'); - }); - }); -});