mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.16] [Bug][Security Solution] - Reliably persist dataview selections for timeline (#211343) (#213492)
# Backport This will backport the following commits from `main` to `8.16`: - [[Bug][Security Solution] - Reliably persist dataview selections for timeline (#211343)](https://github.com/elastic/kibana/pull/211343) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Michael Olorunnisola","email":"michael.olorunnisola@elastic.co"},"sourceCommit":{"committedDate":"2025-03-06T21:09:22Z","message":"[Bug][Security Solution] - Reliably persist dataview selections for timeline (#211343)\n\nresolves https://github.com/elastic/kibana/issues/198944\n\n## Summary\n\nCurrently, the redux store can become out of sync with the state in the\nUI, leading to the selected dataview not being preserved in the store,\nand thereby not being saved when the timeline is saved. This PR sets the\nselected dataview and patterns at the point of saving to ensure that\nthey are set and not overriden.\n\nFor additional background, see referenced issues.","sha":"4abf1a151e9b10a02a633a5f9e88607a55e3f4ba","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:fix","v9.0.0","Team:Threat Hunting:Investigations","backport:version","v8.18.0","v9.1.0","v8.19.0","v8.16.6","v8.17.4"],"title":"[Bug][Security Solution] - Reliably persist dataview selections for timeline","number":211343,"url":"https://github.com/elastic/kibana/pull/211343","mergeCommit":{"message":"[Bug][Security Solution] - Reliably persist dataview selections for timeline (#211343)\n\nresolves https://github.com/elastic/kibana/issues/198944\n\n## Summary\n\nCurrently, the redux store can become out of sync with the state in the\nUI, leading to the selected dataview not being preserved in the store,\nand thereby not being saved when the timeline is saved. This PR sets the\nselected dataview and patterns at the point of saving to ensure that\nthey are set and not overriden.\n\nFor additional background, see referenced issues.","sha":"4abf1a151e9b10a02a633a5f9e88607a55e3f4ba"}},"sourceBranch":"main","suggestedTargetBranches":["8.18","8.x","8.16","8.17"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/213488","number":213488,"state":"OPEN"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/211343","number":211343,"mergeCommit":{"message":"[Bug][Security Solution] - Reliably persist dataview selections for timeline (#211343)\n\nresolves https://github.com/elastic/kibana/issues/198944\n\n## Summary\n\nCurrently, the redux store can become out of sync with the state in the\nUI, leading to the selected dataview not being preserved in the store,\nand thereby not being saved when the timeline is saved. This PR sets the\nselected dataview and patterns at the point of saving to ensure that\nthey are set and not overriden.\n\nFor additional background, see referenced issues.","sha":"4abf1a151e9b10a02a633a5f9e88607a55e3f4ba"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.16","label":"v8.16.6","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.17","label":"v8.17.4","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
This commit is contained in:
parent
dc8ba9985b
commit
0ae7625cf8
3 changed files with 28 additions and 6 deletions
|
@ -12,7 +12,7 @@ import { TimelineId, TimelineTabs } from '../../../../common/types/timeline';
|
|||
import { TimelineTypeEnum, TimelineStatusEnum } from '../../../../common/api/timeline';
|
||||
import { convertTimelineAsInput } from './timeline_save';
|
||||
import type { TimelineModel } from '../model';
|
||||
import { createMockStore, kibanaMock } from '../../../common/mock';
|
||||
import { createMockStore, kibanaMock, mockGlobalState } from '../../../common/mock';
|
||||
import { selectTimelineById } from '../selectors';
|
||||
import { copyTimeline, persistTimeline } from '../../containers/api';
|
||||
import { refreshTimelines } from './helpers';
|
||||
|
@ -79,7 +79,14 @@ describe('Timeline save middleware', () => {
|
|||
await store.dispatch(saveTimeline({ id: TimelineId.test, saveAsNew: false }));
|
||||
|
||||
expect(startTimelineSavingMock).toHaveBeenCalled();
|
||||
expect(persistTimeline as unknown as jest.Mock).toHaveBeenCalled();
|
||||
expect(persistTimeline as unknown as jest.Mock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
timeline: expect.objectContaining({
|
||||
dataViewId: mockGlobalState.sourcerer.sourcererScopes.timeline.selectedDataViewId,
|
||||
indexNames: mockGlobalState.sourcerer.sourcererScopes.timeline.selectedPatterns,
|
||||
}),
|
||||
})
|
||||
);
|
||||
expect(refreshTimelines as unknown as jest.Mock).toHaveBeenCalled();
|
||||
expect(endTimelineSavingMock).toHaveBeenCalled();
|
||||
expect(selectTimelineById(store.getState(), TimelineId.test)).toEqual(
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
isPhrasesFilter,
|
||||
} from '@kbn/es-query';
|
||||
|
||||
import { sourcererSelectors } from '../../../sourcerer/store';
|
||||
import {
|
||||
updateTimeline,
|
||||
startTimelineSaving,
|
||||
|
@ -42,6 +43,7 @@ import type {
|
|||
import type { TimelineModel } from '../model';
|
||||
import type { ColumnHeaderOptions } from '../../../../common/types/timeline';
|
||||
import { refreshTimelines } from './helpers';
|
||||
import { SourcererScopeName } from '../../../sourcerer/store/model';
|
||||
|
||||
function isSaveTimelineAction(action: Action): action is ReturnType<typeof saveTimeline> {
|
||||
return action.type === saveTimeline.type;
|
||||
|
@ -54,10 +56,19 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State
|
|||
|
||||
if (isSaveTimelineAction(action)) {
|
||||
const { id: localTimelineId } = action.payload;
|
||||
const timeline = selectTimelineById(store.getState(), localTimelineId);
|
||||
const storeState = store.getState();
|
||||
const timeline = selectTimelineById(storeState, localTimelineId);
|
||||
const { timelineId, timelineVersion, templateTimelineId, templateTimelineVersion } =
|
||||
extractTimelineIdsAndVersions(timeline);
|
||||
const timelineTimeRange = inputsSelectors.timelineTimeRangeSelector(store.getState());
|
||||
const timelineTimeRange = inputsSelectors.timelineTimeRangeSelector(storeState);
|
||||
const selectedDataViewIdSourcerer = sourcererSelectors.sourcererScopeSelectedDataViewId(
|
||||
storeState,
|
||||
SourcererScopeName.timeline
|
||||
);
|
||||
const selectedPatterns = sourcererSelectors.sourcererScopeSelectedPatterns(
|
||||
storeState,
|
||||
SourcererScopeName.timeline
|
||||
);
|
||||
|
||||
store.dispatch(startTimelineSaving({ id: localTimelineId }));
|
||||
|
||||
|
@ -67,6 +78,8 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State
|
|||
timelineId,
|
||||
timeline: {
|
||||
...convertTimelineAsInput(timeline, timelineTimeRange),
|
||||
dataViewId: selectedDataViewIdSourcerer,
|
||||
indexNames: selectedPatterns,
|
||||
templateTimelineId,
|
||||
templateTimelineVersion,
|
||||
},
|
||||
|
@ -77,6 +90,8 @@ export const saveTimelineMiddleware: (kibana: CoreStart) => Middleware<{}, State
|
|||
version: timelineVersion,
|
||||
timeline: {
|
||||
...convertTimelineAsInput(timeline, timelineTimeRange),
|
||||
dataViewId: selectedDataViewIdSourcerer,
|
||||
indexNames: selectedPatterns,
|
||||
templateTimelineId,
|
||||
templateTimelineVersion,
|
||||
},
|
||||
|
|
|
@ -40,7 +40,7 @@ import { closeTimeline, openTimelineById } from '../../../tasks/timeline';
|
|||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['logs-*', 'metrics-*', '.kibana-event-log-*'];
|
||||
|
||||
describe('Timeline scope', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => {
|
||||
describe('Timeline scope', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
waitForRulesBootstrap();
|
||||
});
|
||||
|
@ -134,7 +134,7 @@ describe('Timeline scope', { tags: ['@ess', '@serverless', '@skipInServerless']
|
|||
});
|
||||
|
||||
const defaultPatterns = [`auditbeat-*`, `${DEFAULT_ALERTS_INDEX}-default`];
|
||||
it('alerts checkbox behaves as expected', () => {
|
||||
it('alerts checkbox behaves as expected', { tags: ['@skipInServerless'] }, () => {
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
|
||||
openDataViewSelection();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue