diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx b/x-pack/solutions/security/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx index 8d55928e4da35..b27f9abd0a97a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/app/components/top_values_popover/top_values_popover.tsx @@ -14,7 +14,7 @@ import { StatefulTopN } from '../../../common/components/top_n'; import { getScopeFromPath } from '../../../sourcerer/containers/sourcerer_paths'; import { useSourcererDataView } from '../../../sourcerer/containers'; import { useKibana } from '../../../common/lib/kibana'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { useBrowserFields } from '../../../data_view_manager/hooks/use_browser_fields'; export const TopValuesPopover = React.memo(() => { @@ -25,10 +25,9 @@ export const TopValuesPopover = React.memo(() => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(sourcererScope); + const { dataView: experimentalDataView } = useDataView(sourcererScope); const experimentalBrowserFields = useBrowserFields(sourcererScope); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const browserFields = newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields; const { @@ -57,7 +56,8 @@ export const TopValuesPopover = React.memo(() => { field={data.fieldName} scopeId={data.scopeId} toggleTopN={onClose} - dataViewSpec={sourcererDataView} + dataView={experimentalDataView} + dataViewSpec={oldSourcererDataView} browserFields={browserFields} /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/assistant/send_to_timeline/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/assistant/send_to_timeline/index.tsx index 4c906bb93154d..432c93b6a7d2b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/assistant/send_to_timeline/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/assistant/send_to_timeline/index.tsx @@ -67,10 +67,10 @@ export const SendToTimelineButton: FC { const pageTitle = useMemo(() => , []); const { sourcererDataView: oldSourcererDataView } = useSourcererDataView(); - - const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(); - - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; + const { dataView: experimentalDataView } = useDataView(); // filterQuery is the combined search bar query and filters in ES format: const [filterQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, queries: [query ?? getDefaultQuery()], // <-- search bar query filters: filters ?? [], // <-- search bar filters }), - [filters, query, sourcererDataView, uiSettings] + [experimentalDataView, filters, oldSourcererDataView, query, uiSettings] ); // renders a toast if the filter query is invalid: diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/create_flyout/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/create_flyout/index.tsx index 1fe95ff8f04dc..be00e1a3caed7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/create_flyout/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/create_flyout/index.tsx @@ -17,6 +17,8 @@ import { } from '@elastic/eui'; import { useAssistantContext, useLoadConnectors } from '@kbn/elastic-assistant'; +import { DataViewManagerScopeName } from '../../../../../data_view_manager/constants'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useKibana } from '../../../../../common/lib/kibana'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; import { Footer } from '../../footer'; @@ -46,6 +48,7 @@ export const CreateFlyout: React.FC = React.memo(({ onClose }) => { }); const { sourcererDataView } = useSourcererDataView(); + const { dataView: experimentalDataView } = useDataView(DataViewManagerScopeName.detections); const { mutateAsync: createAttackDiscoverySchedule, isLoading: isLoadingQuery } = useCreateAttackDiscoverySchedule(); @@ -63,7 +66,8 @@ export const CreateFlyout: React.FC = React.memo(({ onClose }) => { alertsIndexPattern ?? '', connector, sourcererDataView, - uiSettings + uiSettings, + experimentalDataView ); await createAttackDiscoverySchedule({ scheduleToCreate }); onClose(); @@ -75,6 +79,7 @@ export const CreateFlyout: React.FC = React.memo(({ onClose }) => { aiConnectors, alertsIndexPattern, createAttackDiscoverySchedule, + experimentalDataView, onClose, sourcererDataView, uiSettings, diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/details_flyout/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/details_flyout/index.tsx index f97d5df36f1c3..d16e56c1fda9c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/details_flyout/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/details_flyout/index.tsx @@ -24,6 +24,7 @@ import { useAssistantContext, useLoadConnectors } from '@kbn/elastic-assistant'; import { DEFAULT_END, DEFAULT_START } from '@kbn/elastic-assistant-common'; import type { Filter } from '@kbn/es-query'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import * as i18n from './translations'; import { useKibana } from '../../../../../common/lib/kibana'; @@ -39,6 +40,7 @@ import { ScheduleDefinition } from './definition'; import { Header } from './header'; import { ScheduleExecutionLogs } from './execution_logs'; import { convertFormDataInBaseSchedule } from '../utils/convert_form_data'; +import { DataViewManagerScopeName } from '../../../../../data_view_manager/constants'; interface Props { scheduleId: string; @@ -65,6 +67,7 @@ export const DetailsFlyout: React.FC = React.memo(({ scheduleId, onClose }); const { sourcererDataView } = useSourcererDataView(); + const { dataView: experimentalDataView } = useDataView(DataViewManagerScopeName.detections); const [isEditing, setIsEditing] = useState(false); @@ -84,7 +87,8 @@ export const DetailsFlyout: React.FC = React.memo(({ scheduleId, onClose alertsIndexPattern ?? '', connector, sourcererDataView, - uiSettings + uiSettings, + experimentalDataView ); await updateAttackDiscoverySchedule({ id: scheduleId, scheduleToUpdate }); setIsEditing(false); @@ -94,11 +98,12 @@ export const DetailsFlyout: React.FC = React.memo(({ scheduleId, onClose }, [ aiConnectors, - uiSettings, - sourcererDataView, - scheduleId, alertsIndexPattern, + sourcererDataView, + uiSettings, + experimentalDataView, updateAttackDiscoverySchedule, + scheduleId, ] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.test.ts b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.test.ts index 7b3e62fca8fc4..6f15fe55b695f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.test.ts @@ -13,6 +13,7 @@ import { convertFormDataInBaseSchedule } from './convert_form_data'; import { convertToBuildEsQuery } from '../../../../../common/lib/kuery'; import { getGenAiConfig } from '../../../use_attack_discovery/helpers'; import { parseFilterQuery } from '../../parse_filter_query'; +import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub'; jest.mock('../../../../../common/lib/kuery'); jest.mock('../../../use_attack_discovery/helpers'); @@ -50,7 +51,8 @@ describe('convertFormDataInBaseSchedule', () => { {} as DataViewSpec, { get: jest.fn(), - } as unknown as IUiSettingsClient + } as unknown as IUiSettingsClient, + createStubDataView({ spec: {} }) ); expect(baseSchedule).toEqual({ actions: [], diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.ts b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.ts index 7d54801b6478b..7ba7b547920ae 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/schedule/utils/convert_form_data.ts @@ -6,7 +6,7 @@ */ import type { IUiSettingsClient } from '@kbn/core/public'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { DataView, DataViewSpec } from '@kbn/data-plugin/common'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { AIConnector } from '@kbn/elastic-assistant'; @@ -20,13 +20,15 @@ export const convertFormDataInBaseSchedule = ( alertsIndexPattern: string, connector: AIConnector, dataViewSpec: DataViewSpec, - uiSettings: IUiSettingsClient + uiSettings: IUiSettingsClient, + dataView: DataView ) => { const alertsSelectionSettings = scheduleData.alertsSelectionSettings; const [filterQuery, kqlError] = convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), dataViewSpec, + dataView, queries: [alertsSelectionSettings.query], filters: alertsSelectionSettings.filters, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/cell_actions/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/cell_actions/index.tsx index 51ee44c081886..878fab09ebab5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/cell_actions/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/cell_actions/index.tsx @@ -71,7 +71,7 @@ export const SecurityCellActions: React.FC = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { dataView: experimentalDataView } = useDataView(sourcererScopeId); - const dataViewId = newDataViewPickerEnabled ? experimentalDataView?.id : oldDataViewId; + const dataViewId = newDataViewPickerEnabled ? experimentalDataView.id : oldDataViewId; // Make a dependency key to prevent unnecessary re-renders when data object is defined inline // It is necessary because the data object is an array or an object and useMemo would always re-render @@ -82,13 +82,13 @@ export const SecurityCellActions: React.FC = ({ (Array.isArray(data) ? data : [data]) .map(({ field, value }) => ({ field: newDataViewPickerEnabled - ? experimentalDataView?.fields?.getByName(field)?.toSpec() + ? experimentalDataView.fields?.getByName(field)?.toSpec() : oldGetFieldSpec(field), value, })) .filter((item): item is CellActionsData => !!item.field), // eslint-disable-next-line react-hooks/exhaustive-deps -- Use the dependencyKey to prevent unnecessary re-renders - [dependencyKey, oldGetFieldSpec, newDataViewPickerEnabled, experimentalDataView?.fields] + [dependencyKey, oldGetFieldSpec, newDataViewPickerEnabled, experimentalDataView.fields] ); const metadataWithDataView = useMemo(() => ({ ...metadata, dataViewId }), [dataViewId, metadata]); diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx index c4fd72729bbe2..f1d819bdc1df7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -34,7 +34,6 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { EuiTheme } from '@kbn/kibana-react-plugin/common'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { InspectButton } from '../inspect'; import type { @@ -152,27 +151,31 @@ const StatefulEventsViewerComponent: React.FC { + return newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) ?? {} + : (oldSourcererDataView?.runtimeFieldMap as RunTimeMappings) ?? {}; + }, [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataView]); + const experimentalGetFieldSpec = useCallback( (fieldName: string) => { - return experimentalDataView?.fields?.getByName(fieldName)?.toSpec(); + return experimentalDataView.fields?.getByName(fieldName)?.toSpec(); }, - [experimentalDataView?.fields] + [experimentalDataView.fields] ); const getFieldSpec = newDataViewPickerEnabled ? experimentalGetFieldSpec : oldGetFieldSpec; @@ -241,12 +244,22 @@ const StatefulEventsViewerComponent: React.FC([[]]); @@ -416,7 +415,7 @@ const InsightEditorComponent = ({ ); }, [labelController.field.value, providers, dataView]); const filtersStub = useMemo(() => { - const index = sourcererDataView.name ?? '*'; + const index = dataViewName ?? '*'; return [ { $state: { @@ -430,7 +429,7 @@ const InsightEditorComponent = ({ }, }, ]; - }, [sourcererDataView]); + }, [dataViewName]); const isPlatinum = useLicense().isAtLeast('platinum'); return ( @@ -496,11 +495,11 @@ const InsightEditorComponent = ({ /> - {oldDataView ? ( + {dataView ? ( ) : ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts b/x-pack/solutions/security/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts index aa2a64729f93e..6c4bb236794b1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/markdown_editor/plugins/insight/use_insight_query.ts @@ -18,7 +18,7 @@ import { useTimelineEvents } from '../../../../../timelines/containers'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import type { TimeRange } from '../../../../store/inputs/model'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useSelectedPatterns } from '../../../../../data_view_manager/hooks/use_selected_patterns'; import { useBrowserFields } from '../../../../../data_view_manager/hooks/use_browser_fields'; @@ -54,16 +54,15 @@ export const useInsightQuery = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); const experimentalBrowserFields = useBrowserFields(SourcererScopeName.timeline); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; const browserFields = newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields; - const dataViewId = newDataViewPickerEnabled ? dataViewSpec?.id ?? '' : oldDataViewId; + const dataViewId = newDataViewPickerEnabled ? experimentalDataView.id ?? '' : oldDataViewId; const [hasError, setHasError] = useState(false); const combinedQueries = useMemo(() => { @@ -72,7 +71,8 @@ export const useInsightQuery = ({ const parsedCombinedQueries = combineQueries({ config: esQueryConfig, dataProviders, - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, browserFields, filters, kqlQuery: { @@ -87,7 +87,15 @@ export const useInsightQuery = ({ setHasError(true); return null; } - }, [browserFields, dataProviders, esQueryConfig, hasError, sourcererDataView, filters]); + }, [ + hasError, + esQueryConfig, + dataProviders, + oldSourcererDataView, + experimentalDataView, + browserFields, + filters, + ]); const [dataLoadingState, { events, totalCount }] = useTimelineEvents({ dataViewId, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.test.tsx index c680ae5a87dfe..5b60f954693df 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.test.tsx @@ -11,11 +11,12 @@ import { TableId } from '@kbn/securitysolution-data-table'; import { TimelineId } from '../../../../common/types/timeline'; import { mockBrowserFields } from '../../containers/source/mock'; -import { mockGlobalState, TestProviders, createMockStore, mockDataViewSpec } from '../../mock'; +import { createMockStore, mockDataViewSpec, mockGlobalState, TestProviders } from '../../mock'; import type { State } from '../../store'; import { TopN } from './top_n'; import { detectionAlertsTables } from './helpers'; import { StatefulTopN } from '.'; +import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub'; jest.mock('react-router-dom', () => { const original = jest.requireActual('react-router-dom'); @@ -152,6 +153,7 @@ const store = createMockStore(state); const testProps = { browserFields: mockBrowserFields, + dataView: createStubDataView({ spec: {} }), field, indexPattern: mockDataViewSpec, scopeId: TableId.hostsPageEvents, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.tsx index 7cf729e3bc457..371bcdc83b807 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/index.tsx @@ -10,7 +10,7 @@ import type { ConnectedProps } from 'react-redux'; import { connect } from 'react-redux'; import type { Filter, Query } from '@kbn/es-query'; -import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; +import { type DataView, type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; import { isActiveTimeline } from '../../../helpers'; import { InputsModelId } from '../../store/inputs/constants'; import { useGlobalTime } from '../../containers/use_global_time'; @@ -78,12 +78,14 @@ export interface OwnProps { browserFields: BrowserFields; field: string; dataViewSpec?: DataViewSpec; + dataView: DataView; scopeId?: string; toggleTopN: () => void; onFilterAdded?: () => void; paddingSize?: 's' | 'm' | 'l' | 'none'; globalFilters?: Filter[]; } + type PropsFromRedux = ConnectedProps; type Props = OwnProps & PropsFromRedux; @@ -97,6 +99,7 @@ const StatefulTopNComponent: React.FC = ({ dataProviders, field, dataViewSpec, + dataView, globalFilters = EMPTY_FILTERS, globalQuery = EMPTY_QUERY, kqlMode, @@ -120,6 +123,7 @@ const StatefulTopNComponent: React.FC = ({ dataProviders, filters: activeTimelineFilters, dataViewSpec, + dataView, kqlMode, kqlQuery: { language: 'kuery', @@ -134,6 +138,7 @@ const StatefulTopNComponent: React.FC = ({ dataProviders, activeTimelineFilters, dataViewSpec, + dataView, kqlMode, activeTimelineKqlQueryExpression, ] @@ -152,6 +157,7 @@ const StatefulTopNComponent: React.FC = ({ field={field as AlertsStackByField} filters={isActiveTimeline(scopeId ?? '') ? EMPTY_FILTERS : globalFilters} from={isActiveTimeline(scopeId ?? '') ? activeTimelineFrom : from} + dataView={dataView} dataViewSpec={dataViewSpec} options={options} paddingSize={paddingSize} diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.test.tsx index 949786a08da0a..08864ebd19fa1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.test.tsx @@ -6,14 +6,15 @@ */ import React from 'react'; -import { screen, render, waitFor, fireEvent } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { TestProviders, mockDataViewSpec } from '../../mock'; +import { mockDataViewSpec, TestProviders } from '../../mock'; import { allEvents, defaultOptions } from './helpers'; import type { Props as TopNProps } from './top_n'; import { TopN } from './top_n'; import { InputsModelId } from '../../store/inputs/constants'; +import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub'; jest.mock('../visualization_actions/visualization_embeddable'); @@ -105,6 +106,7 @@ describe('TopN', () => { field, filters: [], from: '2020-04-14T00:31:47.695Z', + dataView: createStubDataView({ spec: {} }), dataViewSpec: mockDataViewSpec, options: defaultOptions, query, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.tsx index 861d1f4a408b3..4f82fbd0a1d93 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/top_n/top_n.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { css } from '@emotion/react'; import type { Filter, Query } from '@kbn/es-query'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { DataView, DataViewSpec } from '@kbn/data-plugin/common'; import type { GlobalTimeArgs } from '../../containers/use_global_time'; import { EventsByDataset } from '../../../overview/components/events_by_dataset'; import { SignalsByCategory } from '../../../overview/components/signals_by_category'; @@ -52,6 +52,7 @@ export interface Props extends Pick = ({ filters, field, from, + dataView, dataViewSpec, options, paddingSize, @@ -123,6 +125,7 @@ const TopNComponent: React.FC = ({ filters={applicableFilters} from={from} headerChildren={headerChildren} + dataView={dataView} dataViewSpec={dataViewSpec} onlyField={field} paddingSize={paddingSize} diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx b/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx index 22a32892c2395..cde3ea0f05789 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.tsx @@ -48,12 +48,12 @@ export const useLensAttributes = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView } = useDataView(scopeId); + const { dataView: experimentalDataView } = useDataView(scopeId); const experimentalSelectedPatterns = useSelectedPatterns(scopeId); - const dataViewId = newDataViewPickerEnabled ? dataView?.id ?? '' : oldDataViewId; + const dataViewId = newDataViewPickerEnabled ? experimentalDataView.id ?? '' : oldDataViewId; const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length + ? !!experimentalDataView.matchedIndices?.length : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.test.ts b/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.test.ts index 98c59d415d447..22f32fc1e10a1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.test.ts @@ -7,8 +7,9 @@ import expect from '@kbn/expect'; import type { DataProvider } from '../../../../common/types/timeline'; -import { convertToBuildEsQuery, buildGlobalQuery } from '.'; +import { buildGlobalQuery, convertToBuildEsQuery } from '.'; import { mockDataViewSpec } from '../../mock'; +import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub'; describe('convertToBuildEsQuery', () => { /** @@ -60,6 +61,7 @@ describe('convertToBuildEsQuery', () => { it('should, by default, build a query where the `nested` fields syntax includes the `"ignore_unmapped":true` option', () => { const [converted, _] = convertToBuildEsQuery({ config, + dataView: createStubDataView({ spec: {} }), queries: queryWithNestedFields, dataViewSpec: mockDataViewSpec, filters, @@ -175,6 +177,7 @@ describe('convertToBuildEsQuery', () => { const [converted, _] = convertToBuildEsQuery({ config: configWithOverride, + dataView: createStubDataView({ spec: {} }), queries: queryWithNestedFields, dataViewSpec: mockDataViewSpec, filters, diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.ts b/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.ts index ac66e8f051b2e..ecc90b7f13985 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/lib/kuery/index.ts @@ -5,16 +5,16 @@ * 2.0. */ -import type { Filter, EsQueryConfig, Query, DataViewBase } from '@kbn/es-query'; +import type { DataViewBase, EsQueryConfig, Filter, Query } from '@kbn/es-query'; import { + buildEsQuery, + FilterStateStore, fromKueryExpression, toElasticsearchQuery, - FilterStateStore, - buildEsQuery, } from '@kbn/es-query'; import { get, isEmpty } from 'lodash/fp'; import memoizeOne from 'memoize-one'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { DataView, DataViewSpec } from '@kbn/data-plugin/common'; import { prepareKQLParam } from '../../../../common/utils/kql'; import type { BrowserFields } from '../../../../common/search_strategy'; import type { DataProvider, DataProvidersAnd } from '../../../../common/types'; @@ -30,7 +30,11 @@ export type PrimitiveOrArrayOfPrimitives = export interface CombineQueries { config: EsQueryConfig; dataProviders: DataProvider[]; + /** + * @deprecated Use `dataView` instead. Which accepts a DataView instance instead of a DataViewSpec. + */ dataViewSpec?: DataViewSpec; + dataView: DataView; browserFields: BrowserFields; filters: Filter[]; kqlQuery: Query; @@ -206,12 +210,17 @@ export const dataViewSpecToViewBase = (dataViewSpec?: DataViewSpec): DataViewBas export const convertToBuildEsQuery = ({ config, - dataViewSpec, + dataView, // New dataview prepended with feature flag to enable easy cleanup + dataViewSpec, // Account for the case where sourcerer is active, but this can just use dataView queries, filters, }: { config: EsQueryConfig; - dataViewSpec: DataViewSpec | undefined; + dataView: DataView; + /** + * @deprecated Use `dataView` instead. Which accepts a DataView instance instead of a DataViewSpec. + */ + dataViewSpec?: DataViewSpec; // Ignored but kept for type compatibility queries: Query[]; filters: Filter[]; }): [string, undefined] | [undefined, Error] => { @@ -219,7 +228,7 @@ export const convertToBuildEsQuery = ({ return [ JSON.stringify( buildEsQuery( - dataViewSpecToViewBase(dataViewSpec), + dataView ?? (dataViewSpecToViewBase(dataViewSpec) as DataView), queries, filters.filter((f) => f.meta.disabled === false), { @@ -246,6 +255,7 @@ export const combineQueries = ({ config, dataProviders = [], dataViewSpec, + dataView, browserFields, filters = [], kqlQuery, @@ -259,6 +269,7 @@ export const combineQueries = ({ config, queries: [kuery], dataViewSpec, + dataView, filters, }); @@ -287,6 +298,7 @@ export const combineQueries = ({ config, queries: [kuery], dataViewSpec, + dataView, filters, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/dashboards/pages/details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/dashboards/pages/details/index.tsx index 5bc2dc5af4624..da41aedc2279b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/dashboards/pages/details/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/dashboards/pages/details/index.tsx @@ -12,7 +12,6 @@ import { useParams } from 'react-router-dom'; import { pick } from 'lodash/fp'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { ViewMode } from '@kbn/presentation-publishing'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { SecurityPageName } from '../../../../common/constants'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { useCapabilities } from '../../../common/lib/kibana'; @@ -31,7 +30,6 @@ import { DashboardToolBar } from '../../components/dashboard_tool_bar'; import { useDashboardRenderer } from '../../hooks/use_dashboard_renderer'; import { DashboardTitle } from '../../components/dashboard_title'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; const dashboardViewFlexGroupStyle = { minHeight: `calc(100vh - 140px)` }; @@ -55,11 +53,6 @@ const DashboardViewComponent: React.FC = ({ const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); const { sourcererDataView: oldSourcererDataView } = useSourcererDataView(); - const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(); - - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const { show: canReadDashboard } = useCapabilities('dashboard_v2'); const errorState = useMemo( () => (canReadDashboard ? null : DashboardViewPromptState.NoReadPermission), @@ -77,7 +70,10 @@ const DashboardViewComponent: React.FC = ({ return ( <> - + = ({ ); const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(SourcererScopeName.detections); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.detections); const { addError, addSuccess, remove } = useAppToasts(); @@ -244,8 +243,11 @@ const ExecutionLogTableComponent: React.FC = ({ // Cache UUID field from data view as it can be expensive to iterate all data view fields const uuidDataViewField = useMemo( - () => sourcererDataView.fields?.[EXECUTION_UUID_FIELD_NAME], - [sourcererDataView] + () => + newDataViewPickerEnabled + ? experimentalDataView.fields?.getByName(EXECUTION_UUID_FIELD_NAME) + : oldSourcererDataView.fields?.[EXECUTION_UUID_FIELD_NAME], + [experimentalDataView.fields, newDataViewPickerEnabled, oldSourcererDataView.fields] ); // Callbacks @@ -311,7 +313,9 @@ const ExecutionLogTableComponent: React.FC = ({ const onFilterByExecutionIdCallback = useCallback( (executionId: string, executionStart: string) => { - const dataViewAsViewBase = dataViewSpecToViewBase(sourcererDataView); + const dataViewAsViewBase = newDataViewPickerEnabled + ? experimentalDataView + : dataViewSpecToViewBase(oldSourcererDataView); if ( uuidDataViewField != null && @@ -368,11 +372,13 @@ const ExecutionLogTableComponent: React.FC = ({ } }, [ + newDataViewPickerEnabled, + experimentalDataView, + oldSourcererDataView, uuidDataViewField, filters, query, timerange, - sourcererDataView, dispatch, filterManager, selectAlertsTab, diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index e2726358828e4..0311f74da1399 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -38,13 +38,12 @@ import { tableDefaults, TableId, } from '@kbn/securitysolution-data-table'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { PrebuiltRuleBaseVersionFlyoutContextProvider, usePrebuiltRuleBaseVersionContext, } from '../../../rule_management/components/rule_details/base_version_diff/base_version_context'; import { useGroupTakeActionsItems } from '../../../../detections/hooks/alerts_table/use_group_take_action_items'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; import { defaultGroupStatsAggregations, defaultGroupStatsRenderer, @@ -265,12 +264,7 @@ const RuleDetailsPageComponent: React.FC = ({ const { sourcererDataView: oldSourcererDataViewSpec, loading: oldIsLoadingIndexPattern } = useSourcererDataView(SourcererScopeName.detections); const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec: experimentalDataViewSpec, status } = useDataViewSpec( - SourcererScopeName.detections - ); - const sourcererDataViewSpec: DataViewSpec = newDataViewPickerEnabled - ? experimentalDataViewSpec - : oldSourcererDataViewSpec; + const { dataView: experimentalDataView, status } = useDataView(SourcererScopeName.detections); const isLoadingIndexPattern = newDataViewPickerEnabled ? status !== 'ready' : oldIsLoadingIndexPattern; @@ -647,7 +641,7 @@ const RuleDetailsPageComponent: React.FC = ({ @@ -818,7 +812,8 @@ const RuleDetailsPageComponent: React.FC = ({ , diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/table/table_section.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/table/table_section.tsx index da99131576e78..f19c6856553a1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/table/table_section.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/table/table_section.tsx @@ -88,7 +88,8 @@ export const TableSection = memo(({ dataView, packages, ruleResponse }: TableSec groupIdSelector(), []); const { options } = useDeepEqualSelector((state) => groupId(state, tableType)) ?? { @@ -80,9 +77,13 @@ const AdditionalToolbarControlsComponent = ({ [dispatch, tableType, trackGroupChange] ); - const fields = useMemo(() => { - return Object.values(sourcererDataView.fields || {}); - }, [sourcererDataView.fields]); + const fields = useMemo( + () => + experimentalDataView + ? experimentalDataView.fields.map((field) => field.spec) + : Object.values(oldSourcererDataView.fields || {}), + [experimentalDataView, oldSourcererDataView.fields] + ); const groupSelector = useGetGroupSelectorStateless({ groupingId: tableType, diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx index 527c0e7de2a09..52ec16492c5b4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx @@ -8,7 +8,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import type { Filter, Query } from '@kbn/es-query'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; +import type { DataViewSpec, DataView } from '@kbn/data-views-plugin/common'; import { type GroupOption, type GroupStatsItem, @@ -21,6 +21,7 @@ import { isEmpty, isEqual } from 'lodash/fp'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; import type { TableIdLiteral } from '@kbn/securitysolution-data-table'; import type { GetGroupStats, GroupingArgs, GroupPanelRenderer } from '@kbn/grouping/src'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import type { GroupTakeActionItems } from './types'; import type { AlertsGroupingAggregation } from './grouping_settings/types'; import { groupIdSelector } from '../../../common/store/grouping/selectors'; @@ -59,6 +60,10 @@ export interface AlertsTableComponentProps { * DataViewSpec object to use internally to fetch the data */ dataViewSpec: DataViewSpec; + /** + * DataView object to use internally to fetch the data. + */ + dataView?: DataView; defaultFilters?: Filter[]; /** * Default values to display in the group selection dropdown. @@ -135,7 +140,7 @@ const useStorage = (storage: Storage, tableId: string) => const GroupedAlertsTableComponent: React.FC = (props) => { const dispatch = useDispatch(); - + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { services: { storage, telemetry }, } = useKibana(); @@ -174,8 +179,24 @@ const GroupedAlertsTableComponent: React.FC = (props) ); const fields = useMemo( - () => Object.values(props.dataViewSpec.fields || {}), - [props.dataViewSpec] + () => + newDataViewPickerEnabled + ? props.dataView?.fields.map((field) => field.spec) || [] + : Object.values(props.dataViewSpec.fields || {}), + [newDataViewPickerEnabled, props.dataView?.fields, props.dataViewSpec.fields] + ); + + const runtimeMappings = useMemo( + () => + newDataViewPickerEnabled + ? (props.dataView?.getRuntimeMappings() as RunTimeMappings) + : (props.dataViewSpec?.runtimeFieldMap as RunTimeMappings), + [newDataViewPickerEnabled, props.dataView, props.dataViewSpec?.runtimeFieldMap] + ); + + const dataViewTitle = useMemo( + () => (newDataViewPickerEnabled ? props.dataView?.title : props.dataViewSpec.title), + [newDataViewPickerEnabled, props.dataView?.title, props.dataViewSpec.title] ); const groupingOptions = useMemo( @@ -336,18 +357,28 @@ const GroupedAlertsTableComponent: React.FC = (props) pageSize={pageSize[level] ?? DEFAULT_PAGE_SIZE} parentGroupingFilter={parentGroupingFilter} renderChildComponent={rcc} - runtimeMappings={props.dataViewSpec.runtimeFieldMap as RunTimeMappings} + runtimeMappings={runtimeMappings} selectedGroup={selectedGroup} setPageIndex={(newIndex: number) => setPageVar(newIndex, level, 'index')} setPageSize={(newSize: number) => setPageVar(newSize, level, 'size')} - signalIndexName={props.dataViewSpec.title} + signalIndexName={dataViewTitle} /> ); }, - [getGrouping, groupStatusAggregations, pageIndex, pageSize, props, selectedGroups, setPageVar] + [ + dataViewTitle, + getGrouping, + groupStatusAggregations, + pageIndex, + pageSize, + props, + runtimeMappings, + selectedGroups, + setPageVar, + ] ); - if (isEmpty(props.dataViewSpec.title)) { + if (isEmpty(dataViewTitle)) { return null; } diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx index 92b813621acbf..cd4a674605172 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/alerts_sub_grouping.tsx @@ -15,6 +15,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { DynamicGroupingProps } from '@kbn/grouping/src'; import { parseGroupingQuery } from '@kbn/grouping/src'; import type { TableIdLiteral } from '@kbn/securitysolution-data-table'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import type { GroupTakeActionItems } from './types'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import type { RunTimeMappings } from '../../../sourcerer/store/model'; @@ -33,7 +34,6 @@ import * as i18n from './translations'; import { useQueryAlerts } from '../../containers/detection_engine/alerts/use_query'; import { ALERTS_QUERY_NAMES } from '../../containers/detection_engine/alerts/constants'; import { getAlertsGroupingQuery } from './grouping_settings'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useBrowserFields } from '../../../data_view_manager/hooks/use_browser_fields'; const ALERTS_GROUPING_ID = 'alerts-grouping'; @@ -106,10 +106,10 @@ export const GroupedSubLevelComponent: React.FC = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec } = useDataViewSpec(SourcererScopeName.detections); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.detections); const experimentalBrowserFields = useBrowserFields(SourcererScopeName.detections); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; + const sourcererDataView = oldSourcererDataView; const browserFields = newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields; const getGlobalQuery = useCallback( @@ -119,6 +119,7 @@ export const GroupedSubLevelComponent: React.FC = ({ config: getEsQueryConfig(uiSettings), dataProviders: [], dataViewSpec: sourcererDataView, + dataView: experimentalDataView, browserFields, filters: [ ...defaultFilters, @@ -135,14 +136,15 @@ export const GroupedSubLevelComponent: React.FC = ({ }, [ browserFields, + sourcererDataView, + uiSettings, + experimentalDataView, defaultFilters, - from, globalFilters, - globalQuery, parentGroupingFilter, + from, to, - uiSettings, - sourcererDataView, + globalQuery, ] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 9a858155debfc..d2310d9ef2e4c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -20,7 +20,7 @@ import type { SetOptional } from 'type-fest'; import { noop } from 'lodash'; import type { Alert } from '@kbn/alerting-types'; import { AlertsTable } from '@kbn/response-ops-alerts-table'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { useAlertsContext } from './alerts_context'; import { useBulkActionsByTableType } from '../../hooks/trigger_actions_alert_table/use_bulk_actions'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; @@ -178,12 +178,16 @@ const DetectionEngineAlertsTableComponent: FC + newDataViewPickerEnabled + ? experimentalDataView.getRuntimeMappings() + : (oldSourcererDataView.runtimeFieldMap as RunTimeMappings), + [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataView] + ); - const sourcererDataView = newDataViewPickerEnabled - ? experimentalDataViewSpec - : oldSourcererDataView; const browserFields = newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields; const license = useLicense(); @@ -213,11 +217,12 @@ const DetectionEngineAlertsTableComponent: FC { - if (browserFields != null && sourcererDataView) { + if (browserFields != null && (oldSourcererDataView || experimentalDataView)) { return combineQueries({ config: getEsQueryConfig(uiSettings), dataProviders: [], - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, browserFields, filters: [...allFilters], kqlQuery: globalQuery, @@ -225,7 +230,14 @@ const DetectionEngineAlertsTableComponent: FC { + return newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) + : (oldSourcererDataViewSpec.runtimeFieldMap as RunTimeMappings); + }, [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataViewSpec.runtimeFieldMap]); + const dataViewId = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec.id ?? '' : oldDataViewId), - [experimentalDataViewSpec.id, newDataViewPickerEnabled, oldDataViewId] + () => (newDataViewPickerEnabled ? experimentalDataView.id ?? '' : oldDataViewId), + [experimentalDataView.id, newDataViewPickerEnabled, oldDataViewId] ); const browserFields = useMemo( () => (newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields), [experimentalBrowserFields, newDataViewPickerEnabled, oldBrowserFields] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] @@ -132,13 +133,20 @@ export const useAddBulkToTimelineAction = ({ return combineQueries({ config: esQueryConfig, dataProviders: [], - dataViewSpec, + dataViewSpec: oldSourcererDataViewSpec, + dataView: experimentalDataView, filters: combinedFilters, kqlQuery: { query: '', language: 'kuery' }, browserFields, kqlMode: 'filter', }); - }, [esQueryConfig, dataViewSpec, combinedFilters, browserFields]); + }, [ + esQueryConfig, + oldSourcererDataViewSpec, + experimentalDataView, + combinedFilters, + browserFields, + ]); const filterQuery = useMemo(() => { if (!combinedQuery) return ''; @@ -156,7 +164,7 @@ export const useAddBulkToTimelineAction = ({ sort: timelineQuerySortField, indexNames: selectedPatterns, filterQuery, - runtimeMappings: dataViewSpec.runtimeFieldMap as RunTimeMappings, + runtimeMappings, limit: Math.min(BULK_ADD_TO_TIMELINE_LIMIT, totalCount), timerangeKind: 'absolute', }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx index 427551700bf5d..3edfd3823a931 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.test.tsx @@ -73,7 +73,7 @@ describe('DetectionEngineFilters', () => { }, timeRange: { from: 'now-15m', to: 'now' }, onInit: jest.fn(), - dataViewSpec: { + dataView: { title: 'mock-title', fields: {}, }, @@ -99,7 +99,7 @@ describe('DetectionEngineFilters', () => { expect(container).toBeEmptyDOMElement(); }); - it('renders correctly when spaceId and dataViewSpec are defined', () => { + it('renders correctly when spaceId and dataView are defined', () => { const { container } = render(); expect(container).toBeInTheDocument(); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx index 57837db80eced..f8b12669986d7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx @@ -13,7 +13,7 @@ import type { AlertFilterControlsProps } from '@kbn/alerts-ui-shared/src/alert_f import { AlertFilterControls } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { useHistory } from 'react-router-dom'; import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { DataView, DataViewSpec } from '@kbn/data-plugin/common'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useKibana } from '../../../common/lib/kibana'; import { DEFAULT_DETECTION_PAGE_FILTERS } from '../../../../common/constants'; @@ -25,11 +25,11 @@ export type DetectionEngineFiltersProps = Pick< AlertFilterControlsProps, 'filters' | 'onFiltersChange' | 'query' | 'timeRange' | 'onInit' > & { - dataViewSpec?: DataViewSpec; + dataView?: DataView | DataViewSpec; }; export const DetectionEngineFilters = ({ - dataViewSpec: indexPattern, + dataView: indexPattern, ...props }: DetectionEngineFiltersProps) => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx index 4e71532089cf3..5046b5cd9d9a3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx @@ -57,13 +57,13 @@ export const useRuleFromTimeline = (setRuleQuery: SetRuleQuery): RuleFromTimelin const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); const experimentalBrowserFields = useBrowserFields(SourcererScopeName.timeline); - const { dataView } = useDataView(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; const browserFields = newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields; - const dataViewId = newDataViewPickerEnabled ? dataView?.id ?? '' : oldDataViewId; + const dataViewId = newDataViewPickerEnabled ? experimentalDataView?.id ?? '' : oldDataViewId; const isEql = useRef(false); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_cell_actions.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_cell_actions.tsx index 33f4665e673be..44ad35b4b7077 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_cell_actions.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_cell_actions.tsx @@ -41,7 +41,7 @@ export const useCellActionsOptions = ( } = context ?? {}; const oldGetFieldSpec = useGetFieldSpec(SourcererScopeName.detections); const oldDataViewId = useDataViewId(SourcererScopeName.detections); - const dataViewId = newDataViewPickerEnabled ? experimentalDataView?.id : oldDataViewId; + const dataViewId = newDataViewPickerEnabled ? experimentalDataView.id : oldDataViewId; const cellActionsMetadata = useMemo( () => ({ scopeId: tableId, dataViewId }), @@ -52,7 +52,7 @@ export const useCellActionsOptions = ( columns.map( (column) => (newDataViewPickerEnabled - ? experimentalDataView?.fields?.getByName(column.id)?.toSpec() + ? experimentalDataView.fields?.getByName(column.id)?.toSpec() : oldGetFieldSpec(column.id)) ?? { name: '', type: '', // When type is an empty string all cell actions are incompatible @@ -60,7 +60,7 @@ export const useCellActionsOptions = ( searchable: false, } ), - [columns, experimentalDataView?.fields, oldGetFieldSpec, newDataViewPickerEnabled] + [columns, experimentalDataView.fields, oldGetFieldSpec, newDataViewPickerEnabled] ); /** diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alerts/detection_engine.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alerts/detection_engine.tsx index 60412efb4afa3..b82de38d67a39 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alerts/detection_engine.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/alerts/detection_engine.tsx @@ -34,7 +34,7 @@ import { import { isEqual } from 'lodash'; import type { FilterGroupHandler } from '@kbn/alerts-ui-shared'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { useGroupTakeActionsItems } from '../../hooks/alerts_table/use_group_take_action_items'; import { defaultGroupingOptions, @@ -93,7 +93,6 @@ import type { Status } from '../../../../common/api/detection_engine'; import { GroupedAlertsTable } from '../../components/alerts_table/alerts_grouping'; import { DetectionEngineAlertsTable } from '../../components/alerts_table'; import type { AddFilterProps } from '../../components/alerts_kpis/common/types'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -159,14 +158,17 @@ const DetectionEnginePageComponent: React.FC = () const { sourcererDataView: oldSourcererDataViewSpec, loading: oldIsLoadingIndexPattern } = useSourcererDataView(SourcererScopeName.detections); const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec: experimentalDataViewSpec, status: dataViewSpecStatus } = useDataViewSpec( + const { dataView: experimentalDataView, status: experimentalDataViewStatus } = useDataView( SourcererScopeName.detections ); - const sourcererDataViewSpec: DataViewSpec = newDataViewPickerEnabled - ? experimentalDataViewSpec - : oldSourcererDataViewSpec; + const runtimeMappings = useMemo(() => { + return newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) ?? {} + : (oldSourcererDataViewSpec.runtimeFieldMap as RunTimeMappings) ?? {}; + }, [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataViewSpec.runtimeFieldMap]); + const isLoadingIndexPattern = newDataViewPickerEnabled - ? dataViewSpecStatus !== 'ready' + ? experimentalDataViewStatus !== 'ready' : oldIsLoadingIndexPattern; const { formatUrl } = useFormatUrl(SecurityPageName.rules); @@ -397,7 +399,7 @@ const DetectionEnginePageComponent: React.FC = () = () query={query} timeRange={pageFiltersTimerange} onInit={setDetectionPageFilterHandler} - dataViewSpec={sourcererDataViewSpec} + dataView={ + newDataViewPickerEnabled ? experimentalDataView : oldSourcererDataViewSpec + } /> = () alertsDefaultFilters={alertsDefaultFilters} isLoadingIndexPattern={isChartPanelLoading} query={query} - runtimeMappings={sourcererDataViewSpec.runtimeFieldMap as RunTimeMappings} + runtimeMappings={runtimeMappings} signalIndexName={signalIndexName} updateDateRangeCallback={updateDateRangeCallback} /> @@ -450,7 +454,8 @@ const DetectionEnginePageComponent: React.FC = () { toggleStatus: boolean; @@ -59,11 +57,8 @@ export const TopRiskScoreContributorsAlerts = ({ const { sourcererDataView: oldSourcererDataViewSpec } = useSourcererDataView( SourcererScopeName.detections ); - const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.detections); - const sourcererDataViewSpec: DataViewSpec = newDataViewPickerEnabled - ? experimentalDataViewSpec - : oldSourcererDataViewSpec; + + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.detections); const getGlobalFiltersQuerySelector = useMemo( () => inputsSelectors.globalFiltersQuerySelector(), @@ -148,7 +143,8 @@ export const TopRiskScoreContributorsAlerts = ({ { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { dataView, status } = useDataView(); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const indicesExist = useMemo( () => (newDataViewPickerEnabled ? !!dataView?.matchedIndices?.length : oldIndicesExist), [dataView?.matchedIndices?.length, newDataViewPickerEnabled, oldIndicesExist] @@ -70,7 +63,10 @@ const EntityAnalyticsComponent = () => { ) : ( <> - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/pages/entity_analytics_privileged_user_monitoring_page.tsx b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/pages/entity_analytics_privileged_user_monitoring_page.tsx index 8b31b1089ec6d..7bfd2362842cc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/pages/entity_analytics_privileged_user_monitoring_page.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/pages/entity_analytics_privileged_user_monitoring_page.tsx @@ -215,7 +215,7 @@ export const EntityAnalyticsPrivilegedUserMonitoringPage = () => { <> {state.type === 'dashboard' && ( - + )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx index 327db18136542..9414b0ca9ebe5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.test.tsx @@ -12,7 +12,6 @@ import useResizeObserver from 'use-resize-observer/polyfilled'; import { createMockStore, - mockDataViewSpec, mockGlobalState, mockIndexPattern, TestProviders, @@ -163,7 +162,6 @@ describe('body', () => { setQuery={jest.fn()} hostDetailsPagePath={hostDetailsPagePath} indexNames={[]} - dataViewSpec={mockDataViewSpec} type={HostsType.details} hostDetailsFilter={mockHostDetailsPageFilters} filterQuery={filterQuery} @@ -181,35 +179,6 @@ describe('body', () => { skip: false, startDate: '2020-07-07T08:20:18.966Z', type: 'details', - indexPattern: { - fields: { - '@timestamp': { searchable: true, type: 'date', aggregatable: true }, - '@version': { searchable: true, type: 'string', aggregatable: true }, - 'agent.ephemeral_id': { searchable: true, type: 'string', aggregatable: true }, - 'agent.hostname': { searchable: true, type: 'string', aggregatable: true }, - 'agent.id': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test1': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test2': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test3': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test4': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test5': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test6': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test7': { searchable: true, type: 'string', aggregatable: true }, - 'agent.test8': { searchable: true, type: 'string', aggregatable: true }, - 'host.name': { searchable: true, type: 'string', aggregatable: true }, - 'nestedField.firstAttributes': { - aggregatable: false, - searchable: true, - type: 'string', - }, - 'nestedField.secondAttributes': { - aggregatable: false, - searchable: true, - type: 'string', - }, - }, - title: 'filebeat-*,auditbeat-*,packetbeat-*', - }, hostName: 'host-1', ...(path === 'events' && { additionalFilters: mockHostDetailsPageFilters }), }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx index 228e1a9663e27..1edb02de0b0af 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/hosts/pages/details/details_tabs.tsx @@ -25,14 +25,7 @@ import { } from '../navigation'; export const HostDetailsTabs = React.memo( - ({ - detailName, - filterQuery, - indexNames, - dataViewSpec: indexPattern, - hostDetailsPagePath, - hostDetailsFilter, - }) => { + ({ detailName, filterQuery, indexNames, hostDetailsPagePath, hostDetailsFilter }) => { const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime(); const tabProps = { @@ -43,7 +36,6 @@ export const HostDetailsTabs = React.memo( setQuery, startDate: from, type: HostsType.details, - indexPattern, indexNames, hostName: detailName, }; 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 53c5644189b22..3ae34c421f6be 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 @@ -78,7 +78,6 @@ import { ResponderActionButton } from '../../../../common/components/endpoint/re import { useRefetchOverviewPageRiskScore } from '../../../../entity_analytics/api/hooks/use_refetch_overview_page_risk_score'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns'; import { PageLoader } from '../../../../common/components/page_loader'; @@ -133,13 +132,11 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(DataViewManagerScopeName.explore); - const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const { dataView: experimentalDataView, status } = useDataView(DataViewManagerScopeName.explore); const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length + ? !!experimentalDataView.matchedIndices?.length : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns @@ -157,7 +154,9 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta try { return [ buildEsQuery( - dataViewSpecToViewBase(sourcererDataView), + newDataViewPickerEnabled + ? experimentalDataView + : dataViewSpecToViewBase(oldSourcererDataView), [query], [...hostDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) @@ -166,7 +165,15 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta } catch (e) { return [undefined, e]; } - }, [sourcererDataView, query, hostDetailsPageFilters, globalFilters, uiSettings]); + }, [ + newDataViewPickerEnabled, + experimentalDataView, + oldSourcererDataView, + query, + hostDetailsPageFilters, + globalFilters, + uiSettings, + ]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -226,7 +233,10 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta <> - + = ({ detailName, hostDeta setQuery={setQuery} filterQuery={stringifiedAdditionalFilters} hostDetailsPagePath={hostDetailsPagePath} - dataViewSpec={sourcererDataView} /> 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 b72acf68712bf..66e8dfa55287c 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 @@ -54,7 +54,6 @@ import { EmptyPrompt } from '../../../common/components/empty_prompt'; import { fieldNameExistsFilter } from '../../../common/components/visualization_actions/utils'; import { useLicense } from '../../../common/hooks/use_license'; import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns'; import { PageLoader } from '../../../common/components/page_loader'; @@ -112,12 +111,12 @@ const HostsComponent = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(DataViewManagerScopeName.explore); - const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const { dataView: experimentalDataView, status } = useDataView(DataViewManagerScopeName.explore); const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled + ? experimentalDataView.hasMatchedIndices() + : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -126,21 +125,23 @@ const HostsComponent = () => { () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, queries: [query], filters: globalFilters, }), - [globalFilters, sourcererDataView, uiSettings, query] + [uiSettings, oldSourcererDataView, experimentalDataView, query, globalFilters] ); const [tabsFilterQuery] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, queries: [query], filters: tabsFilters, }), - [sourcererDataView, query, tabsFilters, uiSettings] + [uiSettings, oldSourcererDataView, experimentalDataView, query, tabsFilters] ); useInvalidFilterQuery({ @@ -188,7 +189,10 @@ const HostsComponent = () => { - + 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 8b83c68dcbff1..310ff3c22fcd0 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 @@ -64,7 +64,6 @@ import { } from '../../../../common/components/cell_actions'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns'; const NetworkDetailsManage = manageQuery(IpOverview); @@ -120,12 +119,12 @@ const NetworkDetailsComponent: React.FC = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(DataViewManagerScopeName.explore); - const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const { dataView: experimentalDataView, status } = useDataView(DataViewManagerScopeName.explore); const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled + ? experimentalDataView.hasMatchedIndices() + : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -137,7 +136,9 @@ const NetworkDetailsComponent: React.FC = () => { try { return [ buildEsQuery( - dataViewSpecToViewBase(sourcererDataView), + newDataViewPickerEnabled + ? experimentalDataView + : dataViewSpecToViewBase(oldSourcererDataView), [query], [...networkDetailsFilter, ...globalFilters], getEsQueryConfig(uiSettings) @@ -146,7 +147,15 @@ const NetworkDetailsComponent: React.FC = () => { } catch (e) { return [undefined, e]; } - }, [globalFilters, networkDetailsFilter, query, sourcererDataView, uiSettings]); + }, [ + experimentalDataView, + globalFilters, + networkDetailsFilter, + newDataViewPickerEnabled, + oldSourcererDataView, + query, + uiSettings, + ]); const additionalFilters = useMemo( () => (rawFilteredQuery ? [rawFilteredQuery] : []), @@ -190,8 +199,10 @@ const NetworkDetailsComponent: React.FC = () => { ); const indexPattern = useMemo(() => { - return dataViewSpecToViewBase(sourcererDataView); - }, [sourcererDataView]); + return newDataViewPickerEnabled + ? experimentalDataView || { title: '', fields: [] } + : dataViewSpecToViewBase(oldSourcererDataView); + }, [experimentalDataView, newDataViewPickerEnabled, oldSourcererDataView]); if (newDataViewPickerEnabled && status === 'pristine') { return ; @@ -202,7 +213,10 @@ const NetworkDetailsComponent: React.FC = () => { {indicesExist ? ( <> - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/countries_query_tab_body.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/countries_query_tab_body.tsx index cd19ab18956c5..4badd8e7dca24 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/countries_query_tab_body.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/countries_query_tab_body.tsx @@ -22,7 +22,6 @@ export const CountriesQueryTabBody = ({ filterQuery, flowTarget, indexNames, - indexPattern, ip, setQuery, skip, diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx index 6e49c65454239..fa8210bbe65f2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/network_routes.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; import { EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { TableId } from '@kbn/securitysolution-data-table'; -import { dataViewSpecToViewBase } from '../../../../common/lib/kuery'; import { FlowTargetSourceDest } from '../../../../../common/search_strategy/security_solution/network'; import { @@ -31,9 +30,7 @@ import { NetworkRouteType } from './types'; import { NETWORK_PATH } from '../../../../../common/constants'; export const NetworkRoutes = React.memo( - ({ type, to, filterQuery, isInitializing, from, dataViewSpec, indexNames, setQuery }) => { - const index = useMemo(() => dataViewSpecToViewBase(dataViewSpec), [dataViewSpec]); - + ({ type, to, filterQuery, isInitializing, from, indexNames, setQuery }) => { const networkAnomaliesFilterQuery = { bool: { should: [ @@ -64,7 +61,6 @@ export const NetworkRoutes = React.memo( const tabProps = { ...commonProps, - indexPattern: index, }; const anomaliesProps = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/types.ts b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/types.ts index 339ad2fc71acc..242de09af8646 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/network/pages/navigation/types.ts @@ -7,8 +7,6 @@ import type { Optional } from 'utility-types'; -import type { DataViewBase } from '@kbn/es-query'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; import type { ESTermQuery } from '../../../../../common/typed_json'; import type { NavTab } from '../../../../common/components/navigation/types'; @@ -30,7 +28,6 @@ export type NetworkComponentQueryProps = QueryTabBodyProps; export type IPsQueryTabBodyProps = QueryTabBodyProps & { flowTarget: FlowTargetSourceDest; - indexPattern: DataViewBase; }; export type FTQueryTabBodyProps = QueryTabBodyProps & { @@ -46,7 +43,6 @@ export type HttpQueryTabBodyProps = QueryTabBodyProps; export type NetworkRoutesProps = GlobalTimeArgs & { type: networkModel.NetworkType; filterQuery?: string | ESTermQuery; - dataViewSpec: DataViewSpec; indexNames: string[]; }; 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 503fdd62d937f..14bfb921cf108 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 @@ -47,7 +47,6 @@ import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_ import { sourceOrDestinationIpExistsFilter } from '../../../common/components/visualization_actions/utils'; import { EmptyPrompt } from '../../../common/components/empty_prompt'; import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns'; import { PageLoader } from '../../../common/components/page_loader'; @@ -79,6 +78,7 @@ const NetworkComponent = React.memo( const { tabName } = useParams<{ tabName: string }>(); const canUseMaps = kibana.services.application.capabilities.maps_v2.show; + const { uiSettings } = kibana.services; const tabsFilters = useMemo(() => { if (tabName === NetworkRouteType.events) { @@ -96,10 +96,8 @@ const NetworkComponent = React.memo( const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); 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.hasMatchedIndices() : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns @@ -129,19 +127,29 @@ const NetworkComponent = React.memo( [containerElement, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable] ); - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config: getEsQueryConfig(kibana.services.uiSettings), - dataViewSpec: sourcererDataView, - queries: [query], - filters: globalFilters, - }); + const [filterQuery, kqlError] = useMemo( + () => + convertToBuildEsQuery({ + config: getEsQueryConfig(uiSettings), + dataViewSpec: oldSourcererDataView, + dataView, + queries: [query], + filters: globalFilters, + }), + [uiSettings, oldSourcererDataView, dataView, query, globalFilters] + ); - const [tabsFilterQuery] = convertToBuildEsQuery({ - config: getEsQueryConfig(kibana.services.uiSettings), - dataViewSpec: sourcererDataView, - queries: [query], - filters: tabsFilters, - }); + const [tabsFilterQuery] = useMemo( + () => + convertToBuildEsQuery({ + config: getEsQueryConfig(uiSettings), + dataViewSpec: oldSourcererDataView, + dataView, + queries: [query], + filters: tabsFilters, + }), + [uiSettings, oldSourcererDataView, dataView, query, tabsFilters] + ); useInvalidFilterQuery({ id: ID, filterQuery, kqlError, query, startDate: from, endDate: to }); @@ -155,7 +163,10 @@ const NetworkComponent = React.memo( - + @@ -193,7 +204,7 @@ const NetworkComponent = React.memo( - {capabilitiesFetched && !isInitializing && sourcererDataView ? ( + {capabilitiesFetched && !isInitializing && oldSourcererDataView ? ( <> @@ -205,7 +216,6 @@ const NetworkComponent = React.memo( filterQuery={tabsFilterQuery} from={from} isInitializing={isInitializing} - dataViewSpec={sourcererDataView} indexNames={selectedPatterns} setQuery={setQuery} type={networkModel.NetworkType.page} 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 a6fe5b480db28..f047f8e27b39a 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 @@ -75,7 +75,6 @@ import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml import { EmptyPrompt } from '../../../../common/components/empty_prompt'; import { useRefetchOverviewPageRiskScore } from '../../../../entity_analytics/api/hooks/use_refetch_overview_page_risk_score'; import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns'; import { PageLoader } from '../../../../common/components/page_loader'; @@ -119,12 +118,12 @@ const UsersDetailsComponent: React.FC = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(DataViewManagerScopeName.explore); - const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const { dataView: experimentalDataView, status } = useDataView(DataViewManagerScopeName.explore); const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled + ? experimentalDataView.hasMatchedIndices() + : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -133,7 +132,9 @@ const UsersDetailsComponent: React.FC = ({ try { return [ buildEsQuery( - dataViewSpecToViewBase(sourcererDataView), + newDataViewPickerEnabled + ? experimentalDataView + : dataViewSpecToViewBase(oldSourcererDataView), [query], [...usersDetailsPageFilters, ...globalFilters], getEsQueryConfig(uiSettings) @@ -142,7 +143,15 @@ const UsersDetailsComponent: React.FC = ({ } catch (e) { return [undefined, e]; } - }, [globalFilters, sourcererDataView, query, uiSettings, usersDetailsPageFilters]); + }, [ + experimentalDataView, + globalFilters, + newDataViewPickerEnabled, + oldSourcererDataView, + query, + uiSettings, + usersDetailsPageFilters, + ]); const stringifiedAdditionalFilters = JSON.stringify(rawFilteredQuery); useInvalidFilterQuery({ @@ -223,7 +232,10 @@ const UsersDetailsComponent: React.FC = ({ <> - + @@ -311,7 +323,6 @@ const UsersDetailsComponent: React.FC = ({ filterQuery={stringifiedAdditionalFilters} from={from} indexNames={selectedPatterns} - dataViewSpec={sourcererDataView} isInitializing={isInitializing} userDetailFilter={usersDetailsPageFilters} setQuery={setQuery} diff --git a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/types.ts b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/types.ts index 8b531af663990..65ee492c584c6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/explore/users/pages/details/types.ts @@ -7,7 +7,6 @@ import type { ActionCreator } from 'typescript-fsa'; -import { type DataViewSpec } from '@kbn/data-plugin/common'; import type { Filter, Query } from '@kbn/es-query'; import type { UsersQueryProps } from '../types'; @@ -48,6 +47,5 @@ export type UsersDetailsTabsProps = UserBodyComponentDispatchProps & indexNames: string[]; userDetailFilter: Filter[]; filterQuery?: string; - dataViewSpec?: DataViewSpec; type: usersModel.UsersType; }; 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 df6d4e4ab7a95..76d2017de127d 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 @@ -53,7 +53,6 @@ import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_ca import { EmptyPrompt } from '../../../common/components/empty_prompt'; import { userNameExistsFilter } from './details/helpers'; import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns'; import { PageLoader } from '../../../common/components/page_loader'; @@ -113,12 +112,12 @@ const UsersComponent = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(DataViewManagerScopeName.explore); - const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); + const { dataView: experimentalDataView, status } = useDataView(DataViewManagerScopeName.explore); const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; - const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist; + const indicesExist = newDataViewPickerEnabled + ? experimentalDataView.hasMatchedIndices() + : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; @@ -127,21 +126,23 @@ const UsersComponent = () => { () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, queries: [query], filters: globalFilters, }), - [globalFilters, sourcererDataView, uiSettings, query] + [uiSettings, oldSourcererDataView, experimentalDataView, query, globalFilters] ); const [tabsFilterQuery] = useMemo( () => convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, queries: [query], filters: tabsFilters, }), - [sourcererDataView, query, tabsFilters, uiSettings] + [experimentalDataView, oldSourcererDataView, query, tabsFilters, uiSettings] ); useInvalidFilterQuery({ @@ -190,7 +191,10 @@ const UsersComponent = () => { - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/network_details/components/network_details.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/network_details/components/network_details.tsx index 78fb04370a911..fd196c323796b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/network_details/components/network_details.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/network_details/components/network_details.tsx @@ -31,7 +31,6 @@ import { EmptyPrompt } from '../../../common/components/empty_prompt'; import type { NarrowDateRange } from '../../../common/components/ml/types'; import { SourcererScopeName } from '../../../sourcerer/store/model'; import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns'; export interface NetworkDetailsProps { @@ -86,24 +85,27 @@ export const NetworkDetails = ({ ip, flowTarget }: NetworkDetailsProps) => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); + const { dataView: experimentalDataView, status } = useDataView(); const experimentalSelectedPatterns = useSelectedPatterns(); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length + ? !!experimentalDataView.matchedIndices?.length : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config: getEsQueryConfig(uiSettings), - dataViewSpec: sourcererDataView, - queries: [query], - filters, - }); + const [filterQuery, kqlError] = useMemo( + () => + convertToBuildEsQuery({ + config: getEsQueryConfig(uiSettings), + dataViewSpec: oldSourcererDataView, + dataView: experimentalDataView, + queries: [query], + filters, + }), + [uiSettings, oldSourcererDataView, experimentalDataView, query, filters] + ); const [loading, { id, networkDetails }] = useNetworkDetails({ skip: isInitializing || filterQuery === undefined, diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.test.tsx index f061ead1073ae..86012ea4bd03f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.test.tsx @@ -13,6 +13,7 @@ import { OverviewHost } from '../overview_host'; import { OverviewNetwork } from '../overview_network'; import { EventCounts } from '.'; +import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub'; jest.mock('../../../common/components/link_to'); jest.mock('../overview_host', () => ({ @@ -36,6 +37,7 @@ describe('EventCounts', () => { from, indexNames: [], dataViewSpec: mockDataViewSpec, + dataView: createStubDataView({ spec: {} }), setQuery: jest.fn(), to, query: { diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.tsx index 3f20d3365537f..a6e8ae70f1b1e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -9,6 +9,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; import type { Filter, Query } from '@kbn/es-query'; +import type { DataView } from '@kbn/data-plugin/common'; import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; import { ID as OverviewHostQueryId } from '../../containers/overview_host'; import { OverviewHost } from '../overview_host'; @@ -27,6 +28,7 @@ interface Props extends Pick { filters: Filter[]; indexNames: string[]; dataViewSpec?: DataViewSpec; + dataView: DataView; query: Query; } @@ -35,6 +37,7 @@ const EventCountsComponent: React.FC = ({ from, indexNames, dataViewSpec, + dataView, query, setQuery, to, @@ -46,10 +49,11 @@ const EventCountsComponent: React.FC = ({ convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), dataViewSpec, + dataView, queries: [query], filters: [...filters, ...fieldNameExistsFilter(SecurityPageName.hosts)], }), - [dataViewSpec, filters, query, uiSettings] + [dataViewSpec, filters, dataView, query, uiSettings] ); const [networkFilterQuery] = useMemo( @@ -57,10 +61,11 @@ const EventCountsComponent: React.FC = ({ convertToBuildEsQuery({ config: getEsQueryConfig(uiSettings), dataViewSpec, + dataView, queries: [query], filters: [...filters, ...sourceOrDestinationIpExistsFilter], }), - [uiSettings, dataViewSpec, query, filters] + [uiSettings, dataViewSpec, dataView, query, filters] ); useInvalidFilterQuery({ diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx index a37e6adda8ad5..2c871649d9bbd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx @@ -7,14 +7,14 @@ import { Position } from '@elastic/charts'; import numeral from '@elastic/numeral'; -import React, { useEffect, useMemo, useCallback } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import type { Filter, Query } from '@kbn/es-query'; import styled from '@emotion/styled'; import { EuiButton } from '@elastic/eui'; -import type { DataViewSpec } from '@kbn/data-plugin/common'; +import type { DataView, DataViewSpec } from '@kbn/data-plugin/common'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; -import { DEFAULT_NUMBER_FORMAT, APP_UI_ID } from '../../../../common/constants'; +import { APP_UI_ID, DEFAULT_NUMBER_FORMAT } from '../../../../common/constants'; import { SHOWING, UNIT } from '../../../common/components/events_viewer/translations'; import { getTabsOnHostsUrl } from '../../../common/components/link_to/redirect_to_hosts'; import { MatrixHistogram } from '../../../common/components/matrix_histogram'; @@ -25,8 +25,8 @@ import type { import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { useKibana, useUiSetting$ } from '../../../common/lib/kibana'; import { - eventsStackByOptions, eventsHistogramConfig, + eventsStackByOptions, NO_BREAKDOWN_STACK_BY_VALUE, } from '../../../common/components/events_tab/histogram_configurations'; import { HostsTableType } from '../../../explore/hosts/store/model'; @@ -48,6 +48,7 @@ interface Props extends Pick { filters: Filter[]; headerChildren?: React.ReactNode; dataViewSpec?: DataViewSpec; + dataView: DataView; onlyField?: string; paddingSize?: 's' | 'm' | 'l' | 'none'; query: Query; @@ -78,6 +79,7 @@ const EventsByDatasetComponent: React.FC = ({ from, headerChildren, dataViewSpec, + dataView, onlyField, paddingSize, query, @@ -131,12 +133,13 @@ const EventsByDatasetComponent: React.FC = ({ return convertToBuildEsQuery({ config: getEsQueryConfig(kibana.services.uiSettings), dataViewSpec, + dataView, queries: [query], filters, }); } return [filterQueryFromProps]; - }, [filterQueryFromProps, kibana.services.uiSettings, dataViewSpec, query, filters]); + }, [filterQueryFromProps, kibana.services.uiSettings, dataViewSpec, dataView, query, filters]); useInvalidFilterQuery({ id: uniqueQueryId, diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/pages/detection_response.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/pages/detection_response.tsx index b7c256b57fe4a..c38d5ceff32cf 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/pages/detection_response.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/pages/detection_response.tsx @@ -33,7 +33,6 @@ import { FiltersGlobal } from '../../common/components/filters_global'; import { useGlobalFilterQuery } from '../../common/hooks/use_global_filter_query'; import { useKibana } from '../../common/lib/kibana'; import { useDataView } from '../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../data_view_manager/hooks/use_data_view_spec'; import { PageLoader } from '../../common/components/page_loader'; const DetectionResponseComponent = () => { @@ -47,12 +46,10 @@ const DetectionResponseComponent = () => { } = useSourcererDataView(); const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); + const { dataView: experimentalDataView, status } = useDataView(); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length + ? !!experimentalDataView.matchedIndices?.length : oldIndicesExist; const isSourcererLoading = newDataViewPickerEnabled ? status !== 'ready' : oldIsSourcererLoading; @@ -77,7 +74,10 @@ const DetectionResponseComponent = () => { {indicesExist ? ( <> - + diff --git a/x-pack/solutions/security/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/solutions/security/plugins/security_solution/public/overview/pages/overview.tsx index fa9e88efe27fd..d5dcfea83625e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/overview/pages/overview.tsx @@ -40,7 +40,6 @@ import { useUserPrivileges } from '../../common/components/user_privileges'; import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { EmptyPrompt } from '../../common/components/empty_prompt'; import { useSelectedPatterns } from '../../data_view_manager/hooks/use_selected_patterns'; -import { useDataViewSpec } from '../../data_view_manager/hooks/use_data_view_spec'; import { useDataView } from '../../data_view_manager/hooks/use_data_view'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { PageLoader } from '../../common/components/page_loader'; @@ -63,13 +62,11 @@ const OverviewComponent = () => { const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataView, status } = useDataView(); - const { dataViewSpec } = useDataViewSpec(); + const { dataView: experimentalDataView, status } = useDataView(); const experimentalSelectedPatterns = useSelectedPatterns(); - const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView; const indicesExist = newDataViewPickerEnabled - ? !!dataView?.matchedIndices?.length + ? !!experimentalDataView.matchedIndices?.length : oldIndicesExist; const selectedPatterns = newDataViewPickerEnabled ? experimentalSelectedPatterns @@ -109,7 +106,10 @@ const OverviewComponent = () => { {indicesExist ? ( <> - + @@ -140,7 +140,8 @@ const OverviewComponent = () => { deleteQuery={deleteQuery} filters={filters} from={from} - dataViewSpec={sourcererDataView} + dataViewSpec={oldSourcererDataView} + dataView={experimentalDataView} query={query} queryType="overview" to={to} @@ -152,7 +153,8 @@ const OverviewComponent = () => { filters={filters} from={from} indexNames={selectedPatterns} - dataViewSpec={sourcererDataView} + dataViewSpec={oldSourcererDataView} + dataView={experimentalDataView} query={query} setQuery={setQuery} to={to} diff --git a/x-pack/solutions/security/plugins/security_solution/public/resolver/view/controls/sourcerer_selection.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/resolver/view/controls/sourcerer_selection.test.tsx index 55140a8e53d3f..909c5c65bf025 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/resolver/view/controls/sourcerer_selection.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/resolver/view/controls/sourcerer_selection.test.tsx @@ -11,12 +11,13 @@ import { useLocation } from 'react-router-dom'; import { SourcererButton } from './sourcerer_selection'; import { useKibana } from '../../../common/lib/kibana'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { createMockStore, mockGlobalState } from '../../../common/mock'; import { TestProviders } from '../../../common/mock/test_providers'; import { DATA_VIEW_PICKER_TEST_ID } from '../../../data_view_manager/components/data_view_picker/constants'; import { ALERTS_PATH } from '../../../../common/constants'; import { DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID } from '../../../data_view_manager/constants'; +import type { DataView } from '@kbn/data-views-plugin/common'; jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); @@ -32,8 +33,8 @@ jest.mock('react-redux', () => { jest.mock('../../../common/lib/kibana'); jest.mock('../../../common/hooks/use_experimental_features'); -jest.mock('../../../data_view_manager/hooks/use_data_view_spec', () => ({ - useDataViewSpec: jest.fn(), +jest.mock('../../../data_view_manager/hooks/use_data_view', () => ({ + useDataView: jest.fn(), })); jest.mock('../../../data_view_manager/hooks/use_select_data_view', () => ({ useSelectDataView: jest.fn().mockReturnValue(jest.fn()), @@ -45,11 +46,11 @@ describe('SourcererButton', () => { beforeEach(() => { jest.clearAllMocks(); (useLocation as jest.Mock).mockReturnValue({ pathname: ALERTS_PATH }); - jest.mocked(useDataViewSpec).mockReturnValue({ - dataViewSpec: { + jest.mocked(useDataView).mockReturnValue({ + dataView: { id: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID, name: 'Default Security Data View', - }, + } as DataView, status: 'ready', }); jest.mocked(useKibana).mockReturnValue({ diff --git a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx index 52b5ca9717e8d..2471aa620db4b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/sourcerer/components/use_get_sourcerer_data_view.tsx @@ -10,6 +10,7 @@ import { DataView } from '@kbn/data-views-plugin/public'; import { useSourcererDataView } from '../containers'; import { useKibana } from '../../common/lib/kibana'; import type { SourcererScopeName } from '../store/model'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; export interface UseGetScopedSourcererDataViewArgs { sourcererScope: SourcererScopeName; @@ -27,15 +28,16 @@ export const useGetScopedSourcererDataView = ({ const { services: { fieldFormats }, } = useKibana(); + const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const { sourcererDataView } = useSourcererDataView(sourcererScope); const dataView = useMemo(() => { - if (Object.keys(sourcererDataView).length) { + if (!newDataViewPickerEnabled && Object.keys(sourcererDataView).length) { return new DataView({ spec: sourcererDataView, fieldFormats }); } else { return undefined; } - }, [sourcererDataView, fieldFormats]); + }, [newDataViewPickerEnabled, sourcererDataView, fieldFormats]); return dataView; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/modal/header/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/modal/header/index.tsx index da204ce3a5cbf..ba4ed94918c2d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/modal/header/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/modal/header/index.tsx @@ -15,14 +15,13 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; +import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import styled from 'styled-components'; +import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; - -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; import { NewTimelineButton } from '../actions/new_timeline_button'; import { OpenTimelineButton } from '../actions/open_timeline_button'; import { APP_ID } from '../../../../../common'; @@ -79,18 +78,12 @@ export const TimelineModalHeader = React.memo( const { browserFields: sourcererBrowserFields, sourcererDataView: oldSourcererDataViewSpec } = useSourcererDataView(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec( - DataViewManagerScopeName.timeline - ); + const { dataView: experimentalDataView } = useDataView(DataViewManagerScopeName.timeline); const experimentalBrowserFields = useBrowserFields(DataViewManagerScopeName.timeline); const browserFields = useMemo( () => (newDataViewPickerEnabled ? experimentalBrowserFields : sourcererBrowserFields), [experimentalBrowserFields, newDataViewPickerEnabled, sourcererBrowserFields] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const { cases, uiSettings } = useKibana().services; const esQueryConfig = useMemo(() => getEsQueryConfig(uiSettings), [uiSettings]); @@ -109,13 +102,23 @@ export const TimelineModalHeader = React.memo( combineQueries({ config: esQueryConfig, dataProviders, - dataViewSpec, + dataViewSpec: oldSourcererDataViewSpec, + dataView: experimentalDataView, browserFields, filters: filters ? filters : [], kqlQuery: kqlQueryObj, kqlMode, }), - [browserFields, dataProviders, esQueryConfig, filters, kqlMode, kqlQueryObj, dataViewSpec] + [ + browserFields, + dataProviders, + esQueryConfig, + experimentalDataView, + filters, + kqlMode, + kqlQueryObj, + oldSourcererDataViewSpec, + ] ); const isInspectDisabled = !isDataInTimeline || combinedQueries?.filterQuery === undefined; diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/index.tsx index 0fdbb03484b54..3a2be081fede7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/index.tsx @@ -58,7 +58,7 @@ import { useStartTransaction } from '../../../common/lib/apm/use_start_transacti import { TIMELINE_ACTIONS } from '../../../common/lib/apm/user_actions'; import { defaultUdtHeaders } from '../timeline/body/column_headers/default_headers'; import { timelineDefaults } from '../../store/defaults'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; interface OwnProps { /** Displays open timeline in modal */ @@ -164,12 +164,12 @@ export const StatefulOpenTimelineComponent = React.memo( useSourcererDataView(SourcererScopeName.timeline); const { newDataViewPickerEnabled } = useEnableExperimental(); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); const dataViewId = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec?.id || '' : oldDataViewId), - [experimentalDataViewSpec?.id, newDataViewPickerEnabled, oldDataViewId] + () => (newDataViewPickerEnabled ? experimentalDataView.id || '' : oldDataViewId), + [experimentalDataView.id, newDataViewPickerEnabled, oldDataViewId] ); const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/index.tsx index af02a1b6691a6..4e7bbe66fa968 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/index.tsx @@ -32,7 +32,7 @@ import { EXIT_FULL_SCREEN_CLASS_NAME } from '../../../common/components/exit_ful import { useResolveConflict } from '../../../common/hooks/use_resolve_conflict'; import { defaultUdtHeaders } from './body/column_headers/default_headers'; import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns'; -import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../data_view_manager/hooks/use_data_view'; import { TimelineContext } from './context'; const TimelineBody = styled.div` @@ -102,12 +102,11 @@ const StatefulTimelineComponent: React.FC = ({ const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const selectedDataViewId = useMemo( - () => - newDataViewPickerEnabled ? experimentalDataViewSpec?.id ?? '' : selectedDataViewIdSourcerer, - [experimentalDataViewSpec?.id, newDataViewPickerEnabled, selectedDataViewIdSourcerer] + () => (newDataViewPickerEnabled ? experimentalDataView.id ?? '' : selectedDataViewIdSourcerer), + [experimentalDataView.id, newDataViewPickerEnabled, selectedDataViewIdSourcerer] ); const selectedPatterns = useMemo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx index d6b49f94d32ae..50633afb5316e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx @@ -8,7 +8,7 @@ import React, { useMemo } from 'react'; import { isEmpty, pick } from 'lodash/fp'; import { useSelector } from 'react-redux'; -import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; +import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { TimerangeInput } from '@kbn/timelines-plugin/common'; import { EuiPanel } from '@elastic/eui'; import { useEnableExperimental } from '../../../../common/hooks/use_experimental_features'; @@ -29,7 +29,7 @@ import { startSelector, } from '../../../../common/components/super_date_picker/selectors'; import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; interface KpiExpandedProps { timelineId: string; @@ -38,7 +38,7 @@ interface KpiExpandedProps { export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { const { newDataViewPickerEnabled } = useEnableExperimental(); const experimentalBrowserFields = useBrowserFields(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); const { @@ -51,10 +51,6 @@ export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { () => (newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields), [experimentalBrowserFields, newDataViewPickerEnabled, oldBrowserFields] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] @@ -106,13 +102,23 @@ export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { combineQueries({ config: esQueryConfig, dataProviders, - dataViewSpec, + dataViewSpec: oldSourcererDataViewSpec, + dataView: experimentalDataView, browserFields, filters: filters ? filters : [], kqlQuery, kqlMode, }), - [browserFields, dataProviders, esQueryConfig, filters, dataViewSpec, kqlMode, kqlQuery] + [ + esQueryConfig, + dataProviders, + oldSourcererDataViewSpec, + experimentalDataView, + browserFields, + filters, + kqlQuery, + kqlMode, + ] ); const isBlankTimeline: boolean = useMemo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx index 6345568d21a41..f64073fc1b558 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx @@ -11,9 +11,8 @@ import { EuiOutsideClickDetector } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import { css } from '@emotion/css'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { useEnableExperimental } from '../../../../../common/hooks/use_experimental_features'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import type { EqlOptions } from '../../../../../../common/search_strategy'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; @@ -71,19 +70,13 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) const { newDataViewPickerEnabled } = useEnableExperimental(); - const { dataViewSpec: experimentalDataViewSpec, status } = useDataViewSpec( - SourcererScopeName.timeline - ); + const { dataView: experimentalDataView, status } = useDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); const indexPatternsLoading = useMemo( () => (newDataViewPickerEnabled ? status !== 'ready' : oldIndexPatternsLoading), [newDataViewPickerEnabled, oldIndexPatternsLoading, status] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] @@ -178,17 +171,19 @@ export const EqlQueryBarTimeline = memo(({ timelineId }: { timelineId: string }) } }, [getFields, selectedPatterns]); - const dataView = useMemo( - () => ({ - ...dataViewSpec, - title: dataViewSpec.title ?? '', - fields: Object.values(dataViewSpec.fields || {}), - }), - [dataViewSpec] - ); + const dataView = useMemo(() => { + return newDataViewPickerEnabled + ? experimentalDataView || { title: '', fields: [] } + : { + title: oldSourcererDataViewSpec.title ?? '', + fields: Object.values(oldSourcererDataViewSpec.fields || {}), + }; + }, [experimentalDataView, newDataViewPickerEnabled, oldSourcererDataViewSpec]); /* Force casting `dataViewSpec` to `DataViewBase` is required since EqlQueryEdit - accepts DataViewBase but `useSourcererDataView()` returns `DataViewSpec`. + accepts DataViewBase but `useSourcererDataView()` returns `DataViewSpec`. Since + the DataView class inherits from DataViewBase, it is safe to use directly and the prioir statement is only valid + while sourcerer is not migrated to the new data view picker. When using `UseField` with `EqlQueryBar` such casting isn't required by TS since `UseField` component props are types as `Record`. */ diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx index 58cdd9c444145..98a679fda16e3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx @@ -13,10 +13,8 @@ import type { Filter, Query } from '@kbn/es-query'; import { FilterStateStore } from '@kbn/es-query'; import type { FilterManager, SavedQuery, SavedQueryTimeFilter } from '@kbn/data-plugin/public'; import styled from '@emotion/styled'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { useEnableExperimental } from '../../../../common/hooks/use_experimental_features'; import { useDataView } from '../../../../data_view_manager/hooks/use_data_view'; -import { useDataViewSpec } from '../../../../data_view_manager/hooks/use_data_view_spec'; import { InputsModelId } from '../../../../common/store/inputs/constants'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; @@ -121,17 +119,16 @@ export const QueryBarTimeline = memo( const { newDataViewPickerEnabled } = useEnableExperimental(); const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const experimentalBrowserFields = useBrowserFields(SourcererScopeName.timeline); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] + const dataViewBase = useMemo( + () => dataViewSpecToViewBase(oldSourcererDataViewSpec), + [oldSourcererDataViewSpec] ); - const dataViewBase = useMemo(() => dataViewSpecToViewBase(dataViewSpec), [dataViewSpec]); + const dataView = useMemo( - () => - newDataViewPickerEnabled && experimentalDataView ? experimentalDataView : dataViewBase, + () => (newDataViewPickerEnabled ? experimentalDataView : dataViewBase), [newDataViewPickerEnabled, experimentalDataView, dataViewBase] ); @@ -148,7 +145,7 @@ export const QueryBarTimeline = memo( const queryBarFilters = useMemo(() => getNonDropAreaFilters(filters), [filters]); const [dataProvidersDsl, setDataProvidersDsl] = useState( - convertKueryToElasticSearchQuery(buildGlobalQuery(dataProviders, browserFields), dataViewBase) + convertKueryToElasticSearchQuery(buildGlobalQuery(dataProviders, browserFields), dataView) ); const savedQueryServices = useSavedQueryServices(); @@ -162,11 +159,11 @@ export const QueryBarTimeline = memo( kind, expression, }, - serializedQuery: convertKueryToElasticSearchQuery(expression, dataViewBase), + serializedQuery: convertKueryToElasticSearchQuery(expression, dataView), }, }) ), - [dispatch, dataViewBase, timelineId] + [dispatch, dataView, timelineId] ); useEffect(() => { @@ -178,12 +175,9 @@ export const QueryBarTimeline = memo( useEffect(() => { setDataProvidersDsl( - convertKueryToElasticSearchQuery( - buildGlobalQuery(dataProviders, browserFields), - dataViewBase - ) + convertKueryToElasticSearchQuery(buildGlobalQuery(dataProviders, browserFields), dataView) ); - }, [dataProviders, browserFields, dataViewBase]); + }, [dataProviders, browserFields, dataView]); useEffect(() => { if (fromStr != null && toStr != null) { diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index 1fc2bb64a1cb6..0814b486e4fa7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -16,7 +16,6 @@ import { InPortal } from 'react-reverse-portal'; import { DataLoadingState } from '@kbn/unified-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { useKibana } from '../../../../../common/lib/kibana'; @@ -49,7 +48,7 @@ import { useNotesInFlyout } from '../../properties/use_notes_in_flyout'; import { NotesFlyout } from '../../properties/notes_flyout'; import { DocumentEventTypes, NotesEventTypes } from '../../../../../common/lib/telemetry'; import { TimelineRefetch } from '../../refetch_timeline'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useSelectedPatterns } from '../../../../../data_view_manager/hooks/use_selected_patterns'; export type Props = TimelineTabCommonProps & PropsFromRedux; @@ -88,11 +87,9 @@ export const EqlTabContentComponent: React.FC = ({ sourcererDataView: oldSourcererDataViewSpec, } = useSourcererDataView(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec, status } = useDataViewSpec( - SourcererScopeName.timeline - ); + const { dataView: experimentalDataView, status } = useDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); - const experimentalDataViewId = experimentalDataViewSpec.id ?? null; + const experimentalDataViewId = experimentalDataView.id ?? null; const dataViewId = useMemo( () => (newDataViewPickerEnabled ? experimentalDataViewId : oldDataViewId), @@ -102,10 +99,13 @@ export const EqlTabContentComponent: React.FC = ({ () => (newDataViewPickerEnabled ? status !== 'ready' : oldSourcererLoading), [newDataViewPickerEnabled, oldSourcererLoading, status] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); + + const runtimeMappings = useMemo(() => { + return newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) + : (oldSourcererDataViewSpec.runtimeFieldMap as RunTimeMappings); + }, [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataViewSpec.runtimeFieldMap]); + const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] @@ -144,7 +144,7 @@ export const EqlTabContentComponent: React.FC = ({ indexNames: selectedPatterns, language: 'eql', limit: sampleSize, - runtimeMappings: dataViewSpec.runtimeFieldMap as RunTimeMappings, + runtimeMappings, skip: !canQueryTimeline(), startDate: start, timerangeKind, diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/esql/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/esql/index.tsx index 2447bb787ce46..0781530c490d7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/esql/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/esql/index.tsx @@ -20,7 +20,7 @@ import { useDispatch } from 'react-redux'; import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { APP_STATE_URL_KEY } from '@kbn/discover-plugin/common'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { updateSavedSearchId } from '../../../../store/actions'; import { useDiscoverInTimelineContext } from '../../../../../common/components/discover_in_timeline/use_discover_in_timeline_context'; import { useKibana } from '../../../../../common/lib/kibana'; @@ -63,17 +63,12 @@ export const DiscoverTabContent: FC = ({ timelineId }) const dispatch = useDispatch(); const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled'); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.detections); + const { status: dataViewStatus } = useDataView(SourcererScopeName.detections); const { dataViewId } = useSourcererDataView(SourcererScopeName.detections); const [oldDataViewSpec, setDataViewSpec] = useState(); - const dataViewSpec: DataViewSpec | undefined = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldDataViewSpec] - ); - const [discoverTimerange, setDiscoverTimerange] = useState(); const discoverAppStateSubscription = useRef(); @@ -83,9 +78,9 @@ export const DiscoverTabContent: FC = ({ timelineId }) // TODO: (DV_PICKER) should not be here, used to make discover container work I suppose useEffect(() => { - if (!dataViewId) return; + if (!dataViewId || newDataViewPickerEnabled) return; dataViewService.get(dataViewId).then((dv) => setDataViewSpec(dv?.toSpec?.())); - }, [dataViewId, dataViewService]); + }, [dataViewId, dataViewService, newDataViewPickerEnabled]); const { discoverStateContainer, @@ -290,8 +285,9 @@ export const DiscoverTabContent: FC = ({ timelineId }) const DiscoverContainer = discover.DiscoverContainer; - // TODO: (DV_PICKER) this should not work like that - const isLoading = !dataViewSpec; + const isLoading = newDataViewPickerEnabled + ? dataViewStatus === 'loading' || dataViewStatus === 'pristine' + : !oldDataViewSpec; // TODO: (DV_PICKER) this should not work like that return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx index efee515b081a5..f34e6c099ca57 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx @@ -13,9 +13,8 @@ import deepEqual from 'fast-deep-equal'; import type { EuiDataGridControlColumn } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; -import type { DataViewSpec } from '@kbn/data-views-plugin/common'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useSelectedPatterns } from '../../../../../data_view_manager/hooks/use_selected_patterns'; import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { @@ -94,19 +93,24 @@ export const PinnedTabContentComponent: React.FC = ({ } = useSourcererDataView(SourcererScopeName.timeline); const experimentalSelectedPatterns = useSelectedPatterns(SourcererScopeName.timeline); - const { dataViewSpec: experimentalDataViewSpec } = useDataViewSpec(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); const selectedPatterns = useMemo( () => (newDataViewPickerEnabled ? experimentalSelectedPatterns : oldSelectedPatterns), [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); + const dataViewId = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec.id ?? '' : oldDataViewId), - [experimentalDataViewSpec.id, newDataViewPickerEnabled, oldDataViewId] + () => (newDataViewPickerEnabled ? experimentalDataView.id ?? '' : oldDataViewId), + [experimentalDataView.id, newDataViewPickerEnabled, oldDataViewId] + ); + + const runtimeMappings = useMemo( + () => + newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) + : (oldSourcererDataViewSpec?.runtimeFieldMap as RunTimeMappings), + [experimentalDataView, newDataViewPickerEnabled, oldSourcererDataViewSpec] ); const filterQuery = useMemo(() => { @@ -175,7 +179,7 @@ export const PinnedTabContentComponent: React.FC = ({ fields: timelineQueryFields, limit: itemsPerPage, filterQuery, - runtimeMappings: dataViewSpec.runtimeFieldMap as RunTimeMappings, + runtimeMappings, skip: filterQuery === '', startDate: '', sort: timelineQuerySortField, diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/events_count.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/events_count.tsx index 8b7cae36d54f9..2a984a7703e4c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/events_count.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/events_count.tsx @@ -12,6 +12,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; import { EuiLoadingSpinner } from '@elastic/eui'; import { DataLoadingState } from '@kbn/unified-data-table'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { useTimelineDataFilters } from '../../../../containers/use_timeline_data_filters'; import { useInvalidFilterQuery } from '../../../../../common/hooks/use_invalid_filter_query'; @@ -95,6 +96,7 @@ export const TimelineQueryTabEventsCountComponent: React.FC<{ timelineId: string selectedPatterns, sourcererDataView, } = useSourcererDataView(SourcererScopeName.timeline); + const { dataView: experimentalDataView } = useDataView(SourcererScopeName.timeline); /* * `pageIndex` needs to be maintained for each table in each tab independently * and consequently it cannot be the part of common redux state @@ -117,12 +119,22 @@ export const TimelineQueryTabEventsCountComponent: React.FC<{ timelineId: string config: esQueryConfig, dataProviders, dataViewSpec: sourcererDataView, + dataView: experimentalDataView, browserFields, filters, kqlQuery, kqlMode, }); - }, [esQueryConfig, dataProviders, sourcererDataView, browserFields, filters, kqlQuery, kqlMode]); + }, [ + esQueryConfig, + dataProviders, + sourcererDataView, + experimentalDataView, + browserFields, + filters, + kqlQuery, + kqlMode, + ]); useInvalidFilterQuery({ id: timelineId, diff --git a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx index 8990af034bbac..c6c3829790c93 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx @@ -11,13 +11,13 @@ import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import type { EuiDataGridControlColumn } from '@elastic/eui'; -import { type DataViewSpec, getEsQueryConfig } from '@kbn/data-plugin/common'; +import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { DataLoadingState } from '@kbn/unified-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; +import { useDataView } from '../../../../../data_view_manager/hooks/use_data_view'; import { useSelectedPatterns } from '../../../../../data_view_manager/hooks/use_selected_patterns'; import { useBrowserFields } from '../../../../../data_view_manager/hooks/use_browser_fields'; -import { useDataViewSpec } from '../../../../../data_view_manager/hooks/use_data_view_spec'; import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { DocumentDetailsLeftPanelKey, @@ -71,13 +71,11 @@ export const QueryTabContentComponent: React.FC = ({ end, filters, timelineId, - isLive, itemsPerPage, itemsPerPageOptions, kqlMode, kqlQueryExpression, kqlQueryLanguage, - renderCellValue, rowRenderers, show, showCallOutUnauthorizedMsg, @@ -91,7 +89,7 @@ export const QueryTabContentComponent: React.FC = ({ const dispatch = useDispatch(); const { newDataViewPickerEnabled } = useEnableExperimental(); - const { dataViewSpec: experimentalDataViewSpec, status: sourcererStatus } = useDataViewSpec( + const { dataView: experimentalDataView, status: sourcererStatus } = useDataView( SourcererScopeName.timeline ); const experimentalBrowserFields = useBrowserFields(SourcererScopeName.timeline); @@ -111,10 +109,6 @@ export const QueryTabContentComponent: React.FC = ({ () => (newDataViewPickerEnabled ? sourcererStatus !== 'ready' : oldLoadingSourcerer), [newDataViewPickerEnabled, oldLoadingSourcerer, sourcererStatus] ); - const dataViewSpec: DataViewSpec = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec : oldSourcererDataViewSpec), - [experimentalDataViewSpec, newDataViewPickerEnabled, oldSourcererDataViewSpec] - ); const browserFields = useMemo( () => (newDataViewPickerEnabled ? experimentalBrowserFields : oldBrowserFields), [experimentalBrowserFields, newDataViewPickerEnabled, oldBrowserFields] @@ -124,8 +118,8 @@ export const QueryTabContentComponent: React.FC = ({ [experimentalSelectedPatterns, newDataViewPickerEnabled, oldSelectedPatterns] ); const dataViewId = useMemo( - () => (newDataViewPickerEnabled ? experimentalDataViewSpec.id ?? '' : oldDataViewId), - [experimentalDataViewSpec.id, newDataViewPickerEnabled, oldDataViewId] + () => (newDataViewPickerEnabled ? experimentalDataView.id ?? '' : oldDataViewId), + [experimentalDataView.id, newDataViewPickerEnabled, oldDataViewId] ); /* @@ -158,17 +152,33 @@ export const QueryTabContentComponent: React.FC = ({ [kqlQueryExpression, kqlQueryLanguage] ); + const runtimeMappings = useMemo(() => { + return newDataViewPickerEnabled + ? (experimentalDataView.getRuntimeMappings() as RunTimeMappings) + : (oldSourcererDataViewSpec.runtimeFieldMap as RunTimeMappings); + }, [newDataViewPickerEnabled, experimentalDataView, oldSourcererDataViewSpec.runtimeFieldMap]); + const combinedQueries = useMemo(() => { return combineQueries({ config: esQueryConfig, dataProviders, - dataViewSpec, + dataViewSpec: oldSourcererDataViewSpec, + dataView: experimentalDataView, browserFields, filters, kqlQuery, kqlMode, }); - }, [esQueryConfig, dataProviders, dataViewSpec, browserFields, filters, kqlQuery, kqlMode]); + }, [ + esQueryConfig, + dataProviders, + oldSourcererDataViewSpec, + experimentalDataView, + browserFields, + filters, + kqlQuery, + kqlMode, + ]); useInvalidFilterQuery({ id: timelineId, @@ -218,7 +228,7 @@ export const QueryTabContentComponent: React.FC = ({ indexNames: selectedPatterns, language: kqlQuery.language, limit: sampleSize, - runtimeMappings: dataViewSpec.runtimeFieldMap as RunTimeMappings, + runtimeMappings, skip: !canQueryTimeline, sort: timelineQuerySortField, startDate: start, @@ -473,7 +483,6 @@ const makeMapStateToProps = () => { timelineId, pinnedEventIds, eventIdToNoteIds, - isLive: input.policy.kind === 'interval', itemsPerPage, itemsPerPageOptions, kqlMode, @@ -501,7 +510,6 @@ const QueryTabContent = connector( compareQueryProps(prevProps, nextProps) && prevProps.activeTab === nextProps.activeTab && isTimerangeSame(prevProps, nextProps) && - prevProps.isLive === nextProps.isLive && prevProps.itemsPerPage === nextProps.itemsPerPage && prevProps.show === nextProps.show && prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg &&