diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/home/global_header/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/app/home/global_header/index.tsx index 7cdfd73c7ceef..75a7df7237dd3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/home/global_header/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/app/home/global_header/index.tsx @@ -43,6 +43,7 @@ const BUTTON_ADD_DATA = i18n.translate('xpack.securitySolution.globalHeader.butt * right hand side of the Kibana global header */ export const GlobalHeader = React.memo(() => { + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const portalNode = useMemo(() => createHtmlPortalNode(), []); const { theme, @@ -58,7 +59,7 @@ export const GlobalHeader = React.memo(() => { (state) => (getTimeline(state, TimelineId.active) ?? timelineDefaults).show ); - const sourcererScope = getScopeFromPath(pathname); + const sourcererScope = getScopeFromPath(pathname, newDataViewPickerEnabled); const showSourcerer = showSourcererByPath(pathname); const dashboardViewPath = isDashboardViewPath(pathname); @@ -85,8 +86,6 @@ export const GlobalHeader = React.memo(() => { } }, [portalNode, setHeaderActionMenu, theme, kibanaServiceI18n, dashboardViewPath]); - const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const dataViewPicker = newDataViewPickerEnabled ? ( = ({ children }) => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { pathname } = useLocation(); - const sourcererScope = getScopeFromPath(pathname); - const { browserFields: oldBrowserFields } = useInitSourcerer(sourcererScope); - const { browserFields: experimentalBrowserFields } = useBrowserFields(sourcererScope); + const { browserFields: oldBrowserFields } = useInitSourcerer(getScopeFromPath(pathname, false)); + const { browserFields: experimentalBrowserFields } = useBrowserFields( + getScopeFromPath(pathname, newDataViewPickerEnabled) + ); - useRestoreDataViewManagerStateFromURL(useInitDataViewManager(), sourcererScope); + useRestoreDataViewManagerStateFromURL( + useInitDataViewManager(), + getScopeFromPath(pathname, newDataViewPickerEnabled) + ); useUrlState(); useUpdateBrowserTitle(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx index 8dbaeceef38b4..f5e3dd1318932 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_tab/events_query_tab_body.tsx @@ -80,6 +80,8 @@ const EventsQueryTabBodyComponent: React.FC = }) => { let ACTION_BUTTON_COUNT = MAX_ACTION_BUTTON_COUNT; + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); + const dispatch = useDispatch(); const { globalFullScreen } = useGlobalFullScreen(); const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); @@ -191,6 +193,9 @@ const EventsQueryTabBodyComponent: React.FC = filterQuery={filterQuery} {...(showExternalAlerts ? alertsHistogramConfig : eventsHistogramConfig)} subtitle={getHistogramSubtitle} + sourcererScopeId={ + newDataViewPickerEnabled ? SourcererScopeName.explore : SourcererScopeName.default + } /> )} = leadingControlColumns={leadingControlColumns} renderCellValue={DefaultCellRenderer} rowRenderers={defaultRowRenderers} - sourcererScope={SourcererScopeName.default} + sourcererScope={ + newDataViewPickerEnabled ? SourcererScopeName.explore : SourcererScopeName.default + } tableId={tableId} unit={showExternalAlerts ? i18n.EXTERNAL_ALERTS_UNIT : i18n.EVENTS_UNIT} defaultModel={defaultModel} diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/visualization_embeddable.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/visualization_embeddable.tsx index 0ff89d650fb2b..99844b1730ad5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/visualization_embeddable.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/visualization_embeddable.tsx @@ -44,9 +44,7 @@ const VisualizationEmbeddableComponent: React.FC = const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { dataView } = useDataView(lensProps.scopeId); - const indicesExist = newDataViewPickerEnabled - ? Boolean(dataView?.matchedIndices?.length) - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const memorizedTimerange = useRef(lensProps.timerange); const getGlobalQuery = useMemo(() => inputsSelectors.globalQueryByIdSelector(), []); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/solutions/security/plugins/security_solution/public/common/mock/global_state.ts index 8ec0145afa532..ba72920183f2e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/mock/global_state.ts @@ -498,6 +498,16 @@ export const mockGlobalState: State = { true ), }, + [SourcererScopeName.explore]: { + ...mockSourcererState.sourcererScopes[SourcererScopeName.default], + selectedDataViewId: mockSourcererState.defaultDataView.id, + selectedPatterns: getScopePatternListSelection( + mockSourcererState.defaultDataView, + SourcererScopeName.default, + mockSourcererState.signalIndexName, + true + ), + }, }, }, globalUrlParam: {}, diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_browser_fields.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_browser_fields.ts index d818931a1addc..04950e13094be 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_browser_fields.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_browser_fields.ts @@ -13,6 +13,8 @@ import { useDataView } from './use_data_view'; import { browserFieldsManager } from '../utils/security_browser_fields_manager'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; +const emptyFields = {}; + export const useBrowserFields = ( scope: DataViewManagerScopeName = DataViewManagerScopeName.default, /** @@ -25,8 +27,8 @@ export const useBrowserFields = ( const activeDataView = newDataViewPickerEnabled ? dataView : oldDataView; return useMemo(() => { - if (!activeDataView) { - return {}; + if (!activeDataView?.id) { + return emptyFields; } const { browserFields } = browserFieldsManager.getBrowserFields(activeDataView, scope); diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_init_data_view_manager.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_init_data_view_manager.ts index 8caa8238c8263..a84f761aa8de8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_init_data_view_manager.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_init_data_view_manager.ts @@ -96,6 +96,7 @@ export const useInitDataViewManager = () => { DataViewManagerScopeName.timeline, DataViewManagerScopeName.detections, DataViewManagerScopeName.analyzer, + DataViewManagerScopeName.explore, ].map((scope) => createDataViewSelectedListener({ scope, diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_sync_url_state.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_sync_url_state.ts index 4ca16f8e57224..178b60492b06d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_sync_url_state.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_sync_url_state.ts @@ -18,7 +18,10 @@ import { type SelectDataViewAsyncPayload } from '../redux/actions'; // TODO: remove this in cleanup phase Remove deprecated sourcerer code https://github.com/elastic/security-team/issues/12665 export const useSyncSourcererUrlState = ( - scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default + scopeId: + | SourcererScopeName.default + | SourcererScopeName.explore + | SourcererScopeName.detections = SourcererScopeName.default ) => { const scopeDataViewId = useSelector((state: State) => { return sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId); @@ -82,7 +85,10 @@ export const useSyncSourcererUrlState = ( */ export const useRestoreDataViewManagerStateFromURL = ( initDataViewPickerWithSelection: (initialSelection: SelectDataViewAsyncPayload[]) => void, - scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default + scopeId: + | SourcererScopeName.default + | SourcererScopeName.explore + | SourcererScopeName.detections = SourcererScopeName.default ) => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.test.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.test.ts index 33bf8f8da4fa2..9f3ba9b637971 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.test.ts @@ -40,6 +40,10 @@ const mockedState: RootState = { dataViewId: null, status: 'pristine', }, + explore: { + dataViewId: null, + status: 'pristine', + }, shared: { adhocDataViews: [ { diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.ts index e965a98f37a6c..9221be81a23f4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/data_view_selected.ts @@ -71,7 +71,7 @@ export const createDataViewSelectedListener = (dependencies: { // This is required to compute browserFields later. // If the view is not returned here, it will be fetched further down this file, and that // should return the full data view. - if (isEmpty(cachedDataView?.fields)) { + if (cachedDataView === cachedPersistedDataView && isEmpty(cachedDataView?.fields)) { return null; } diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.test.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.test.ts index 39ac956e100a9..216e130fa0218 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.test.ts @@ -35,7 +35,7 @@ const mockDataViewsService = { const http = {} as unknown as CoreStart['http']; const application = {} as unknown as CoreStart['application']; const uiSettings = {} as unknown as CoreStart['uiSettings']; -const spaces = {} as unknown as SpacesPluginStart; +const spaces = { getActiveSpace: async () => ({ id: 'default' }) } as unknown as SpacesPluginStart; const mockDispatch = jest.fn(); const mockGetState = jest.fn(() => { @@ -45,6 +45,7 @@ const mockGetState = jest.fn(() => { state.dataViewManager.detections = structuredClone(state.dataViewManager.default); state.dataViewManager.timeline = structuredClone(state.dataViewManager.default); state.dataViewManager.analyzer = structuredClone(state.dataViewManager.default); + state.dataViewManager.explore = structuredClone(state.dataViewManager.default); return state; }); @@ -59,6 +60,13 @@ describe('createInitListener', () => { beforeEach(() => { jest.clearAllMocks(); + + jest.mocked(createDefaultDataView).mockResolvedValue({ + defaultDataView: { id: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID, title: '' }, + alertDataView: { id: DEFAULT_ALERT_DATA_VIEW_ID, title: '' }, + kibanaDataViews: [], + } as unknown as Awaited>); + listener = createInitListener({ dataViews: mockDataViewsService, http, @@ -66,12 +74,6 @@ describe('createInitListener', () => { uiSettings, spaces, }); - - jest.mocked(createDefaultDataView).mockResolvedValue({ - defaultDataView: { id: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID }, - alertDataView: { id: DEFAULT_ALERT_DATA_VIEW_ID }, - kibanaDataViews: [], - } as unknown as Awaited>); }); it('should load the data views and dispatch further actions', async () => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.ts index 8b2ebe22e4c4e..a958c233ee23d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/listeners/init_listener.ts @@ -14,6 +14,7 @@ import { sharedDataViewManagerSlice } from '../slices'; import { DataViewManagerScopeName } from '../../constants'; import { selectDataViewAsync } from '../actions'; import { createDefaultDataView } from '../../utils/create_default_data_view'; +import { createExploreDataView } from '../../utils/create_explore_data_view'; /** * Creates a Redux listener for initializing the Data View Manager state. @@ -46,9 +47,7 @@ export const createInitListener = (dependencies: { listenerApi: ListenerEffectAPI> ) => { try { - // Initialize default security data view first - // Note: this is subject to change, as we might want to add specific data view just for alerts - + // Initialize default data views first const { defaultDataView, alertDataView } = await createDefaultDataView({ dataViewService: dependencies.dataViews, uiSettings: dependencies.uiSettings, @@ -57,6 +56,17 @@ export const createInitListener = (dependencies: { http: dependencies.http, }); + const exploreDataView = await createExploreDataView( + { + dataViews: dependencies.dataViews, + spaces: dependencies.spaces, + }, + defaultDataView.title.split(','), + alertDataView.title + ); + + listenerApi.dispatch(sharedDataViewManagerSlice.actions.addDataView(exploreDataView)); + // NOTE: This is later used in the data view manager drop-down selector const dataViews = await dependencies.dataViews.getAllDataViewLazy(); const dataViewSpecs = await Promise.all(dataViews.map((dataView) => dataView.toSpec())); @@ -81,25 +91,35 @@ export const createInitListener = (dependencies: { DataViewManagerScopeName.analyzer, DataViewManagerScopeName.timeline, DataViewManagerScopeName.default, + DataViewManagerScopeName.explore, ] // NOTE: only init default data view for slices that are not initialized yet .filter((scope) => !listenerApi.getState().dataViewManager[scope].dataViewId) .forEach((scope) => { if (scope === DataViewManagerScopeName.detections) { - listenerApi.dispatch( + return listenerApi.dispatch( selectDataViewAsync({ id: alertDataView.id, scope, }) ); - } else { - listenerApi.dispatch( + } + + if (scope === DataViewManagerScopeName.explore) { + return listenerApi.dispatch( selectDataViewAsync({ - id: defaultDataView.id, + id: exploreDataView.id, scope, }) ); } + + listenerApi.dispatch( + selectDataViewAsync({ + id: defaultDataView.id, + scope, + }) + ); }); // NOTE: if there is a list of data views to preload other than default one (eg. coming in from the url storage) diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/reducer.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/reducer.ts index 1bcaec9a28b25..8d18cd0d733bc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/reducer.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/redux/reducer.ts @@ -23,6 +23,7 @@ const REGISTERED_SCOPES = [ DataViewManagerScopeName.timeline, DataViewManagerScopeName.detections, DataViewManagerScopeName.analyzer, + DataViewManagerScopeName.explore, ] as const; /** diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/utils/create_explore_data_view.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/utils/create_explore_data_view.ts new file mode 100644 index 0000000000000..96dd447864d25 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/utils/create_explore_data_view.ts @@ -0,0 +1,28 @@ +/* + * 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 { DataViewsServicePublic, DataView } from '@kbn/data-views-plugin/public'; +import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; + +export const createExploreDataView = async ( + dependencies: { + dataViews: DataViewsServicePublic; + spaces: SpacesPluginStart; + }, + defaultDataViewPatterns: string[], + alertsDataViewPattern: string +): Promise => { + const exploreDataViewPattern = defaultDataViewPatterns + .filter((pattern) => pattern !== alertsDataViewPattern) + .join(); + + return dependencies.dataViews.create({ + id: `explore-data-view-${(await dependencies.spaces.getActiveSpace()).id}`, + name: 'Explore Data View', + title: exploreDataViewPattern, + }); +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/components/stat_items/metric_embeddable.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/components/stat_items/metric_embeddable.tsx index 49cc7305bf1fb..b1b176eb58185 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/components/stat_items/metric_embeddable.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/components/stat_items/metric_embeddable.tsx @@ -6,9 +6,11 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import React from 'react'; +import { DataViewManagerScopeName } from '../../../data_view_manager/constants'; import { FlexItem, StatValue } from './utils'; import { VisualizationEmbeddable } from '../../../common/components/visualization_actions/visualization_embeddable'; import type { FieldConfigs } from './types'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; export interface MetricEmbeddableProps { fields: FieldConfigs[]; @@ -25,6 +27,8 @@ const MetricEmbeddableComponent = ({ inspectTitle, timerange, }: MetricEmbeddableProps) => { + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); + return ( {fields.map((field) => ( @@ -51,6 +55,11 @@ const MetricEmbeddableComponent = ({ lensAttributes={field.lensAttributes} timerange={timerange} inspectTitle={inspectTitle} + scopeId={ + newDataViewPickerEnabled + ? DataViewManagerScopeName.explore + : DataViewManagerScopeName.default + } /> )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/index.tsx index f0b0cd85342e0..53c5644189b22 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/index.tsx @@ -18,6 +18,7 @@ import { useDispatch } from 'react-redux'; import type { Filter } from '@kbn/es-query'; import { buildEsQuery } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import { DataViewManagerScopeName } from '../../../../data_view_manager/constants'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import type { NarrowDateRange } from '../../../../common/components/ml/types'; import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; @@ -132,9 +133,9 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const indicesExist = newDataViewPickerEnabled @@ -283,7 +284,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta hostName={detailName} indexNames={selectedPatterns} jobNameById={jobNameById} - scopeId={SourcererScopeName.default} + scopeId={SourcererScopeName.explore} /> )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/hosts.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/hosts.tsx index df9053908cc70..b72acf68712bf 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/hosts.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/hosts.tsx @@ -14,6 +14,7 @@ import type { Filter } from '@kbn/es-query'; import { isTab } from '@kbn/timelines-plugin/public'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { LastEventIndexKey } from '@kbn/timelines-plugin/common'; +import { DataViewManagerScopeName } from '../../../data_view_manager/constants'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { InputsModelId } from '../../../common/store/inputs/constants'; import { SecurityPageName } from '../../../app/types'; @@ -111,14 +112,12 @@ const HostsComponent = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx index 4ad664b73d9d9..2494829bdf212 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx @@ -7,6 +7,7 @@ import React, { useMemo } from 'react'; import type { ITooltipProperty } from '@kbn/maps-plugin/public/classes/tooltips/tooltip_property'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { sourceDestinationFieldMappings } from '../map_config'; import { getEmptyTagValue, @@ -27,6 +28,8 @@ export const PointToolTipContentComponent = ({ contextId, featureProps, }: PointToolTipContentProps) => { + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); + const featureDescriptionListItems = useMemo( () => featureProps.map((featureProp) => { @@ -43,7 +46,11 @@ export const PointToolTipContentComponent = ({ attrName={key} idPrefix={`map-point-tooltip-${contextId}-${key}-${value}`} render={(item) => getRenderedFieldValue(key, item)} - scopeId={SourcererScopeName.default} + scopeId={ + newDataViewPickerEnabled + ? SourcererScopeName.explore + : SourcererScopeName.default + } /> ) : ( getEmptyTagValue() @@ -52,7 +59,7 @@ export const PointToolTipContentComponent = ({ ), }; }), - [contextId, featureProps] + [contextId, featureProps, newDataViewPickerEnabled] ); return ; diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/details/index.tsx index 1f6d5d4000158..8b83c68dcbff1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/details/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/details/index.tsx @@ -13,6 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elasti import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { buildEsQuery } from '@kbn/es-query'; +import { DataViewManagerScopeName } from '../../../../data_view_manager/constants'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { AlertsByStatus } from '../../../../overview/components/detection_response/alerts_by_status'; @@ -119,14 +120,12 @@ const NetworkDetailsComponent: React.FC = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -251,7 +250,7 @@ const NetworkDetailsComponent: React.FC = () => { narrowDateRange={narrowDateRange} indexPatterns={selectedPatterns} jobNameById={jobNameById} - scopeId={SourcererScopeName.default} + scopeId={SourcererScopeName.explore} /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/dns_query_tab_body.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/dns_query_tab_body.tsx index 09fd8a1633d1f..50b02e065d271 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/dns_query_tab_body.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/dns_query_tab_body.tsx @@ -8,6 +8,7 @@ import React, { useEffect, useCallback, useMemo, useState } from 'react'; import { getOr } from 'lodash/fp'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { NetworkDnsTable } from '../../components/network_dns_table'; import { useNetworkDns, ID } from '../../containers/network_dns'; import { manageQuery } from '../../../../common/components/page/manage_query'; @@ -24,6 +25,7 @@ import { networkSelectors } from '../../store'; import { useShallowEqualSelector } from '../../../../common/hooks/use_selector'; import { getDnsTopDomainsLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/dns_top_domains'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; +import { SourcererScopeName } from '../../../../sourcerer/store/model'; const HISTOGRAM_ID = 'networkDnsHistogramQuery'; @@ -99,6 +101,8 @@ const DnsQueryTabBodyComponent: React.FC = ({ [getTitle] ); + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); + return ( <> = ({ filterQuery={filterQuery} startDate={startDate} {...dnsHistogramConfigs} + sourcererScopeId={ + newDataViewPickerEnabled ? SourcererScopeName.explore : SourcererScopeName.default + } /> ( const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/index.tsx index 3497e835bbd28..a6fe5b480db28 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/index.tsx @@ -19,6 +19,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { Filter } from '@kbn/es-query'; import { buildEsQuery } from '@kbn/es-query'; import { LastEventIndexKey } from '@kbn/timelines-plugin/common'; +import { DataViewManagerScopeName } from '../../../../data_view_manager/constants'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; @@ -118,14 +119,12 @@ const UsersDetailsComponent: React.FC = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -269,7 +268,11 @@ const UsersDetailsComponent: React.FC = ({ narrowDateRange={narrowDateRange} indexPatterns={selectedPatterns} jobNameById={jobNameById} - scopeId={SourcererScopeName.default} + scopeId={ + newDataViewPickerEnabled + ? SourcererScopeName.explore + : SourcererScopeName.default + } /> )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/navigation/authentications_query_tab_body.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/navigation/authentications_query_tab_body.tsx index fdb55542a2aac..ee9dcabbf6f42 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/navigation/authentications_query_tab_body.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/navigation/authentications_query_tab_body.tsx @@ -6,6 +6,8 @@ */ import React from 'react'; +import { SourcererScopeName } from '../../../../sourcerer/store/model'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { AuthenticationsUserTable } from '../../../components/authentication/authentications_user_table'; import { histogramConfigs } from '../../../components/authentication/helpers'; import type { AuthenticationsUserTableProps } from '../../../components/authentication/types'; @@ -25,6 +27,8 @@ export const AuthenticationsQueryTabBody = ({ deleteQuery, userName, }: AuthenticationsUserTableProps) => { + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); + return ( <> { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); - const experimentalSelectedPatterns = useSelectedPatterns(); + const { dataView, status } = useDataView(DataViewManagerScopeName.explore); + const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length - : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; diff --git a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/sourcerer_paths.ts b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/sourcerer_paths.ts index 388eae965f7c8..80ba3c35356cb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/sourcerer_paths.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/sourcerer_paths.ts @@ -37,15 +37,33 @@ const detectionsPaths = [ ATTACK_DISCOVERY_PATH, ]; +const explorePaths = [HOSTS_PATH, USERS_PATH, NETWORK_PATH, OVERVIEW_PATH]; + export const getScopeFromPath = ( - pathname: string -): SourcererScopeName.default | SourcererScopeName.detections => - matchPath(pathname, { - path: detectionsPaths, - strict: false, - }) == null - ? SourcererScopeName.default - : SourcererScopeName.detections; + pathname: string, + newDataViewPickerEnabled?: boolean +): SourcererScopeName.default | SourcererScopeName.detections | SourcererScopeName.explore => { + if ( + matchPath(pathname, { + path: detectionsPaths, + strict: false, + }) + ) { + return SourcererScopeName.detections; + } + + if ( + newDataViewPickerEnabled && + matchPath(pathname, { + path: explorePaths, + strict: false, + }) + ) { + return SourcererScopeName.explore; + } + + return SourcererScopeName.default; +}; export const showSourcererByPath = (pathname: string): boolean => matchPath(pathname, { diff --git a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/use_init_sourcerer.tsx b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/use_init_sourcerer.tsx index 6117794852704..acaf75e9c6694 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/use_init_sourcerer.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/containers/use_init_sourcerer.tsx @@ -27,7 +27,10 @@ import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experime const defaultInitResult = { browserFields: {} }; export const useInitSourcerer = ( - scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default + scopeId: + | SourcererScopeName.default + | SourcererScopeName.detections + | SourcererScopeName.explore = SourcererScopeName.default ) => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/helpers.ts b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/helpers.ts index 2fccdbdd23025..dcec74c6a8150 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/helpers.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/helpers.ts @@ -20,6 +20,7 @@ const getPatternListFromScope = ( // when our SIEM data view is set, here are the defaults switch (scope) { case SourcererScopeName.default: + case SourcererScopeName.explore: return sortWithExcludesAtEnd(patternList.filter((index) => index !== signalIndexName)); case SourcererScopeName.detections: // set to signalIndexName whether or not it exists yet in the patternList diff --git a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/model.ts b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/model.ts index 32cf67e0fc743..6455d6bfd5171 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/model.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/store/model.ts @@ -16,6 +16,7 @@ export enum SourcererScopeName { detections = 'detections', timeline = 'timeline', analyzer = 'analyzer', + explore = 'explore', } /** @@ -165,5 +166,9 @@ export const initialSourcererState: SourcererModel = { ...initSourcererScope, id: SourcererScopeName.analyzer, }, + [SourcererScopeName.explore]: { + ...initSourcererScope, + id: SourcererScopeName.explore, + }, }, };