Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const BUTTON_ADD_DATA = i18n.translate('xpack.securitySolution.globalHeader.butt
* right hand side of the Kibana global header
*/
export const GlobalHeader = React.memo(() => {
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');
const portalNode = useMemo(() => createHtmlPortalNode(), []);
const {
theme,
Expand All @@ -58,7 +59,7 @@ export const GlobalHeader = React.memo(() => {
(state) => (getTimeline(state, TimelineId.active) ?? timelineDefaults).show
);

const sourcererScope = getScopeFromPath(pathname);
const sourcererScope = getScopeFromPath(pathname, newDataViewPickerEnabled);
const showSourcerer = showSourcererByPath(pathname);
const dashboardViewPath = isDashboardViewPath(pathname);

Expand All @@ -85,8 +86,6 @@ export const GlobalHeader = React.memo(() => {
}
}, [portalNode, setHeaderActionMenu, theme, kibanaServiceI18n, dashboardViewPath]);

const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

const dataViewPicker = newDataViewPickerEnabled ? (
<DataViewPicker
scope={sourcererScope}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

const { pathname } = useLocation();
const sourcererScope = getScopeFromPath(pathname);
const { browserFields: oldBrowserFields } = useInitSourcerer(sourcererScope);
const { browserFields: experimentalBrowserFields } = useBrowserFields(sourcererScope);
const { browserFields: oldBrowserFields } = useInitSourcerer(getScopeFromPath(pathname, false));
const { browserFields: experimentalBrowserFields } = useBrowserFields(
getScopeFromPath(pathname, newDataViewPickerEnabled)
);

useRestoreDataViewManagerStateFromURL(useInitDataViewManager(), sourcererScope);
useRestoreDataViewManagerStateFromURL(
useInitDataViewManager(),
getScopeFromPath(pathname, newDataViewPickerEnabled)
);

useUrlState();
useUpdateBrowserTitle();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> =
}) => {
let ACTION_BUTTON_COUNT = MAX_ACTION_BUTTON_COUNT;

const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

const dispatch = useDispatch();
const { globalFullScreen } = useGlobalFullScreen();
const [defaultNumberFormat] = useUiSetting$<string>(DEFAULT_NUMBER_FORMAT);
Expand Down Expand Up @@ -191,6 +193,9 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> =
filterQuery={filterQuery}
{...(showExternalAlerts ? alertsHistogramConfig : eventsHistogramConfig)}
subtitle={getHistogramSubtitle}
sourcererScopeId={
newDataViewPickerEnabled ? SourcererScopeName.explore : SourcererScopeName.default
}
/>
)}
<StatefulEventsViewer
Expand All @@ -201,7 +206,9 @@ const EventsQueryTabBodyComponent: React.FC<EventsQueryTabBodyComponentProps> =
leadingControlColumns={leadingControlColumns}
renderCellValue={DefaultCellRenderer}
rowRenderers={defaultRowRenderers}
sourcererScope={SourcererScopeName.default}
sourcererScope={
newDataViewPickerEnabled ? SourcererScopeName.explore : SourcererScopeName.default
}
tableId={tableId}
unit={showExternalAlerts ? i18n.EXTERNAL_ALERTS_UNIT : i18n.EVENTS_UNIT}
defaultModel={defaultModel}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ const VisualizationEmbeddableComponent: React.FC<VisualizationEmbeddableProps> =
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');
const { dataView } = useDataView(lensProps.scopeId);

const indicesExist = newDataViewPickerEnabled
? Boolean(dataView?.matchedIndices?.length)
: oldIndicesExist;
const indicesExist = newDataViewPickerEnabled ? dataView.hasMatchedIndices() : oldIndicesExist;

const memorizedTimerange = useRef(lensProps.timerange);
const getGlobalQuery = useMemo(() => inputsSelectors.globalQueryByIdSelector(), []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,16 @@ export const mockGlobalState: State = {
true
),
},
[SourcererScopeName.explore]: {
...mockSourcererState.sourcererScopes[SourcererScopeName.default],
selectedDataViewId: mockSourcererState.defaultDataView.id,
selectedPatterns: getScopePatternListSelection(
mockSourcererState.defaultDataView,
SourcererScopeName.default,
mockSourcererState.signalIndexName,
true
),
},
},
},
globalUrlParam: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useDataView } from './use_data_view';
import { browserFieldsManager } from '../utils/security_browser_fields_manager';
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';

const emptyFields = {};

export const useBrowserFields = (
scope: DataViewManagerScopeName = DataViewManagerScopeName.default,
/**
Expand All @@ -25,8 +27,8 @@ export const useBrowserFields = (
const activeDataView = newDataViewPickerEnabled ? dataView : oldDataView;

return useMemo(() => {
if (!activeDataView) {
return {};
if (!activeDataView?.id) {
return emptyFields;
}

const { browserFields } = browserFieldsManager.getBrowserFields(activeDataView, scope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const useInitDataViewManager = () => {
DataViewManagerScopeName.timeline,
DataViewManagerScopeName.detections,
DataViewManagerScopeName.analyzer,
DataViewManagerScopeName.explore,
].map((scope) =>
createDataViewSelectedListener({
scope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { type SelectDataViewAsyncPayload } from '../redux/actions';

// TODO: remove this in cleanup phase Remove deprecated sourcerer code https://github.com/elastic/security-team/issues/12665
export const useSyncSourcererUrlState = (
scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default
scopeId:
| SourcererScopeName.default
| SourcererScopeName.explore
| SourcererScopeName.detections = SourcererScopeName.default
) => {
const scopeDataViewId = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId);
Expand Down Expand Up @@ -82,7 +85,10 @@ export const useSyncSourcererUrlState = (
*/
export const useRestoreDataViewManagerStateFromURL = (
initDataViewPickerWithSelection: (initialSelection: SelectDataViewAsyncPayload[]) => void,
scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default
scopeId:
| SourcererScopeName.default
| SourcererScopeName.explore
| SourcererScopeName.detections = SourcererScopeName.default
) => {
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const mockedState: RootState = {
dataViewId: null,
status: 'pristine',
},
explore: {
dataViewId: null,
status: 'pristine',
},
shared: {
adhocDataViews: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const createDataViewSelectedListener = (dependencies: {
// This is required to compute browserFields later.
// If the view is not returned here, it will be fetched further down this file, and that
// should return the full data view.
if (isEmpty(cachedDataView?.fields)) {
if (cachedDataView === cachedPersistedDataView && isEmpty(cachedDataView?.fields)) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const mockDataViewsService = {
const http = {} as unknown as CoreStart['http'];
const application = {} as unknown as CoreStart['application'];
const uiSettings = {} as unknown as CoreStart['uiSettings'];
const spaces = {} as unknown as SpacesPluginStart;
const spaces = { getActiveSpace: async () => ({ id: 'default' }) } as unknown as SpacesPluginStart;

const mockDispatch = jest.fn();
const mockGetState = jest.fn(() => {
Expand All @@ -45,6 +45,7 @@ const mockGetState = jest.fn(() => {
state.dataViewManager.detections = structuredClone(state.dataViewManager.default);
state.dataViewManager.timeline = structuredClone(state.dataViewManager.default);
state.dataViewManager.analyzer = structuredClone(state.dataViewManager.default);
state.dataViewManager.explore = structuredClone(state.dataViewManager.default);

return state;
});
Expand All @@ -59,19 +60,20 @@ describe('createInitListener', () => {

beforeEach(() => {
jest.clearAllMocks();

jest.mocked(createDefaultDataView).mockResolvedValue({
defaultDataView: { id: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID, title: '' },
alertDataView: { id: DEFAULT_ALERT_DATA_VIEW_ID, title: '' },
kibanaDataViews: [],
} as unknown as Awaited<ReturnType<typeof createDefaultDataView>>);

listener = createInitListener({
dataViews: mockDataViewsService,
http,
application,
uiSettings,
spaces,
});

jest.mocked(createDefaultDataView).mockResolvedValue({
defaultDataView: { id: DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID },
alertDataView: { id: DEFAULT_ALERT_DATA_VIEW_ID },
kibanaDataViews: [],
} as unknown as Awaited<ReturnType<typeof createDefaultDataView>>);
});

it('should load the data views and dispatch further actions', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { sharedDataViewManagerSlice } from '../slices';
import { DataViewManagerScopeName } from '../../constants';
import { selectDataViewAsync } from '../actions';
import { createDefaultDataView } from '../../utils/create_default_data_view';
import { createExploreDataView } from '../../utils/create_explore_data_view';

/**
* Creates a Redux listener for initializing the Data View Manager state.
Expand Down Expand Up @@ -46,9 +47,7 @@ export const createInitListener = (dependencies: {
listenerApi: ListenerEffectAPI<RootState, Dispatch<AnyAction>>
) => {
try {
// Initialize default security data view first
// Note: this is subject to change, as we might want to add specific data view just for alerts

// Initialize default data views first
const { defaultDataView, alertDataView } = await createDefaultDataView({
dataViewService: dependencies.dataViews,
uiSettings: dependencies.uiSettings,
Expand All @@ -57,6 +56,17 @@ export const createInitListener = (dependencies: {
http: dependencies.http,
});

const exploreDataView = await createExploreDataView(
{
dataViews: dependencies.dataViews,
spaces: dependencies.spaces,
},
defaultDataView.title.split(','),
alertDataView.title
);

listenerApi.dispatch(sharedDataViewManagerSlice.actions.addDataView(exploreDataView));

// NOTE: This is later used in the data view manager drop-down selector
const dataViews = await dependencies.dataViews.getAllDataViewLazy();
const dataViewSpecs = await Promise.all(dataViews.map((dataView) => dataView.toSpec()));
Expand All @@ -81,25 +91,35 @@ export const createInitListener = (dependencies: {
DataViewManagerScopeName.analyzer,
DataViewManagerScopeName.timeline,
DataViewManagerScopeName.default,
DataViewManagerScopeName.explore,
]
// NOTE: only init default data view for slices that are not initialized yet
.filter((scope) => !listenerApi.getState().dataViewManager[scope].dataViewId)
.forEach((scope) => {
if (scope === DataViewManagerScopeName.detections) {
listenerApi.dispatch(
return listenerApi.dispatch(
selectDataViewAsync({
id: alertDataView.id,
scope,
})
);
} else {
listenerApi.dispatch(
}

if (scope === DataViewManagerScopeName.explore) {
return listenerApi.dispatch(
selectDataViewAsync({
id: defaultDataView.id,
id: exploreDataView.id,
scope,
})
);
}

listenerApi.dispatch(
selectDataViewAsync({
id: defaultDataView.id,
scope,
})
);
});

// NOTE: if there is a list of data views to preload other than default one (eg. coming in from the url storage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const REGISTERED_SCOPES = [
DataViewManagerScopeName.timeline,
DataViewManagerScopeName.detections,
DataViewManagerScopeName.analyzer,
DataViewManagerScopeName.explore,
] as const;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { DataViewsServicePublic, DataView } from '@kbn/data-views-plugin/public';
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';

export const createExploreDataView = async (
dependencies: {
dataViews: DataViewsServicePublic;
spaces: SpacesPluginStart;
},
defaultDataViewPatterns: string[],
alertsDataViewPattern: string
): Promise<DataView> => {
const exploreDataViewPattern = defaultDataViewPatterns
.filter((pattern) => pattern !== alertsDataViewPattern)
.join();

return dependencies.dataViews.create({
id: `explore-data-view-${(await dependencies.spaces.getActiveSpace()).id}`,
name: 'Explore Data View',
title: exploreDataViewPattern,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
*/
import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui';
import React from 'react';
import { DataViewManagerScopeName } from '../../../data_view_manager/constants';
import { FlexItem, StatValue } from './utils';
import { VisualizationEmbeddable } from '../../../common/components/visualization_actions/visualization_embeddable';
import type { FieldConfigs } from './types';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';

export interface MetricEmbeddableProps {
fields: FieldConfigs[];
Expand All @@ -25,6 +27,8 @@ const MetricEmbeddableComponent = ({
inspectTitle,
timerange,
}: MetricEmbeddableProps) => {
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

return (
<EuiFlexGroup gutterSize="none" className="metricEmbeddable">
{fields.map((field) => (
Expand All @@ -51,6 +55,11 @@ const MetricEmbeddableComponent = ({
lensAttributes={field.lensAttributes}
timerange={timerange}
inspectTitle={inspectTitle}
scopeId={
newDataViewPickerEnabled
? DataViewManagerScopeName.explore
: DataViewManagerScopeName.default
}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useDispatch } from 'react-redux';
import type { Filter } from '@kbn/es-query';
import { buildEsQuery } from '@kbn/es-query';
import { getEsQueryConfig } from '@kbn/data-plugin/common';
import { DataViewManagerScopeName } from '../../../../data_view_manager/constants';
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
import type { NarrowDateRange } from '../../../../common/components/ml/types';
import { dataViewSpecToViewBase } from '../../../../common/lib/kuery';
Expand Down Expand Up @@ -132,9 +133,9 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({ detailName, hostDeta

const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');

const { dataView, status } = useDataView();
const { dataViewSpec } = useDataViewSpec();
const experimentalSelectedPatterns = useSelectedPatterns();
const { dataView, status } = useDataView(DataViewManagerScopeName.explore);
const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore);
const experimentalSelectedPatterns = useSelectedPatterns(DataViewManagerScopeName.explore);

const sourcererDataView = newDataViewPickerEnabled ? dataViewSpec : oldSourcererDataView;
const indicesExist = newDataViewPickerEnabled
Expand Down Expand Up @@ -283,7 +284,7 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({ detailName, hostDeta
hostName={detailName}
indexNames={selectedPatterns}
jobNameById={jobNameById}
scopeId={SourcererScopeName.default}
scopeId={SourcererScopeName.explore}
/>
)}
</AnomalyTableProvider>
Expand Down
Loading