Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ee7ea1e
WIP working data view/date picker for analyzer
kqualters-elastic Feb 7, 2024
646202b
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 7, 2024
3838226
Add 1 more TODO
kqualters-elastic Feb 7, 2024
fe089e0
Move sourcerer popover to own component, add basic tests
kqualters-elastic Feb 9, 2024
df5fdea
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 9, 2024
c15dc55
Merge branch 'main' into analyzer-sourcerer
kqualters-elastic Feb 9, 2024
75acb32
Fix types/tests
kqualters-elastic Feb 9, 2024
7804019
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 9, 2024
0a4a0ca
Merge branch 'main' into analyzer-sourcerer
kqualters-elastic Feb 13, 2024
ef55166
Fix overlay tests
kqualters-elastic Feb 13, 2024
d6c57a0
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 13, 2024
abfd822
Add feature flag
kqualters-elastic Feb 13, 2024
423a8cc
Address pr comments, fix bug with component unmounting + date math
kqualters-elastic Feb 14, 2024
80835c2
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 14, 2024
cd1859c
Fix failing tests, remove unneeded outside click detector
kqualters-elastic Feb 14, 2024
f8c2b39
Merge remote-tracking branch 'upstream/main' into analyzer-sourcerer
kqualters-elastic Feb 14, 2024
05074be
Rewrite sourcerer selectors so that they make use of createSelector
kqualters-elastic Feb 14, 2024
d5f1209
Use cache size = number of sourcerer scopes
kqualters-elastic Feb 14, 2024
766f292
Dynamic size of sourcerer scopes
kqualters-elastic Feb 14, 2024
696b008
Fix most tests
kqualters-elastic Feb 14, 2024
0e708e6
Fix remaining tests
kqualters-elastic Feb 15, 2024
8de7477
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 15, 2024
24d4f48
Merge branch 'main' into sourcerer-selectors-new-style
kqualters-elastic Feb 15, 2024
50d74ea
Add scope.isLoading
kqualters-elastic Feb 15, 2024
f24a35f
Merge branch 'main' into sourcerer-selectors-new-style
kqualters-elastic Feb 15, 2024
95ccd8d
Fix types
kqualters-elastic Feb 15, 2024
016a362
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 15, 2024
26f5905
Merge remote-tracking branch 'origin/sourcerer-selectors-new-style' i…
kqualters-elastic Feb 15, 2024
fa48b4a
Fix resolver clickthrough tests
kqualters-elastic Feb 15, 2024
177d128
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 15, 2024
03b32b1
Merge branch 'main' into sourcerer-selectors-new-style
kqualters-elastic Feb 19, 2024
bbd096b
PR feedback/cleanup
kqualters-elastic Feb 19, 2024
7874764
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 19, 2024
7d6b2c0
Undo null check for selector, type or code is off
kqualters-elastic Feb 20, 2024
6afd726
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 20, 2024
b9fb99d
Merge branch 'main' into sourcerer-selectors-new-style
kqualters-elastic Feb 20, 2024
9234cf1
Merge remote-tracking branch 'upstream/main' into sourcerer-selectors…
kqualters-elastic Feb 22, 2024
9825a17
Focus timeline open toggle on close
kqualters-elastic Feb 22, 2024
9abf581
Fix types
kqualters-elastic Feb 22, 2024
5b820ce
Fix test
kqualters-elastic Feb 22, 2024
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 @@ -5,13 +5,12 @@
* 2.0.
*/

import React, { useCallback, useMemo } from 'react';
import React, { useCallback } from 'react';
import { EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
import type { Filter } from '@kbn/es-query';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { useAssistantContext } from '@kbn/elastic-assistant';
import { useDeepEqualSelector } from '../../common/hooks/use_selector';
import { sourcererSelectors } from '../../common/store';
import { sourcererActions } from '../../common/store/actions';
import { inputsActions } from '../../common/store/inputs';
Expand Down Expand Up @@ -63,13 +62,8 @@ export const SendToTimelineButton: React.FunctionComponent<SendToTimelineButtonP

const isEsqlTabInTimelineDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled');

const getDataViewsSelector = useMemo(
() => sourcererSelectors.getSourcererDataViewsSelector(),
[]
);
const { defaultDataView, signalIndexName } = useDeepEqualSelector((state) =>
getDataViewsSelector(state)
);
const signalIndexName = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);

