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 @@ -86,6 +86,7 @@ export const useInitDataViewManager = () => {
uiSettings: services.uiSettings,
application: services.application,
spaces: services.spaces,
storage: services.storage,
});

dispatch(addListener(dataViewsLoadingListener));
Expand All @@ -101,6 +102,7 @@ export const useInitDataViewManager = () => {
createDataViewSelectedListener({
scope,
dataViews: services.dataViews,
storage: services.storage,
})
);

Expand All @@ -123,6 +125,7 @@ export const useInitDataViewManager = () => {
services.dataViews,
services.http,
services.spaces,
services.storage,
services.uiSettings,
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { AnyAction, Dispatch, ListenerEffectAPI } from '@reduxjs/toolkit';
import type { RootState } from '../reducer';
import { DataViewManagerScopeName, DEFAULT_SECURITY_SOLUTION_DATA_VIEW_ID } from '../../constants';
import { DEFAULT_ALERT_DATA_VIEW_ID } from '../../../../common/constants';
import type { Storage } from '@kbn/kibana-utils-plugin/public';

const mockDataViewsService = {
getDataViewLazy: jest.fn(),
Expand Down Expand Up @@ -79,6 +80,12 @@ const mockedState: RootState = {

const mockDispatch = jest.fn();
const mockGetState = jest.fn(() => mockedState);
const mockStorage = {
set: jest.fn(),
get: jest.fn(),
remove: jest.fn(),
clear: jest.fn(),
} as unknown as Storage;

const mockListenerApi = {
dispatch: mockDispatch,
Expand All @@ -95,6 +102,7 @@ describe('createDataViewSelectedListener', () => {
listener = createDataViewSelectedListener({
dataViews: mockDataViewsService,
scope: DataViewManagerScopeName.default,
storage: mockStorage,
});
});

Expand Down Expand Up @@ -165,4 +173,51 @@ describe('createDataViewSelectedListener', () => {
})
);
});

describe('analyzer scope storage', () => {
it('should store data view ID in storage when scope is analyzer', async () => {
const analyzerListener = createDataViewSelectedListener({
dataViews: mockDataViewsService,
scope: DataViewManagerScopeName.analyzer,
storage: mockStorage,
});

await analyzerListener.effect(
selectDataViewAsync({ id: 'adhoc_test-*', scope: DataViewManagerScopeName.analyzer }),
mockListenerApi
);

expect(mockStorage.set).toHaveBeenCalledWith(
'securitySolution.dataViewManager.selectedDataView.analyzer',
'adhoc_test-*'
);
});

it('should not store data view ID in storage when scope is not analyzer', async () => {
await listener.effect(
selectDataViewAsync({ id: 'adhoc_test-*', scope: DataViewManagerScopeName.default }),
mockListenerApi
);

expect(mockStorage.set).not.toHaveBeenCalled();
});

it('should store resolved data view ID from cached view when scope is analyzer', async () => {
const analyzerListener = createDataViewSelectedListener({
dataViews: mockDataViewsService,
scope: DataViewManagerScopeName.analyzer,
storage: mockStorage,
});

await analyzerListener.effect(
selectDataViewAsync({ id: 'persisted_test-*', scope: DataViewManagerScopeName.analyzer }),
mockListenerApi
);

expect(mockStorage.set).toHaveBeenCalledWith(
'securitySolution.dataViewManager.selectedDataView.analyzer',
'persisted_test-*'
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import type { DataView, DataViewLazy, DataViewsServicePublic } from '@kbn/data-views-plugin/public';
import type { AnyAction, Dispatch, ListenerEffectAPI } from '@reduxjs/toolkit';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import { isEmpty } from 'lodash';
import type { RootState } from '../reducer';
import { scopes } from '../reducer';
import { selectDataViewAsync } from '../actions';
import { sharedDataViewManagerSlice } from '../slices';
import type { DataViewManagerScopeName } from '../../constants';
import { DataViewManagerScopeName } from '../../constants';

/**
* Creates a Redux listener for handling data view selection logic in the data view manager.
Expand All @@ -27,12 +28,13 @@ import type { DataViewManagerScopeName } from '../../constants';
* If a data view is successfully resolved, it dispatches an action to set it as selected for the current scope.
* If an error occurs during fetching or creation, it dispatches an error action for the current scope.
*
* @param dependencies - The dependencies required for the listener, including the scope and DataViews service.
* @param dependencies - The dependencies required for the listener, including the scope, DataViews service, and storage.
* @returns An object with the action creator and effect for Redux middleware.
*/
export const createDataViewSelectedListener = (dependencies: {
scope: DataViewManagerScopeName;
dataViews: DataViewsServicePublic;
storage: Storage;
}) => {
return {
actionCreator: selectDataViewAsync,
Expand Down Expand Up @@ -130,6 +132,12 @@ export const createDataViewSelectedListener = (dependencies: {
}

listenerApi.dispatch(currentScopeActions.setSelectedDataView(resolvedIdToUse));
if (action.payload.scope === DataViewManagerScopeName.analyzer) {
dependencies.storage.set(
`securitySolution.dataViewManager.selectedDataView.${action.payload.scope}`,
resolvedIdToUse
);
}
} else if (dataViewByIdError || adhocDataViewCreationError) {
const err = dataViewByIdError || adhocDataViewCreationError;
listenerApi.dispatch(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { selectDataViewAsync } from '../actions';
import type { CoreStart } from '@kbn/core/public';
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
import { createDefaultDataView } from '../../utils/create_default_data_view';
import type { Storage } from '@kbn/kibana-utils-plugin/public';

jest.mock('../../utils/create_default_data_view', () => ({
createDefaultDataView: jest.fn(),
Expand Down Expand Up @@ -73,6 +74,12 @@ describe('createInitListener', () => {
application,
uiSettings,
spaces,
storage: {
get: jest.fn(),
set: jest.fn(),
remove: jest.fn(),
clear: jest.fn(),
} as unknown as Storage,
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { AnyAction, Dispatch, ListenerEffectAPI } from '@reduxjs/toolkit';
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import type { RootState } from '../reducer';
import { sharedDataViewManagerSlice } from '../slices';
import { DataViewManagerScopeName } from '../../constants';
Expand Down Expand Up @@ -39,6 +40,7 @@ export const createInitListener = (dependencies: {
uiSettings: CoreStart['uiSettings'];
dataViews: DataViewsServicePublic;
spaces: SpacesPluginStart;
storage: Storage;
}) => {
return {
actionCreator: sharedDataViewManagerSlice.actions.init,
Expand Down Expand Up @@ -111,6 +113,30 @@ export const createInitListener = (dependencies: {
scope,
})
);

const storedDataViewId = dependencies.storage.get(
`securitySolution.dataViewManager.selectedDataView.${scope}`
) as string | null | undefined;
const state = listenerApi.getState();
if (
storedDataViewId &&
!state.dataViewManager[scope].dataViewId &&
typeof storedDataViewId === 'string'
) {
return listenerApi.dispatch(
selectDataViewAsync({
id: storedDataViewId,
scope,
})
);
} else {
return 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