diff --git a/plugins/main/public/components/common/data_grid/data_grid_service.ts b/plugins/main/public/components/common/data_grid/data_grid_service.ts index 68d2606bdf..59eda523cd 100644 --- a/plugins/main/public/components/common/data_grid/data_grid_service.ts +++ b/plugins/main/public/components/common/data_grid/data_grid_service.ts @@ -1,66 +1,10 @@ import { SearchResponse } from "../../../../../../src/core/server"; -import { getPlugins } from '../../../kibana-services'; -import { IndexPattern, Filter, OpenSearchQuerySortValue } from "../../../../../../src/plugins/data/public"; import * as FileSaver from '../../../services/file-saver'; import { beautifyDate } from "../../agents/vuls/inventory/lib"; +import { SearchParams, search } from "../search_bar/use_search_bar_service"; +import { IFieldType, IndexPattern } from "../../../../../../src/plugins/data/common"; export const MAX_ENTRIES_PER_QUERY = 10000; - -interface SearchParams { - indexPattern: IndexPattern; - filters?: Filter[]; - query?: any; - pagination?: { - pageIndex?: number; - pageSize?: number; - }; - fields?: string[], - sorting?: { - columns: { - id: string; - direction: 'asc' | 'desc'; - }[]; - }; -} - -export const search = async (params: SearchParams): Promise => { - const { indexPattern, filters = [], query, pagination, sorting, fields } = params; - if(!indexPattern){ - return; - } - const data = getPlugins().data; - const searchSource = await data.search.searchSource.create(); - const fromField = (pagination?.pageIndex || 0) * (pagination?.pageSize || 100); - const sortOrder: OpenSearchQuerySortValue[] = sorting?.columns.map((column) => { - const sortDirection = column.direction === 'asc' ? 'asc' : 'desc'; - return { [column?.id || '']: sortDirection } as OpenSearchQuerySortValue; - }) || []; - - const searchParams = searchSource - .setParent(undefined) - .setField('filter', filters) - .setField('query', query) - .setField('sort', sortOrder) - .setField('size', pagination?.pageSize) - .setField('from', fromField) - .setField('index', indexPattern) - - // add fields - if (fields && Array.isArray(fields) && fields.length > 0){ - searchParams.setField('fields', fields); - } - try{ - return await searchParams.fetch(); - }catch(error){ - if(error.body){ - throw error.body; - } - throw error; - } - -}; - - export const parseData = (resultsHits: SearchResponse['hits']['hits']): any[] => { const data = resultsHits.map((hit) => { if (!hit) { @@ -93,13 +37,19 @@ export const getFieldFormatted = (rowIndex, columnId, indexPattern, rowsParsed) fieldValue = fieldValue[field]; } }); - } else { - fieldValue = rowsParsed[rowIndex][columnId].formatted - ? rowsParsed[rowIndex][columnId].formatted - : rowsParsed[rowIndex][columnId]; + const rowValue = rowsParsed[rowIndex]; + // when not exist the column in the row value then the value is null + if(!rowValue.hasOwnProperty(columnId)){ + fieldValue = null; + }else{ + fieldValue = rowValue[columnId]?.formatted || rowValue[columnId]; + } + } + // when fieldValue is null or undefined then return a empty string + if (fieldValue === null || fieldValue === undefined) { + return ''; } - // if is date field if (field?.type === 'date') { // @ts-ignore @@ -108,6 +58,7 @@ export const getFieldFormatted = (rowIndex, columnId, indexPattern, rowsParsed) return fieldValue; } +// receive search params export const exportSearchToCSV = async (params: SearchParams): Promise => { const DEFAULT_MAX_SIZE_PER_CALL = 1000; const { indexPattern, filters = [], query, sorting, fields, pagination } = params; @@ -191,4 +142,20 @@ export const exportSearchToCSV = async (params: SearchParams): Promise => if (blobData) { FileSaver?.saveAs(blobData, `vulnerabilities_inventory-${new Date().toISOString()}.csv`); } -} \ No newline at end of file +} + +export const parseColumns = (fields: IFieldType[]): EuiDataGridColumn[] => { + // remove _source field becuase is a object field and is not supported + fields = fields.filter((field) => field.name !== '_source'); + return fields.map((field) => { + return { + ...field, + id: field.name, + display: field.name, + schema: field.type, + actions: { + showHide: true, + }, + }; + }) || []; +} diff --git a/plugins/main/public/components/common/data_grid/index.ts b/plugins/main/public/components/common/data_grid/index.ts new file mode 100644 index 0000000000..eccf698259 --- /dev/null +++ b/plugins/main/public/components/common/data_grid/index.ts @@ -0,0 +1,2 @@ +export * from './data_grid_service'; +export * from './use_data_grid'; \ No newline at end of file diff --git a/plugins/main/public/components/common/data_grid/use_data_grid.ts b/plugins/main/public/components/common/data_grid/use_data_grid.ts index 4225f5a80c..50388b4926 100644 --- a/plugins/main/public/components/common/data_grid/use_data_grid.ts +++ b/plugins/main/public/components/common/data_grid/use_data_grid.ts @@ -1,35 +1,23 @@ import { EuiDataGridCellValueElementProps, EuiDataGridColumn, EuiDataGridProps, EuiDataGridSorting } from "@elastic/eui" import React, { useEffect, useMemo, useState, Fragment } from "react"; import { SearchResponse } from "@opensearch-project/opensearch/api/types"; -import { IFieldType, IndexPattern } from "../../../../../../src/plugins/data/common"; // ToDo: check how create this methods -import { parseData, getFieldFormatted } from './data_grid_service'; +import { parseData, getFieldFormatted, parseColumns } from './data_grid_service'; const MAX_ENTRIES_PER_QUERY = 10000; +export type tDataGridColumn = { + render?: (value: any) => string | React.ReactNode; +} & EuiDataGridColumn; + type tDataGridProps = { indexPattern: IndexPattern; results: SearchResponse; - defaultColumns: EuiDataGridColumn[]; + defaultColumns: tDataGridColumn[]; DocViewInspectButton: ({ rowIndex }: EuiDataGridCellValueElementProps) => React.JSX.Element ariaLabelledBy: string; }; -export const parseColumns = (fields: IFieldType[]): EuiDataGridColumn[] => { - // remove _source field becuase is a object field and is not supported - fields = fields.filter((field) => field.name !== '_source'); - return fields.map((field) => { - return { - ...field, - id: field.name, - display: field.name, - schema: field.type, - actions: { - showHide: true, - }, - }; - }) || []; -} export const useDataGrid = (props: tDataGridProps): EuiDataGridProps => { const { indexPattern, DocViewInspectButton, results, defaultColumns } = props; @@ -49,15 +37,15 @@ export const useDataGrid = (props: tDataGridProps): EuiDataGridProps => { } const defaultSorting: EuiDataGridSorting['columns'] = getDefaultSorting(); const [sortingColumns, setSortingColumns] = useState(defaultSorting); - const onSort = (sortingColumns) => {setSortingColumns(sortingColumns)}; + const onSort = (sortingColumns) => { setSortingColumns(sortingColumns) }; /** Pagination **/ const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 20 }); const onChangeItemsPerPage = useMemo(() => (pageSize) => - setPagination((pagination) => ({ - ...pagination, - pageSize, - pageIndex: 0, - })), [rows, rowCount]); + setPagination((pagination) => ({ + ...pagination, + pageSize, + pageIndex: 0, + })), [rows, rowCount]); const onChangePage = (pageIndex) => setPagination((pagination) => ({ ...pagination, pageIndex })) useEffect(() => { @@ -72,10 +60,17 @@ export const useDataGrid = (props: tDataGridProps): EuiDataGridProps => { const rowsParsed = parseData(rows); // On the context data always is stored the current page data (pagination) // then the rowIndex is relative to the current page - const relativeRowIndex = rowIndex % pagination.pageSize; - return rowsParsed.hasOwnProperty(relativeRowIndex) - ? getFieldFormatted(relativeRowIndex, columnId, indexPattern, rowsParsed) - : null; + const relativeRowIndex = rowIndex % pagination.pageSize; + if(rowsParsed.hasOwnProperty(relativeRowIndex)){ + const fieldFormatted = getFieldFormatted(relativeRowIndex, columnId, indexPattern, rowsParsed); + // check if column have render method initialized + const column = columns.find((column) => column.id === columnId); + if (column && column.render) { + return column.render(fieldFormatted); + } + return fieldFormatted; + } + return null }; const leadingControlColumns = useMemo(() => { diff --git a/plugins/main/public/components/common/search_bar/use_search_bar_configuration.test.ts b/plugins/main/public/components/common/search_bar/use_search_bar.test.ts similarity index 77% rename from plugins/main/public/components/common/search_bar/use_search_bar_configuration.test.ts rename to plugins/main/public/components/common/search_bar/use_search_bar.test.ts index 732c827d40..dbe769a294 100644 --- a/plugins/main/public/components/common/search_bar/use_search_bar_configuration.test.ts +++ b/plugins/main/public/components/common/search_bar/use_search_bar.test.ts @@ -9,7 +9,7 @@ import { TimeRange, } from '../../../../../../src/plugins/data/public'; // wazuh plugin dependencies -import useSearchBar from './use_search_bar_configuration'; +import useSearchBar from './use_search_bar'; import { getDataPlugin } from '../../../kibana-services'; import * as timeFilterHook from '../hooks/use-time-filter'; import * as queryManagerHook from '../hooks/use-query'; @@ -41,7 +41,7 @@ mockedGetDataPlugin.mockImplementation( }, }, }, - } as Start) + } as Start), ); /////////////////////////////////////////////////////////// @@ -77,7 +77,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(); @@ -93,15 +95,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 () => { @@ -112,19 +120,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, ]); @@ -145,50 +159,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 () => { @@ -204,11 +190,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([ diff --git a/plugins/main/public/components/common/search_bar/use_search_bar_configuration.tsx b/plugins/main/public/components/common/search_bar/use_search_bar.tsx similarity index 51% rename from plugins/main/public/components/common/search_bar/use_search_bar_configuration.tsx rename to plugins/main/public/components/common/search_bar/use_search_bar.tsx index 425b53de66..037b17f075 100644 --- a/plugins/main/public/components/common/search_bar/use_search_bar_configuration.tsx +++ b/plugins/main/public/components/common/search_bar/use_search_bar.tsx @@ -17,7 +17,10 @@ import { AUTHORIZED_AGENTS } from '../../../../common/constants'; type tUseSearchBarCustomInputs = { defaultIndexPatternID: IIndexPattern['id']; onFiltersUpdated?: (filters: Filter[]) => void; - onQuerySubmitted?: (payload: { dateRange: TimeRange; query?: Query }, isUpdate?: boolean) => void; + onQuerySubmitted?: ( + payload: { dateRange: TimeRange; query?: Query }, + isUpdate?: boolean, + ) => void; }; type tUseSearchBarProps = Partial & tUseSearchBarCustomInputs; @@ -31,29 +34,46 @@ type tUserSearchBarResponse = { * @param props * @returns */ -const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarResponse => { +const useSearchBar = ( + 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 ? useState(props?.query) : useQueryManager(); + const [query, setQuery] = props?.query + ? useState(props?.query) + : useQueryManager(); const { timeFilter, timeHistory, setTimeFilter } = useTimeFilter(); // states const [isLoading, setIsLoading] = useState(false); - const [indexPatternSelected, setIndexPatternSelected] = useState(); + const [indexPatternSelected, setIndexPatternSelected] = + useState(); 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 */ @@ -61,8 +81,8 @@ const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarRe 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); }; @@ -72,7 +92,8 @@ const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarRe * @returns */ const getIndexPattern = async (indexPatternID?: string) => { - const indexPatternService = getDataPlugin().indexPatterns as IndexPatternsContract; + const indexPatternService = getDataPlugin() + .indexPatterns as IndexPatternsContract; if (indexPatternID) { try { return await indexPatternService.get(indexPatternID); @@ -87,37 +108,33 @@ const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarRe }; /** - * 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, + ); }; /** @@ -132,13 +149,28 @@ const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarRe 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 }, - _isUpdate?: boolean + _isUpdate?: boolean, ): void => { const { dateRange, query } = payload; // its necessary execute setter to apply query filters @@ -153,4 +185,4 @@ const useSearchBarConfiguration = (props?: tUseSearchBarProps): tUserSearchBarRe }; }; -export default useSearchBarConfiguration; +export default useSearchBar; diff --git a/plugins/main/public/components/common/search_bar/use_search_bar_service.ts b/plugins/main/public/components/common/search_bar/use_search_bar_service.ts new file mode 100644 index 0000000000..d7c546ccff --- /dev/null +++ b/plugins/main/public/components/common/search_bar/use_search_bar_service.ts @@ -0,0 +1,56 @@ +import { getPlugins } from '../../../kibana-services'; +import { IndexPattern, Filter, OpenSearchQuerySortValue } from "../../../../../../src/plugins/data/public"; +import { SearchResponse } from "../../../../../../src/core/server"; + +export interface SearchParams { + indexPattern: IndexPattern; + filters?: Filter[]; + query?: any; + pagination?: { + pageIndex?: number; + pageSize?: number; + }; + fields?: string[], + sorting?: { + columns: { + id: string; + direction: 'asc' | 'desc'; + }[]; + }; +} + +export const search = async (params: SearchParams): Promise => { + const { indexPattern, filters = [], query, pagination, sorting, fields } = params; + if(!indexPattern){ + return; + } + const data = getPlugins().data; + const searchSource = await data.search.searchSource.create(); + const fromField = (pagination?.pageIndex || 0) * (pagination?.pageSize || 100); + const sortOrder: OpenSearchQuerySortValue[] = sorting?.columns.map((column) => { + const sortDirection = column.direction === 'asc' ? 'asc' : 'desc'; + return { [column?.id || '']: sortDirection } as OpenSearchQuerySortValue; + }) || []; + + const searchParams = searchSource + .setParent(undefined) + .setField('filter', filters) + .setField('query', query) + .setField('sort', sortOrder) + .setField('size', pagination?.pageSize) + .setField('from', fromField) + .setField('index', indexPattern) + + // add fields + if (fields && Array.isArray(fields) && fields.length > 0){ + searchParams.setField('fields', fields); + } + try{ + return await searchParams.fetch(); + }catch(error){ + if(error.body){ + throw error.body; + } + throw error; + } +}; \ No newline at end of file diff --git a/plugins/main/public/components/common/wazuh_discover/wz_discover.tsx b/plugins/main/public/components/common/wazuh_discover/wz_discover.tsx index 0a7f50f43d..686c72252d 100644 --- a/plugins/main/public/components/common/wazuh_discover/wz_discover.tsx +++ b/plugins/main/public/components/common/wazuh_discover/wz_discover.tsx @@ -23,7 +23,7 @@ import { SearchResponse } from '../../../../../../src/core/server'; import DocViewer from '../doc_viewer/doc_viewer'; import { DiscoverNoResults } from '../../overview/vulnerabilities/common/components/no_results'; import { LoadingSpinner } from '../../overview/vulnerabilities/common/components/loading_spinner'; -import { useDataGrid } from '../data_grid/use_data_grid'; +import { useDataGrid, tDataGridColumn } from '../data_grid'; import { useDocViewer } from '../doc_viewer/use_doc_viewer'; //import './inventory.scss'; import { search, exportSearchToCSV } from '../../overview/vulnerabilities/dashboards/inventory/inventory_service'; @@ -31,39 +31,32 @@ import { ErrorHandler, ErrorFactory, HttpError } from '../../../react-services/e import { withErrorBoundary } from '../hocs'; import { HitsCounter } from '../../../kibana-integrations/discover/application/components/hits_counter'; import { formatNumWithCommas } from '../../../kibana-integrations/discover/application/helpers'; -import useSearchBarConfiguration from '../search_bar/use_search_bar_configuration'; +import useSearchBar from '../search_bar/use_search_bar'; import { getPlugins } from '../../../kibana-services'; import { ViewMode } from '../../../../../../src/plugins/embeddable/public'; import { getDiscoverPanels } from './config/chart'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; +/** + * ToDo: + * - add possibility to customize column render + * - add save query feature + */ + -export const MAX_ENTRIES_PER_QUERY = 10000; -const defaultTableColumns: EuiDataGridColumn[] = [{ - id: 'timestamp' -}, -{ - id: 'agent.name' -}, -{ - id: 'rule.description' -}, -{ - id: 'rule.level' -}, -{ - id: 'rule.id' -}] + +export const MAX_ENTRIES_PER_QUERY = 10000; type WazuhDiscoverProps = { - indexPattern: string; - tableColumns: EuiDataGridColumn[]; + indexPatternName: string; + tableColumns: tDataGridColumn[]; } -const WazuhDiscover = () => { - const { searchBarProps } = useSearchBarConfiguration({ - defaultIndexPatternID: 'wazuh-alerts-*', +const WazuhDiscover = (props: WazuhDiscoverProps) => { + const { indexPatternName, tableColumns: defaultTableColumns } = props + const { searchBarProps } = useSearchBar({ + defaultIndexPatternID: indexPatternName, }) const { isLoading, filters, query, indexPatterns } = searchBarProps; const SearchBar = getPlugins().data.ui.SearchBar;