const hasTemplateProviders =
dataProviders && dataProviders.find((provider) => provider.type === 'template');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* 2.0.
*/

import React, { useMemo, useCallback } from 'react';
import React, { useCallback } from 'react';
import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
import type { IconType } from '@elastic/eui';
import type { Filter } from '@kbn/es-query';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { sourcererSelectors } from '../../../store';
import { InputsModelId } from '../../../store/inputs/constants';
Expand All @@ -23,7 +23,6 @@ import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineType } from '../../../../../common/api/timeline';
import { useCreateTimeline } from '../../../../timelines/hooks/use_create_timeline';
import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../../../detections/components/alerts_table/translations';
import { useDeepEqualSelector } from '../../../hooks/use_selector';

export interface InvestigateInTimelineButtonProps {
asEmptyButton: boolean;
Expand All @@ -49,13 +48,8 @@ export const InvestigateInTimelineButton: React.FunctionComponent<
}) => {
const dispatch = useDispatch();

const getDataViewsSelector = useMemo(
() => sourcererSelectors.getSourcererDataViewsSelector(),
[]
);
const { defaultDataView, signalIndexName } = useDeepEqualSelector((state) =>
getDataViewsSelector(state)
);
const signalIndexName = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);

const hasTemplateProviders =
dataProviders && dataProviders.find((provider) => provider.type === 'template');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import {
} from '@elastic/eui';
import type { ChangeEventHandler } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import * as i18n from './translations';
import type { sourcererModel } from '../../store/sourcerer';
import { sourcererActions, sourcererSelectors } from '../../store/sourcerer';
import { useDeepEqualSelector } from '../../hooks/use_selector';
import type { SourcererUrlState } from '../../store/sourcerer/model';
import type { State } from '../../store';
import type { ModifiedTypes } from './use_pick_index_patterns';
import { SourcererScopeName } from '../../store/sourcerer/model';
import { usePickIndexPatterns } from './use_pick_index_patterns';
Expand Down Expand Up @@ -129,17 +129,18 @@ export const Sourcerer = React.memo<SourcererComponentProps>(({ scope: scopeId }
const isDefaultSourcerer = scopeId === SourcererScopeName.default;
const updateUrlParam = useUpdateUrlParam<SourcererUrlState>(URL_PARAM_KEY.sourcerer);

const sourcererScopeSelector = useMemo(() => sourcererSelectors.getSourcererScopeSelector(), []);
const {
defaultDataView,
kibanaDataViews,
signalIndexName,
sourcererScope: {
selectedDataViewId,
selectedPatterns,
missingPatterns: sourcererMissingPatterns,
},
} = useDeepEqualSelector((state) => sourcererScopeSelector(state, scopeId));
const signalIndexName = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);
const kibanaDataViews = useSelector(sourcererSelectors.kibanaDataViews);
const selectedDataViewId = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId);
});
const selectedPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedPatterns(state, scopeId);
});
const sourcererMissingPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeMissingPatterns(state, scopeId);
});
const { pollForSignalIndex } = useSignalHelpers();

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { i18n } from '@kbn/i18n';
import { matchPath } from 'react-router-dom';
import { sourcererActions, sourcererSelectors } from '../../store/sourcerer';
Expand Down Expand Up @@ -36,6 +36,7 @@ import { useAppToasts } from '../../hooks/use_app_toasts';
import { createSourcererDataView } from './create_sourcerer_data_view';
import { getDataViewStateFromIndexFields, useDataView } from '../source/use_data_view';
import { useFetchIndex } from '../source';
import type { State } from '../../store';
import { useInitializeUrlParam, useUpdateUrlParam } from '../../utils/global_query_string';
import { URL_PARAM_KEY } from '../../hooks/use_url_state';
import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer';
Expand All @@ -54,14 +55,8 @@ export const useInitSourcerer = (
const { loading: loadingSignalIndex, isSignalIndexExists, signalIndexName } = useUserInfo();
const updateUrlParam = useUpdateUrlParam<SourcererUrlState>(URL_PARAM_KEY.sourcerer);

const getDataViewsSelector = useMemo(
() => sourcererSelectors.getSourcererDataViewsSelector(),
[]
);
const { defaultDataView, signalIndexName: signalIndexNameSourcerer } = useDeepEqualSelector(
(state) => getDataViewsSelector(state)
);

const signalIndexNameSourcerer = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);
const { addError, addWarning } = useAppToasts();

