Skip to content

Commit

Permalink
Fix default filters per tab in vulnerabilities module (#6188)
Browse files Browse the repository at this point in the history
* Fix default filters per vulnerabilities tab

* Update use_search_bar_configuration test
  • Loading branch information
jbiset authored Dec 4, 2023
1 parent 740e2e1 commit b5be965
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const DashboardVulsComponent: React.FC = () => {
appConfig.data['vulnerabilities.pattern'];
const { searchBarProps } = useSearchBarConfiguration({
defaultIndexPatternID: VULNERABILITIES_INDEX_PATTERN_ID,
filters: [],
});
const {
isLoading: isLoadingSearchbar,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { renderHook } from '@testing-library/react-hooks';
import '@testing-library/jest-dom/extend-expect';
// osd dependencies
import { Start, dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks';
import {
Start,
dataPluginMock,
} from '../../../../../../../src/plugins/data/public/mocks';
import {
Filter,
IndexPattern,
Expand Down Expand Up @@ -41,7 +44,7 @@ mockedGetDataPlugin.mockImplementation(
},
},
},
} as Start)
} as Start),
);
///////////////////////////////////////////////////////////

Expand Down Expand Up @@ -77,7 +80,9 @@ describe('[hook] useSearchBarConfiguration', () => {
jest
.spyOn(mockDataPlugin.indexPatterns, 'getDefault')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest.spyOn(mockDataPlugin.query.filterManager, 'getFilters').mockReturnValue([]);
jest
.spyOn(mockDataPlugin.query.filterManager, 'getFilters')
.mockReturnValue([]);
const { result, waitForNextUpdate } = renderHook(() => useSearchBar({}));
await waitForNextUpdate();
expect(mockDataPlugin.indexPatterns.getDefault).toBeCalled();
Expand All @@ -93,15 +98,21 @@ describe('[hook] useSearchBarConfiguration', () => {
id: exampleIndexPatternId,
title: '',
};
jest.spyOn(mockDataPlugin.indexPatterns, 'get').mockResolvedValue(mockedIndexPatternData);
jest
.spyOn(mockDataPlugin.indexPatterns, 'get')
.mockResolvedValue(mockedIndexPatternData);
const { result, waitForNextUpdate } = renderHook(() =>
useSearchBar({
defaultIndexPatternID: 'wazuh-index-pattern',
})
}),
);
await waitForNextUpdate();
expect(mockDataPlugin.indexPatterns.get).toBeCalledWith(exampleIndexPatternId);
expect(result.current.searchBarProps.indexPatterns).toMatchObject([mockedIndexPatternData]);
expect(mockDataPlugin.indexPatterns.get).toBeCalledWith(
exampleIndexPatternId,
);
expect(result.current.searchBarProps.indexPatterns).toMatchObject([
mockedIndexPatternData,
]);
});

it('should show an ERROR message and get the default app index pattern when not found the index pattern data by the ID received', async () => {
Expand All @@ -112,19 +123,25 @@ describe('[hook] useSearchBarConfiguration', () => {
jest
.spyOn(mockDataPlugin.indexPatterns, 'getDefault')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest.spyOn(mockDataPlugin.query.filterManager, 'getFilters').mockReturnValue([]);
jest
.spyOn(mockDataPlugin.query.filterManager, 'getFilters')
.mockReturnValue([]);

// mocking console error to avoid logs in test and check if is called
const mockedConsoleError = jest.spyOn(console, 'error').mockImplementationOnce(() => {});
const mockedConsoleError = jest
.spyOn(console, 'error')
.mockImplementationOnce(() => {});
const { result, waitForNextUpdate } = renderHook(() =>
useSearchBar({
defaultIndexPatternID: 'invalid-index-pattern-id',
})
}),
);

await waitForNextUpdate();
expect(mockDataPlugin.indexPatterns.getDefault).toBeCalled();
expect(mockDataPlugin.indexPatterns.get).toBeCalledWith('invalid-index-pattern-id');
expect(mockDataPlugin.indexPatterns.get).toBeCalledWith(
'invalid-index-pattern-id',
);
expect(result.current.searchBarProps.indexPatterns).toMatchObject([
mockedDefaultIndexPatternData,
]);
Expand All @@ -145,50 +162,22 @@ describe('[hook] useSearchBarConfiguration', () => {
jest
.spyOn(mockDataPlugin.indexPatterns, 'getDefault')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest.spyOn(mockDataPlugin.query.filterManager, 'getFilters').mockReturnValue(defaultFilters);
jest
.spyOn(mockDataPlugin.query.filterManager, 'getFilters')
.mockReturnValue(defaultFilters);
const { result, waitForNextUpdate } = renderHook(() =>
useSearchBar({
filters: defaultFilters,
})
}),
);

await waitForNextUpdate();

expect(result.current.searchBarProps.filters).toMatchObject(defaultFilters);
expect(mockDataPlugin.query.filterManager.setFilters).toBeCalledWith(defaultFilters);
expect(mockDataPlugin.query.filterManager.getFilters).toBeCalled();
});

