diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts
index 135b6121d1dd5..0cf97cdf8140e 100644
--- a/src/plugins/data/public/mocks.ts
+++ b/src/plugins/data/public/mocks.ts
@@ -60,7 +60,7 @@ const createStartContract = (): Start => {
query: queryStartMock,
ui: {
IndexPatternSelect: jest.fn(),
- SearchBar: jest.fn(),
+ SearchBar: jest.fn().mockReturnValue(null),
},
indexPatterns: ({
createField: jest.fn(() => {}),
diff --git a/x-pack/plugins/security_solution/public/common/components/search_bar/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/search_bar/index.test.tsx
new file mode 100644
index 0000000000000..356456c777791
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/search_bar/index.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { InputsModelId } from '../../store/inputs/constants';
+import { SearchBarComponent } from '.';
+import { TestProviders } from '../../mock';
+
+jest.mock('../../lib/kibana');
+
+describe('SearchBarComponent', () => {
+ const props = {
+ id: 'global' as InputsModelId,
+ indexPattern: {
+ fields: [],
+ title: '',
+ },
+ updateSearch: jest.fn(),
+ setSavedQuery: jest.fn(),
+ setSearchBarFilter: jest.fn(),
+ end: '',
+ start: '',
+ toStr: '',
+ fromStr: '',
+ isLoading: false,
+ filterQuery: {
+ query: '',
+ language: '',
+ },
+ queries: [],
+ savedQuery: undefined,
+ };
+
+ it('calls setSearchBarFilter on mount', () => {
+ mount(, { wrappingComponent: TestProviders });
+
+ expect(props.setSearchBarFilter).toHaveBeenCalled();
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
index de60bca73cedf..2dc44fd48e66d 100644
--- a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
@@ -33,7 +33,6 @@ import {
filterQuerySelector,
fromStrSelector,
isLoadingSelector,
- kindSelector,
queriesSelector,
savedQuerySelector,
startSelector,
@@ -44,6 +43,8 @@ import { networkActions } from '../../../network/store';
import { timelineActions } from '../../../timelines/store/timeline';
import { useKibana } from '../../lib/kibana';
+const APP_STATE_STORAGE_KEY = 'securitySolution.searchBar.appState';
+
interface SiemSearchBarProps {
id: InputsModelId;
indexPattern: IIndexPattern;
@@ -57,7 +58,7 @@ const SearchBarContainer = styled.div`
}
`;
-const SearchBarComponent = memo(
+export const SearchBarComponent = memo(
({
end,
filterQuery,
@@ -74,20 +75,27 @@ const SearchBarComponent = memo(
updateSearch,
dataTestSubj,
}) => {
- const { data } = useKibana().services;
const {
- timefilter: { timefilter },
- filterManager,
- } = data.query;
-
- if (fromStr != null && toStr != null) {
- timefilter.setTime({ from: fromStr, to: toStr });
- } else if (start != null && end != null) {
- timefilter.setTime({
- from: new Date(start).toISOString(),
- to: new Date(end).toISOString(),
- });
- }
+ data: {
+ query: {
+ timefilter: { timefilter },
+ filterManager,
+ },
+ ui: { SearchBar },
+ },
+ storage,
+ } = useKibana().services;
+
+ useEffect(() => {
+ if (fromStr != null && toStr != null) {
+ timefilter.setTime({ from: fromStr, to: toStr });
+ } else if (start != null && end != null) {
+ timefilter.setTime({
+ from: new Date(start).toISOString(),
+ to: new Date(end).toISOString(),
+ });
+ }
+ }, [end, fromStr, start, timefilter, toStr]);
const onQuerySubmit = useCallback(
(payload: { dateRange: TimeRange; query?: Query }) => {
@@ -135,8 +143,7 @@ const SearchBarComponent = memo(
window.setTimeout(() => updateSearch(updateSearchBar), 0);
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [id, end, filterQuery, fromStr, queries, start, toStr]
+ [id, toStr, end, fromStr, start, filterManager, filterQuery, queries, updateSearch]
);
const onRefresh = useCallback(
@@ -155,16 +162,14 @@ const SearchBarComponent = memo(
queries.forEach((q) => q.refetch && (q.refetch as inputsModel.Refetch)());
}
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [id, queries, filterManager]
+ [updateSearch, id, filterManager, queries]
);
const onSaved = useCallback(
(newSavedQuery: SavedQuery) => {
setSavedQuery({ id, savedQuery: newSavedQuery });
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [id]
+ [id, setSavedQuery]
);
const onSavedQueryUpdated = useCallback(
@@ -200,8 +205,7 @@ const SearchBarComponent = memo(
updateSearch(updateSearchBar);
},
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [id, end, fromStr, start, toStr]
+ [id, toStr, end, fromStr, start, filterManager, updateSearch]
);
const onClearSavedQuery = useCallback(() => {
@@ -223,8 +227,16 @@ const SearchBarComponent = memo(
filterManager,
});
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [id, end, filterManager, fromStr, start, toStr, savedQuery]);
+ }, [savedQuery, updateSearch, id, toStr, end, fromStr, start, filterManager]);
+
+ const saveAppStateToStorage = useCallback(
+ (filters: Filter[]) => storage.set(APP_STATE_STORAGE_KEY, filters),
+ [storage]
+ );
+
+ const getAppStateFromStorage = useCallback(() => storage.get(APP_STATE_STORAGE_KEY) ?? [], [
+ storage,
+ ]);
useEffect(() => {
let isSubscribed = true;
@@ -234,6 +246,7 @@ const SearchBarComponent = memo(
filterManager.getUpdates$().subscribe({
next: () => {
if (isSubscribed) {
+ saveAppStateToStorage(filterManager.getAppFilters());
setSearchBarFilter({
id,
filters: filterManager.getFilters(),
@@ -243,16 +256,25 @@ const SearchBarComponent = memo(
})
);
+ // for the initial state
+ filterManager.setAppFilters(getAppStateFromStorage());
+ setSearchBarFilter({
+ id,
+ filters: filterManager.getFilters(),
+ });
+
return () => {
isSubscribed = false;
subscriptions.unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
+
const indexPatterns = useMemo(() => [indexPattern], [indexPattern]);
+
return (
- {
const getEndSelector = endSelector();
const getFromStrSelector = fromStrSelector();
const getIsLoadingSelector = isLoadingSelector();
- const getKindSelector = kindSelector();
const getQueriesSelector = queriesSelector();
const getStartSelector = startSelector();
const getToStrSelector = toStrSelector();
@@ -292,7 +313,6 @@ const makeMapStateToProps = () => {
fromStr: getFromStrSelector(inputsRange),
filterQuery: getFilterQuerySelector(inputsRange),
isLoading: getIsLoadingSelector(inputsRange),
- kind: getKindSelector(inputsRange),
queries: getQueriesSelector(inputsRange),
savedQuery: getSavedQuerySelector(inputsRange),
start: getStartSelector(inputsRange),