From 08d96b3af1c5b9d0be85f0c8b27eec75b084266a Mon Sep 17 00:00:00 2001 From: lgestc Date: Fri, 4 Jul 2025 11:05:51 +0200 Subject: [PATCH 01/12] [Security Solution][Sourcerer] Add dedicated scope for explore pages --- .../public/app/home/global_header/index.tsx | 5 ++- .../public/app/home/index.tsx | 12 ++++--- .../events_tab/events_query_tab_body.tsx | 9 ++++- .../visualization_embeddable.tsx | 2 +- .../hooks/use_browser_fields.ts | 4 +-- .../hooks/use_init_data_view_manager.ts | 1 + .../hooks/use_sync_url_state.ts | 5 ++- .../redux/listeners/data_view_selected.ts | 2 +- .../redux/listeners/init_listener.ts | 34 +++++++++++++++---- .../public/data_view_manager/redux/reducer.ts | 1 + .../utils/create_explore_data_view.ts | 28 +++++++++++++++ .../stat_items/metric_embeddable.tsx | 9 +++++ .../explore/hosts/pages/details/index.tsx | 9 ++--- .../public/explore/hosts/pages/hosts.tsx | 7 ++-- .../map_tool_tip/point_tool_tip_content.tsx | 11 ++++-- .../explore/network/pages/details/index.tsx | 9 ++--- .../pages/navigation/dns_query_tab_body.tsx | 7 ++++ .../public/explore/network/pages/network.tsx | 9 ++--- .../explore/users/pages/details/index.tsx | 9 ++--- .../authentications_query_tab_body.tsx | 7 ++++ .../public/explore/users/pages/users.tsx | 7 ++-- .../sourcerer/containers/sourcerer_paths.ts | 34 ++++++++++++++----- .../containers/use_init_sourcerer.tsx | 5 ++- .../public/sourcerer/store/model.ts | 5 +++ 24 files changed, 178 insertions(+), 53 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/data_view_manager/utils/create_explore_data_view.ts 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..b4567163dbd4f 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 @@ -45,7 +45,7 @@ const VisualizationEmbeddableComponent: React.FC = const { dataView } = useDataView(lensProps.scopeId); const indicesExist = newDataViewPickerEnabled - ? Boolean(dataView?.matchedIndices?.length) + ? Boolean(dataView.matchedIndices.length) : oldIndicesExist; const memorizedTimerange = useRef(lensProps.timerange); 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 f498e841a5791..ba583db5762c4 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 @@ -17,7 +17,7 @@ export const useBrowserFields = ( const { dataViewSpec } = useDataViewSpec(scope); return useMemo(() => { - if (!dataViewSpec) { + if (!dataViewSpec.id) { return {}; } @@ -27,5 +27,5 @@ export const useBrowserFields = ( ); return browserFields; - }, [dataViewSpec]); + }, [dataViewSpec.id, dataViewSpec?.title, dataViewSpec.fields]); }; 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..4bcbcc98ae9f1 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 @@ -82,7 +82,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.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.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..5b8d25601236b 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,9 +112,9 @@ 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 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..1cf8b8e72fa4a 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,9 +120,9 @@ 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 @@ -251,7 +252,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 + ? !!dataView.matchedIndices.length : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns 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..78079ac6e9b64 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,9 +119,9 @@ 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 @@ -269,7 +270,7 @@ const UsersDetailsComponent: 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/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 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/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, + }, }, }; From 0eb93a56d8b4187fba4ae54785ba9dc4e0f35e29 Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 09:14:04 +0200 Subject: [PATCH 02/12] types --- .../plugins/security_solution/public/sourcerer/store/helpers.ts | 1 + 1 file changed, 1 insertion(+) 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 From f2ee6cd68676e770f909f7dfbb43aeef90e59070 Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 09:15:38 +0200 Subject: [PATCH 03/12] add missing initial scope for explore --- .../redux/listeners/data_view_selected.test.ts | 4 ++++ 1 file changed, 4 insertions(+) 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: [ { From 3799806f050eb9390d24a6351854a33103f80953 Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 11:58:20 +0200 Subject: [PATCH 04/12] use hasMatchedIndices --- .../visualization_actions/visualization_embeddable.tsx | 4 +--- .../security_solution/public/explore/hosts/pages/hosts.tsx | 4 +--- .../public/explore/network/pages/details/index.tsx | 4 +--- .../public/explore/network/pages/network.tsx | 4 +--- .../public/explore/users/pages/details/index.tsx | 4 +--- .../security_solution/public/explore/users/pages/users.tsx | 4 +--- 6 files changed, 6 insertions(+), 18 deletions(-) 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 b4567163dbd4f..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/explore/hosts/pages/hosts.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/hosts.tsx index 5b8d25601236b..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 @@ -117,9 +117,7 @@ const HostsComponent = () => { 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/pages/details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/details/index.tsx index 1cf8b8e72fa4a..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 @@ -125,9 +125,7 @@ const NetworkDetailsComponent: React.FC = () => { 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/pages/network.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/network.tsx index 3cc8492dd6b65..503fdd62d937f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/network.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/network.tsx @@ -100,9 +100,7 @@ const NetworkComponent = React.memo( 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 78079ac6e9b64..7eaf81cdc7e0d 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 @@ -124,9 +124,7 @@ const UsersDetailsComponent: React.FC = ({ 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/users.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/users.tsx index bff86a9913885..df6d4e4ab7a95 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/users.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/users.tsx @@ -118,9 +118,7 @@ const UsersComponent = () => { 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; From d3b4d4acf85b45e505059afaf5eea4c759654c65 Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 12:50:38 +0200 Subject: [PATCH 05/12] update parameter type --- .../public/data_view_manager/hooks/use_sync_url_state.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 4bcbcc98ae9f1..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); From 604489e0558799399a827f8283149a732d8aad2a Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 15:13:36 +0200 Subject: [PATCH 06/12] fix broken tesT --- .../redux/listeners/init_listener.test.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 () => { From bcdee9bdc012d0cf279dc56aa6b74d257d70e9a1 Mon Sep 17 00:00:00 2001 From: lgestc Date: Mon, 7 Jul 2025 16:19:25 +0200 Subject: [PATCH 07/12] sourcerer test --- .../public/common/mock/global_state.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) 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: {}, From 5f194e0adb51a4a97d9000c4d6332a8297570c57 Mon Sep 17 00:00:00 2001 From: lgestc Date: Wed, 9 Jul 2025 11:21:57 +0200 Subject: [PATCH 08/12] fix missing spot --- .../public/explore/users/pages/details/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 7eaf81cdc7e0d..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 @@ -268,7 +268,11 @@ const UsersDetailsComponent: React.FC = ({ narrowDateRange={narrowDateRange} indexPatterns={selectedPatterns} jobNameById={jobNameById} - scopeId={SourcererScopeName.explore} + scopeId={ + newDataViewPickerEnabled + ? SourcererScopeName.explore + : SourcererScopeName.default + } /> )} From 0cf568ca55e2c36e0b74be73a1e06080929b2de5 Mon Sep 17 00:00:00 2001 From: lgestc Date: Wed, 9 Jul 2025 14:04:08 +0200 Subject: [PATCH 09/12] [Security Solution][Sourcerer] Display explore DV as managed --- .../components/data_view_picker/index.tsx | 6 ++++-- .../public/data_view_manager/constants.ts | 2 ++ .../hooks/use_managed_data_views.ts | 13 ++++++++++--- .../utils/create_explore_data_view.ts | 3 ++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx index 40513f0af7a46..e9a9bf171d074 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx @@ -17,7 +17,7 @@ import { useKibana } from '../../../common/lib/kibana'; import { sharedStateSelector } from '../../redux/selectors'; import { sharedDataViewManagerSlice } from '../../redux/slices'; import { useSelectDataView } from '../../hooks/use_select_data_view'; -import { DataViewManagerScopeName } from '../../constants'; +import { DataViewManagerScopeName, EXPLORE_DATA_VIEW_PREFIX } from '../../constants'; import { useManagedDataViews } from '../../hooks/use_managed_data_views'; import { useSavedDataViews } from '../../hooks/use_saved_data_views'; import { DEFAULT_SECURITY_DATA_VIEW, LOADING } from './translations'; @@ -61,7 +61,9 @@ export const DataViewPicker = memo(({ scope, onClosePopover, disabled }: DataVie const { adhocDataViews: adhocDataViewSpecs, defaultDataViewId } = useSelector(sharedStateSelector); const adhocDataViews = useMemo(() => { - return adhocDataViewSpecs.map((spec) => new DataView({ spec, fieldFormats })); + return adhocDataViewSpecs + .filter((spec) => !spec.id?.startsWith(EXPLORE_DATA_VIEW_PREFIX)) + .map((spec) => new DataView({ spec, fieldFormats })); }, [adhocDataViewSpecs, fieldFormats]); const managedDataViews = useManagedDataViews(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts index 24657f7f3a096..97b2d86fa334e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts @@ -10,3 +10,5 @@ export const DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID = 'security-solution-default export { SourcererScopeName as DataViewManagerScopeName } from '../sourcerer/store/model'; export const SLICE_PREFIX = 'x-pack/security_solution/dataViewManager' as const; + +export const EXPLORE_DATA_VIEW_PREFIX = 'explore-data-view' as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts index a45aec3ca42fc..54b1be75ab199 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts @@ -10,6 +10,7 @@ import { useSelector } from 'react-redux'; import { useMemo } from 'react'; import { useKibana } from '../../common/lib/kibana'; import { sharedStateSelector } from '../redux/selectors'; +import { EXPLORE_DATA_VIEW_PREFIX } from '../constants'; /** * Returns the default security solution data view and alert data view @@ -17,6 +18,7 @@ import { sharedStateSelector } from '../redux/selectors'; export const useManagedDataViews = (): DataView[] => { const { dataViews: dataViewSpecs, + adhocDataViews, defaultDataViewId, alertDataViewId, } = useSelector(sharedStateSelector); @@ -26,9 +28,14 @@ export const useManagedDataViews = (): DataView[] => { return useMemo( () => - dataViewSpecs - .filter((dv) => dv.id === defaultDataViewId || dv.id === alertDataViewId) + [...dataViewSpecs, ...adhocDataViews] + .filter( + (dv) => + dv.id === defaultDataViewId || + dv.id === alertDataViewId || + dv.id?.startsWith(EXPLORE_DATA_VIEW_PREFIX) + ) .map((spec) => new DataView({ spec, fieldFormats })), - [dataViewSpecs, defaultDataViewId, alertDataViewId, fieldFormats] + [dataViewSpecs, adhocDataViews, defaultDataViewId, alertDataViewId, fieldFormats] ); }; 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 index 96dd447864d25..fc1ec853f35ca 100644 --- 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 @@ -7,6 +7,7 @@ import type { DataViewsServicePublic, DataView } from '@kbn/data-views-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import { EXPLORE_DATA_VIEW_PREFIX } from '../constants'; export const createExploreDataView = async ( dependencies: { @@ -21,7 +22,7 @@ export const createExploreDataView = async ( .join(); return dependencies.dataViews.create({ - id: `explore-data-view-${(await dependencies.spaces.getActiveSpace()).id}`, + id: `${EXPLORE_DATA_VIEW_PREFIX}-${(await dependencies.spaces.getActiveSpace()).id}`, name: 'Explore Data View', title: exploreDataViewPattern, }); From c0f29debaf31afb20cf6220d75167ca125531b0a Mon Sep 17 00:00:00 2001 From: lgestc Date: Thu, 10 Jul 2025 09:52:08 +0200 Subject: [PATCH 10/12] fix broken tesT --- .../data_view_manager/hooks/use_managed_data_views.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.test.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.test.ts index 0eadbeb8ff976..fd1c253cd2b17 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.test.ts @@ -58,6 +58,7 @@ describe('useManagedDataViews', () => { // Mock the Redux selector (useSelector as jest.Mock).mockReturnValue({ dataViews: mockDataViews, + adhocDataViews: [], defaultDataViewId: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID, alertDataViewId: DEFAULT_ALERT_DATA_VIEW_ID, }); @@ -101,6 +102,7 @@ describe('useManagedDataViews', () => { ]; (useSelector as jest.Mock).mockReturnValue({ dataViews: mockDataViews, + adhocDataViews: [], defaultDataViewId: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID, }); From 8ed25bdc060aebaa764edfe6550d19927327cb95 Mon Sep 17 00:00:00 2001 From: lgestc Date: Thu, 10 Jul 2025 09:54:33 +0200 Subject: [PATCH 11/12] move constant --- .../security/plugins/security_solution/common/constants.ts | 2 ++ .../data_view_manager/components/data_view_picker/index.tsx | 3 ++- .../security_solution/public/data_view_manager/constants.ts | 2 -- .../public/data_view_manager/hooks/use_managed_data_views.ts | 2 +- .../public/data_view_manager/utils/create_explore_data_view.ts | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/constants.ts index 3c2ced7ba57ee..80300227b0ae7 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/constants.ts @@ -82,6 +82,8 @@ export const DEFAULT_THREAT_INDEX_KEY = 'securitySolution:defaultThreatIndex' as export const DEFAULT_THREAT_INDEX_VALUE = ['logs-ti_*'] as const; export const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"' as const; +export const EXPLORE_DATA_VIEW_PREFIX = 'explore-data-view' as const; + export const EXPLORE_PATH = '/explore' as const; export const DASHBOARDS_PATH = '/dashboards' as const; export const MANAGE_PATH = '/manage' as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx index e9a9bf171d074..0418821e0a454 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/components/data_view_picker/index.tsx @@ -10,6 +10,7 @@ import React, { useCallback, useRef, useMemo, memo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { DataView } from '@kbn/data-views-plugin/public'; +import { EXPLORE_DATA_VIEW_PREFIX } from '../../../../common/constants'; import type { SourcererUrlState } from '../../../sourcerer/store/model'; import { useUpdateUrlParam } from '../../../common/utils/global_query_string'; import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; @@ -17,7 +18,7 @@ import { useKibana } from '../../../common/lib/kibana'; import { sharedStateSelector } from '../../redux/selectors'; import { sharedDataViewManagerSlice } from '../../redux/slices'; import { useSelectDataView } from '../../hooks/use_select_data_view'; -import { DataViewManagerScopeName, EXPLORE_DATA_VIEW_PREFIX } from '../../constants'; +import { DataViewManagerScopeName } from '../../constants'; import { useManagedDataViews } from '../../hooks/use_managed_data_views'; import { useSavedDataViews } from '../../hooks/use_saved_data_views'; import { DEFAULT_SECURITY_DATA_VIEW, LOADING } from './translations'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts index 97b2d86fa334e..24657f7f3a096 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/constants.ts @@ -10,5 +10,3 @@ export const DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID = 'security-solution-default export { SourcererScopeName as DataViewManagerScopeName } from '../sourcerer/store/model'; export const SLICE_PREFIX = 'x-pack/security_solution/dataViewManager' as const; - -export const EXPLORE_DATA_VIEW_PREFIX = 'explore-data-view' as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts index 54b1be75ab199..5960d12b103fe 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/data_view_manager/hooks/use_managed_data_views.ts @@ -8,9 +8,9 @@ import { DataView } from '@kbn/data-views-plugin/public'; import { useSelector } from 'react-redux'; import { useMemo } from 'react'; +import { EXPLORE_DATA_VIEW_PREFIX } from '../../../common/constants'; import { useKibana } from '../../common/lib/kibana'; import { sharedStateSelector } from '../redux/selectors'; -import { EXPLORE_DATA_VIEW_PREFIX } from '../constants'; /** * Returns the default security solution data view and alert data view 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 index fc1ec853f35ca..a2d06cb5df16c 100644 --- 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 @@ -7,7 +7,7 @@ import type { DataViewsServicePublic, DataView } from '@kbn/data-views-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { EXPLORE_DATA_VIEW_PREFIX } from '../constants'; +import { EXPLORE_DATA_VIEW_PREFIX } from '../../../common/constants'; export const createExploreDataView = async ( dependencies: { From 32076958321e4a3765f8925a2d8a4c4314c81f3a Mon Sep 17 00:00:00 2001 From: lgestc Date: Thu, 10 Jul 2025 09:55:12 +0200 Subject: [PATCH 12/12] naming --- .../public/data_view_manager/utils/create_explore_data_view.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index a2d06cb5df16c..b6aec04ed395e 100644 --- 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 @@ -23,7 +23,7 @@ export const createExploreDataView = async ( return dependencies.dataViews.create({ id: `${EXPLORE_DATA_VIEW_PREFIX}-${(await dependencies.spaces.getActiveSpace()).id}`, - name: 'Explore Data View', + name: 'Explore data view', title: exploreDataViewPattern, }); };