it('should return and preserve filters when the index pattern received is equal to the index pattern already selected in the app', async () => {
const defaultIndexFilters: Filter[] = [
{
query: 'something to filter',
meta: {
alias: 'filter-mocked',
disabled: false,
negate: true,
},
},
];
jest
.spyOn(mockDataPlugin.indexPatterns, 'getDefault')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest
.spyOn(mockDataPlugin.indexPatterns, 'get')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest
.spyOn(mockDataPlugin.query.filterManager, 'getFilters')
.mockReturnValue(defaultIndexFilters);
const { result, waitForNextUpdate } = renderHook(() =>
useSearchBar({
defaultIndexPatternID: mockedDefaultIndexPatternData.id,
})
expect(mockDataPlugin.query.filterManager.setFilters).toBeCalledWith(
defaultFilters,
);
await waitForNextUpdate();
expect(result.current.searchBarProps.indexPatterns).toMatchObject([
mockedDefaultIndexPatternData,
]);
expect(result.current.searchBarProps.filters).toMatchObject(defaultIndexFilters);
expect(mockDataPlugin.query.filterManager.getFilters).toBeCalled();
});

it('should return empty filters when the index pattern is NOT equal to the default app index pattern', async () => {
Expand All @@ -204,11 +193,13 @@ describe('[hook] useSearchBarConfiguration', () => {
jest
.spyOn(mockDataPlugin.indexPatterns, 'getDefault')
.mockResolvedValue(mockedDefaultIndexPatternData);
jest.spyOn(mockDataPlugin.query.filterManager, 'getFilters').mockReturnValue([]);
jest
.spyOn(mockDataPlugin.query.filterManager, 'getFilters')
.mockReturnValue([]);
const { result, waitForNextUpdate } = renderHook(() =>
useSearchBar({
defaultIndexPatternID: exampleIndexPatternId,
})
}),
);
await waitForNextUpdate();
expect(result.current.searchBarProps.indexPatterns).toMatchObject([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import {
SearchBarProps,
FilterManager,
Expand Down Expand Up @@ -44,6 +44,7 @@ const useSearchBarConfiguration = (
props?: tUseSearchBarProps,
): tUserSearchBarResponse => {
// dependencies
const SESSION_STORAGE_FILTERS_NAME = 'wazuh_persistent_searchbar_filters';
const filterManager = useFilterManager().filterManager as FilterManager;
const { filters } = useFilterManager();
const [query, setQuery] = props?.query
Expand All @@ -56,29 +57,38 @@ const useSearchBarConfiguration = (
useState<IIndexPattern>();

useEffect(() => {
if (filters && filters.length > 0) {
sessionStorage.setItem(
SESSION_STORAGE_FILTERS_NAME,
JSON.stringify(filters),
);
}
initSearchBar();
/**
* When the component is disassembled, the original filters that arrived
* when the component was assembled are added.
*/
return () => {
const storagePreviousFilters = sessionStorage.getItem(
SESSION_STORAGE_FILTERS_NAME,
);
if (storagePreviousFilters) {
const previousFilters = JSON.parse(storagePreviousFilters);
const cleanedFilters = cleanFilters(previousFilters);
filterManager.setFilters(cleanedFilters);
}
};
}, []);

useEffect(() => {
const defaultIndex = props?.defaultIndexPatternID;
/* Filters that do not belong to the default index are filtered */
const cleanedFilters = filters.filter(
filter => filter.meta.index === defaultIndex,
);
if (cleanedFilters.length !== filters.length) {
filterManager.setFilters(cleanedFilters);
}
}, [filters]);

/**
* Initialize the searchbar props with the corresponding index pattern and filters
*/
const initSearchBar = async () => {
setIsLoading(true);
const indexPattern = await getIndexPattern(props?.defaultIndexPatternID);
setIndexPatternSelected(indexPattern);
const filters = await getInitialFilters(indexPattern);
filterManager.setFilters(filters);
const initialFilters = props?.filters ?? filters;
filterManager.setFilters(initialFilters);
setIsLoading(false);
};

Expand All @@ -104,44 +114,33 @@ const useSearchBarConfiguration = (
};

/**
* Return the initial filters considering if hook receives initial filters
* When the default index pattern is the same like the received preserve the filters
* @param indexPattern
* Return filters from filters manager.
* Additionally solve the known issue with the auto loaded agent.id filters from the searchbar
* and filters those filters that are not related to the default index pattern
* @returns
*/
const getInitialFilters = async (indexPattern: IIndexPattern) => {
const indexPatternService = getDataPlugin()
.indexPatterns as IndexPatternsContract;
let initialFilters: Filter[] = [];
if (props?.filters) {
return props?.filters;
}
if (indexPattern) {
// get filtermanager and filters
// if the index is the same, get filters stored
// else clear filters
const defaultIndexPattern =
(await indexPatternService.getDefault()) as IIndexPattern;
initialFilters =
defaultIndexPattern.id === indexPattern.id
? filterManager.getFilters()
: [];
} else {
initialFilters = [];
}
return initialFilters;
const getFilters = () => {
const originalFilters = filterManager ? filterManager.getFilters() : [];
return originalFilters.filter(
(filter: Filter) =>
filter?.meta?.controlledBy !== AUTHORIZED_AGENTS && // remove auto loaded agent.id filters
filter?.meta?.index === props?.defaultIndexPatternID,
);
};

/**
* Return filters from filters manager.
* Additionally solve the known issue with the auto loaded agent.id filters from the searchbar
* Return cleaned filters.
* Clean the known issue with the auto loaded agent.id filters from the searchbar
* and filters those filters that are not related to the default index pattern
* @param previousFilters
* @returns
*/
const getFilters = () => {
const filters = filterManager ? filterManager.getFilters() : [];
return filters.filter(
filter => filter.meta.controlledBy !== AUTHORIZED_AGENTS,
); // remove auto loaded agent.id filters
const cleanFilters = (previousFilters: Filter[]) => {
return previousFilters.filter(
(filter: Filter) =>
filter?.meta?.controlledBy !== AUTHORIZED_AGENTS &&
filter?.meta?.index !== props?.defaultIndexPatternID,
);
};

/**
Expand All @@ -156,9 +155,24 @@ const useSearchBarConfiguration = (
dateRangeFrom: timeFilter.from,
dateRangeTo: timeFilter.to,
onFiltersUpdated: (filters: Filter[]) => {
// its necessary execute setter to apply filters
filterManager.setFilters(filters);
props?.onFiltersUpdated && props?.onFiltersUpdated(filters);
const storagePreviousFilters = sessionStorage.getItem(
SESSION_STORAGE_FILTERS_NAME,
);
/**
* If there are persisted filters, it is necessary to add them when
* updating the filters in the filterManager
*/
if (storagePreviousFilters) {
const previousFilters = JSON.parse(storagePreviousFilters);
const cleanedFilters = cleanFilters(previousFilters);
filterManager.setFilters([...cleanedFilters, ...filters]);

props?.onFiltersUpdated &&
props?.onFiltersUpdated([...cleanedFilters, ...filters]);
} else {
filterManager.setFilters(filters);
props?.onFiltersUpdated && props?.onFiltersUpdated(filters);
}
},
onQuerySubmit: (
payload: { dateRange: TimeRange; query?: Query },
Expand Down

0 comments on commit b5be965

Please sign in to comment.