useEffect(() => {
Expand All @@ -83,19 +78,29 @@ export const useInitSourcerer = (
getTimelineSelector(state, TimelineId.active)
);

const sourcererScopeSelector = useMemo(() => sourcererSelectors.getSourcererScopeSelector(), []);
const {
sourcererScope: { selectedDataViewId: scopeDataViewId, selectedPatterns, missingPatterns },
} = useDeepEqualSelector((state) => sourcererScopeSelector(state, scopeId));
const scopeDataViewId = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId);
});
const selectedPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedPatterns(state, scopeId);
});
const missingPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeMissingPatterns(state, scopeId);
});

const {
selectedDataView: timelineSelectedDataView,
sourcererScope: {
selectedDataViewId: timelineDataViewId,
selectedPatterns: timelineSelectedPatterns,
missingPatterns: timelineMissingPatterns,
},
} = useDeepEqualSelector((state) => sourcererScopeSelector(state, SourcererScopeName.timeline));
const kibanaDataViews = useSelector(sourcererSelectors.kibanaDataViews);
const timelineDataViewId = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedDataViewId(state, SourcererScopeName.timeline);
});
const timelineSelectedPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedPatterns(state, SourcererScopeName.timeline);
});
const timelineMissingPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeMissingPatterns(state, SourcererScopeName.timeline);
});
const timelineSelectedDataView = useMemo(() => {
return kibanaDataViews.find((dataView) => dataView.id === timelineDataViewId);
}, [kibanaDataViews, timelineDataViewId]);

const { indexFieldsSearch } = useDataView();

Expand Down Expand Up @@ -387,26 +392,23 @@ export const useInitSourcerer = (
export const useSourcererDataView = (
scopeId: SourcererScopeName = SourcererScopeName.default
): SelectedDataView => {
const { getDataViewsSelector, getSourcererDataViewSelector, getScopeSelector } = useMemo(
() => ({
getDataViewsSelector: sourcererSelectors.getSourcererDataViewsSelector(),
getSourcererDataViewSelector: sourcererSelectors.sourcererDataViewSelector(),
getScopeSelector: sourcererSelectors.scopeIdSelector(),
}),
[]
);
const {
defaultDataView,
signalIndexName,
selectedDataView,
sourcererScope: { missingPatterns, selectedPatterns: scopeSelectedPatterns, loading },
}: sourcererSelectors.SourcererScopeSelector = useDeepEqualSelector((state) => {
const sourcererScope = getScopeSelector(state, scopeId);
return {
...getDataViewsSelector(state),
selectedDataView: getSourcererDataViewSelector(state, sourcererScope.selectedDataViewId),
sourcererScope,
};
const kibanaDataViews = useSelector(sourcererSelectors.kibanaDataViews);
const signalIndexName = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);
const selectedDataViewId = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId);
});
const selectedDataView = useMemo(() => {
return kibanaDataViews.find((dataView) => dataView.id === selectedDataViewId);
}, [kibanaDataViews, selectedDataViewId]);
const loading = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeIsLoading(state, scopeId);
});
const scopeSelectedPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeSelectedPatterns(state, scopeId);
});
const missingPatterns = useSelector((state: State) => {
return sourcererSelectors.sourcererScopeMissingPatterns(state, scopeId);
});

const selectedPatterns = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

import { useCallback, useMemo, useRef } from 'react';
import { i18n } from '@kbn/i18n';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { sourcererSelectors } from '../../store';
import { useDeepEqualSelector } from '../../hooks/use_selector';
import { useSourcererDataView } from '.';
import { SourcererScopeName } from '../../store/sourcerer/model';
import { useDataView } from '../source/use_data_view';
Expand All @@ -33,17 +32,8 @@ export const useSignalHelpers = (): {
data: { dataViews },
} = useKibana().services;

const getDefaultDataViewSelector = useMemo(
() => sourcererSelectors.defaultDataViewSelector(),
[]
);
const getSignalIndexNameSelector = useMemo(
() => sourcererSelectors.signalIndexNameSelector(),
[]
);
const signalIndexNameSourcerer = useDeepEqualSelector(getSignalIndexNameSelector);
const defaultDataView = useDeepEqualSelector(getDefaultDataViewSelector);

const signalIndexNameSourcerer = useSelector(sourcererSelectors.signalIndexName);
const defaultDataView = useSelector(sourcererSelectors.defaultDataView);
const signalIndexNeedsInit = useMemo(
() => !defaultDataView.title.includes(`${signalIndexNameSourcerer}`),
[defaultDataView.title, signalIndexNameSourcerer]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
* 2.0.
*/

import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import type { SourcererScopeName } from '../store/sourcerer/model';
import { getSelectedDataviewSelector } from '../store/sourcerer/selectors';
import { useDeepEqualSelector } from './use_selector';

// Calls it from the module scope due to non memoized selectors https://github.com/elastic/kibana/issues/159315
const selectedDataviewSelector = getSelectedDataviewSelector();
import { sourcererSelectors } from '../store/sourcerer';
import type { State } from '../store';

export const useGetFieldSpec = (scopeId: SourcererScopeName) => {
const dataView = useDeepEqualSelector((state) => selectedDataviewSelector(state, scopeId));

const kibanaDataViews = useSelector(sourcererSelectors.kibanaDataViews);
const selectedDataViewId = useSelector((state: State) =>
sourcererSelectors.sourcererScopeSelectedDataViewId(state, scopeId)
);
const dataView = useMemo(
() => kibanaDataViews.find((dv) => dv.id === selectedDataViewId),
[kibanaDataViews, selectedDataViewId]
);
return useCallback(
(fieldName: string) => {
const fields = dataView?.fields;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,47 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { parseExperimentalConfigValue } from '../../../common/experimental_features';
import type { SecuritySubPlugins } from '../../app/types';
import { createInitialState } from './reducer';
import { mockIndexPattern, mockSourcererState } from '../mock';
import { mockIndexPattern, mockSourcererState, TestProviders, createMockStore } from '../mock';
import { useSourcererDataView } from '../containers/sourcerer';
import { useDeepEqualSelector } from '../hooks/use_selector';
import { renderHook } from '@testing-library/react-hooks';
import { initialGroupingState } from './grouping/reducer';
import { initialAnalyzerState } from '../../resolver/store/helpers';

jest.mock('../hooks/use_selector');
jest.mock('../lib/kibana', () => ({
KibanaServices: {
get: jest.fn(() => ({ uiSettings: { get: () => ({ from: 'now-24h', to: 'now' }) } })),
},
}));
jest.mock('../lib/kibana', () => {
const original = jest.requireActual('../lib/kibana');
return {
...original,
useKibana: () => ({
...original.useKibana(),
services: {
...original.useKibana().services,
upselling: {
...original.useKibana().services.upselling,
featureUsage: {
...original.useKibana().services.upselling.featureUsage,
hasShown: jest.fn(),
},
},
},
}),
KibanaServices: {
get: jest.fn(() => ({ uiSettings: { get: () => ({ from: 'now-24h', to: 'now' }) } })),
},
};
});
jest.mock('../containers/source', () => ({
useFetchIndex: () => [
false,
{ indexes: [], indicesExist: true, indexPatterns: mockIndexPattern },
],
}));

// TODO: this is more of a hook test, a reducer is a pure function and should not need hooks and context to test.
describe('createInitialState', () => {
describe('sourcerer -> default -> indicesExist', () => {
const mockPluginState = {} as Omit<
Expand All @@ -53,15 +70,13 @@ describe('createInitialState', () => {
analyzer: initialAnalyzerState,
}
);
beforeEach(() => {
(useDeepEqualSelector as jest.Mock).mockImplementation((cb) => cb(initState));
});
afterEach(() => {
(useDeepEqualSelector as jest.Mock).mockClear();
});

test('indicesExist should be TRUE if patternList is NOT empty', async () => {
const { result } = renderHook(() => useSourcererDataView());
const { result } = renderHook(() => useSourcererDataView(), {
wrapper: ({ children }) => (
<TestProviders store={createMockStore(initState)}>{children}</TestProviders>
),
});
expect(result.current.indicesExist).toEqual(true);
});

Expand Down Expand Up @@ -93,8 +108,11 @@ describe('createInitialState', () => {
analyzer: initialAnalyzerState,
}
);
(useDeepEqualSelector as jest.Mock).mockImplementation((cb) => cb(state));
const { result } = renderHook(() => useSourcererDataView());
const { result } = renderHook(() => useSourcererDataView(), {
wrapper: ({ children }) => (
<TestProviders store={createMockStore(state)}>{children}</TestProviders>
),
});
expect(result.current.indicesExist).toEqual(false);
});
});
Expand Down
Loading