diff --git a/CHANGELOG.md b/CHANGELOG.md index 46bd00551a..bbd2bb858c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Removed GET /elastic/statistics API endpoint [#7001](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7001) - Removed VirusTotal application in favor of Malware Detection [#7038](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7038) -## Wazuh v4.9.1 - OpenSearch Dashboards 2.13.0 - Revision 03 +## Wazuh v4.9.1 - OpenSearch Dashboards 2.13.0 - Revision 04 ### Added @@ -64,6 +64,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Fixed style when unnpinned an agent in endpoint summary section [#7015](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7015) - Fixed overflow style on a long value filter [#7021](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7021) - Fixed buttons enabled for a readonly user in `Endpoint groups` section [#7056](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7056) +- Fixed the automatic page refresh in dashboards and prevent duplicate requests [#7090](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7090) ### Changed @@ -79,6 +80,7 @@ All notable changes to the Wazuh app project will be documented in this file. - Removed the PDF report footer year [#7023](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7023) - Removed the XML autoformat function group configuration due to performance [#6999](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6999) +- Removed data grid tables from Threat hunting dashboard, GitHub panel and Office365 panel [#7086](https://github.com/wazuh/wazuh-dashboard-plugins/pull/7086) ## Wazuh v4.9.0 - OpenSearch Dashboards 2.13.0 - Revision 07 diff --git a/plugins/main/common/constants.ts b/plugins/main/common/constants.ts index 40ef55817b..7b25a1d98c 100644 --- a/plugins/main/common/constants.ts +++ b/plugins/main/common/constants.ts @@ -527,3 +527,6 @@ export const SEARCH_BAR_DEBOUNCE_UPDATE_TIME = 400; // ID used to refer the createOsdUrlStateStorage state export const OSD_URL_STATE_STORAGE_ID = 'state:storeInSessionStorage'; + +export const APP_STATE_URL_KEY = '_a'; +export const GLOBAL_STATE_URL_KEY = '_g'; diff --git a/plugins/main/public/components/common/data-grid/use-data-grid.tsx b/plugins/main/public/components/common/data-grid/use-data-grid.tsx index babf9cb790..68ff88c09e 100644 --- a/plugins/main/public/components/common/data-grid/use-data-grid.tsx +++ b/plugins/main/public/components/common/data-grid/use-data-grid.tsx @@ -261,5 +261,6 @@ export const useDataGrid = (props: tDataGridProps): EuiDataGridProps => { onChangeItemsPerPage: onChangeItemsPerPage, onChangePage: onChangePage, }, + setPagination, } as EuiDataGridProps; }; diff --git a/plugins/main/public/components/common/data-source/hooks/use-data-source.ts b/plugins/main/public/components/common/data-source/hooks/use-data-source.ts index 6a026e7b3a..0fec9b7db9 100644 --- a/plugins/main/public/components/common/data-source/hooks/use-data-source.ts +++ b/plugins/main/public/components/common/data-source/hooks/use-data-source.ts @@ -98,7 +98,6 @@ export function useDataSource< const { filters: initialFilters = [...defaultFilters], fetchFilters: initialFetchFilters = [], - fixedFilters: initialFixedFilters = [], DataSource: DataSourceConstructor, repository, factory: injectedFactory, diff --git a/plugins/main/public/components/common/hooks/saved_query/constants.ts b/plugins/main/public/components/common/hooks/saved_query/constants.ts new file mode 100644 index 0000000000..59d4f85684 --- /dev/null +++ b/plugins/main/public/components/common/hooks/saved_query/constants.ts @@ -0,0 +1 @@ +export const SAVED_QUERY = 'savedQuery'; diff --git a/plugins/main/public/components/common/hooks/saved_query/use_saved_query.ts b/plugins/main/public/components/common/hooks/saved_query/use_saved_query.ts new file mode 100644 index 0000000000..de1b8ec4f8 --- /dev/null +++ b/plugins/main/public/components/common/hooks/saved_query/use_saved_query.ts @@ -0,0 +1,185 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { useState, useEffect } from 'react'; +import { + DataPublicPluginStart, + RefreshInterval, + SavedQuery, + TimeRange, + Query, + Filter, +} from '../../../../../../../src/plugins/data/public'; +import NavigationService from '../../../../react-services/navigation-service'; +import { OSD_URL_STATE_STORAGE_ID } from '../../../../../common/constants'; +import { getDataPlugin, getUiSettings } from '../../../../kibana-services'; +import { createOsdUrlStateStorage } from '../../../../../../../src/plugins/opensearch_dashboards_utils/public'; +import OsdUrlStateStorage from '../../../../react-services/state-storage'; + +interface Options { + firstTime?: boolean; +} + +interface UseSavedQueriesProps { + queryService: DataPublicPluginStart['query']; + setTimeFilter: (timeFilter: TimeRange) => void; + setRefreshInterval: (refreshInterval: RefreshInterval) => void; + setQuery: (query?: Query) => void; + setFilters: (filters: Filter[]) => void; +} + +interface UseSavedQueriesReturn { + savedQuery?: SavedQuery; + setSavedQuery: (savedQuery: SavedQuery) => void; + clearSavedQuery: () => void; +} + +export const useSavedQuery = ( + props: UseSavedQueriesProps, +): UseSavedQueriesReturn => { + // Handle saved queries + const [savedQuery, setSavedQuery] = useState(); + const data = getDataPlugin(); + const config = getUiSettings(); + const history = NavigationService.getInstance().getHistory(); + const osdUrlStateStorage = createOsdUrlStateStorage({ + useHash: config.get(OSD_URL_STATE_STORAGE_ID), + history: history, + }); + + const getAppFilters = ( + newSavedQuery?: SavedQuery, + { firstTime }: Options = { firstTime: false }, + ) => { + const { filterManager } = props.queryService; + // When the page reloads, savedQuery starts as undefined, so retrieve the time and refreshInterval from the URL. + return firstTime + ? filterManager.getAppFilters() + : newSavedQuery?.attributes.filters ?? []; + }; + + const getQuery = ( + newSavedQuery?: SavedQuery, + { firstTime }: Options = { firstTime: false }, + ) => { + const { queryString } = props.queryService; + // When the page reloads, savedQuery starts as undefined, so retrieve the time and refreshInterval from the URL. + return firstTime + ? queryString.getQuery() + : newSavedQuery?.attributes.query ?? { query: '', language: 'kuery' }; + }; + + const getTimeFilter = ( + newSavedQuery?: SavedQuery, + { firstTime }: Options = { firstTime: false }, + ) => { + const { timefilter } = props.queryService; + // When the page reloads, savedQuery starts as undefined, so retrieve the time and refreshInterval from the URL. + return firstTime + ? timefilter.timefilter.getTime() + : newSavedQuery?.attributes.timefilter; + }; + + const getRefreshInterval = ( + newSavedQuery?: SavedQuery, + { firstTime }: Options = { firstTime: false }, + ) => { + const { timefilter } = props.queryService; + // When the page reloads, savedQuery starts as undefined, so retrieve the time and refreshInterval from the URL. + return firstTime + ? timefilter.timefilter.getRefreshInterval() + : newSavedQuery?.attributes.timefilter?.refreshInterval; + }; + + const setTimeFilter = (timeFilter: TimeRange) => { + props.setTimeFilter(timeFilter); + props.queryService.timefilter.timefilter.setTime(timeFilter); + }; + + const saveSavedQuery = async ( + newSavedQuery?: SavedQuery, + { firstTime }: Options = { firstTime: false }, + ) => { + setSavedQuery(newSavedQuery); + const filters = getAppFilters(newSavedQuery, { firstTime }); + const query = getQuery(newSavedQuery, { firstTime }); + await OsdUrlStateStorage(data, osdUrlStateStorage).replaceUrlAppState({ + savedQuery: newSavedQuery?.id, + }); + props.setFilters(filters); + props.setQuery(query); + if (newSavedQuery?.attributes.timefilter) { + setTimeFilter(getTimeFilter(newSavedQuery, { firstTime })); + props.setRefreshInterval( + getRefreshInterval(newSavedQuery, { firstTime }), + ); + } + }; + + const updateSavedQuery = async ( + savedQuery: SavedQuery, + { firstTime }: { firstTime?: boolean } = { firstTime: false }, + ) => { + saveSavedQuery(savedQuery, { firstTime }); + }; + + const clearSavedQuery = () => { + // remove saved query from url + saveSavedQuery(undefined); + }; + + // Effect is used to convert a saved query id into an object + useEffect(() => { + const fetchSavedQuery = async () => { + try { + const savedQueryId = OsdUrlStateStorage( + data, + osdUrlStateStorage, + ).getAppStateFromUrl().savedQuery as string; + if (!savedQueryId) return; + // fetch saved query + const savedQuery = await props.queryService.savedQueries.getSavedQuery( + savedQueryId, + ); + updateSavedQuery(savedQuery, { firstTime: true }); + } catch (error) { + clearSavedQuery(); + } + }; + + fetchSavedQuery(); + }, [props.queryService, props.queryService.savedQueries]); + + return { + savedQuery, + setSavedQuery: updateSavedQuery, + clearSavedQuery, + }; +}; diff --git a/plugins/main/public/components/common/hooks/use-time-filter.ts b/plugins/main/public/components/common/hooks/use-time-filter.ts index 384169f65f..f580cb38aa 100644 --- a/plugins/main/public/components/common/hooks/use-time-filter.ts +++ b/plugins/main/public/components/common/hooks/use-time-filter.ts @@ -30,15 +30,30 @@ export function useTimeFilter() { const [timeFilter, setTimeFilter] = useState( globalStateFromUrl?.time ?? timefilter.getTime(), ); + const [refreshInterval, setRefreshInterval] = useState( + globalStateFromUrl?.refreshInterval ?? timefilter.getRefreshInterval(), + ); const [timeHistory, setTimeHistory] = useState(timefilter._history); useEffect(() => { const subscription = timefilter.getTimeUpdate$().subscribe(() => { setTimeFilter(timefilter.getTime()); setTimeHistory(timefilter._history); }); + const subscriptionRefreshInterval = timefilter + .getRefreshIntervalUpdate$() + .subscribe(() => { + setRefreshInterval(timefilter.getRefreshInterval()); + }); return () => { subscription.unsubscribe(); + subscriptionRefreshInterval.unsubscribe(); }; }, []); - return { timeFilter, setTimeFilter: timefilter.setTime, timeHistory }; + return { + timeFilter, + setTimeFilter: timefilter.setTime, + refreshInterval, + setRefreshInterval: timefilter.setRefreshInterval, + timeHistory, + }; } diff --git a/plugins/main/public/components/common/permissions/button.tsx b/plugins/main/public/components/common/permissions/button.tsx index 6033960584..5f4d920e69 100644 --- a/plugins/main/public/components/common/permissions/button.tsx +++ b/plugins/main/public/components/common/permissions/button.tsx @@ -18,18 +18,19 @@ import { EuiButtonEmpty, EuiButtonIcon, EuiLink, + EuiButtonProps, } from '@elastic/eui'; import { IWzElementPermissionsProps, WzElementPermissions } from './element'; -interface IWzButtonPermissionsProps - extends Omit< - IWzElementPermissionsProps, - 'children' | 'additionalPropsFunction' - > { - buttonType?: 'default' | 'empty' | 'icon' | 'link' | 'switch'; - rest: any; -} +type IWzButtonPermissionsProps = Omit< + IWzElementPermissionsProps, + 'children' | 'additionalPropsFunction' +> & + React.ButtonHTMLAttributes & + EuiButtonProps & { + buttonType?: 'default' | 'empty' | 'icon' | 'link' | 'switch'; + }; export const WzButtonPermissions = ({ buttonType = 'default', diff --git a/plugins/main/public/components/common/search-bar/search-bar.tsx b/plugins/main/public/components/common/search-bar/search-bar.tsx index e12a317b76..7161c2cbbf 100644 --- a/plugins/main/public/components/common/search-bar/search-bar.tsx +++ b/plugins/main/public/components/common/search-bar/search-bar.tsx @@ -15,11 +15,15 @@ export interface WzSearchBarProps extends SearchBarProps { postFilters?: React.ReactElement; postFixedFilters?: () => React.ReactElement[]; hideFixedFilters?: boolean; + showSaveQueryButton?: boolean; + showSaveQuery?: boolean; } export const WzSearchBar = ({ fixedFilters = [], postFixedFilters, + showSaveQueryButton = true, + showSaveQuery = true, preQueryBar, hideFixedFilters, postFilters, @@ -52,7 +56,11 @@ export const WzSearchBar = ({ > {preQueryBar ? {preQueryBar} : null} - + ) : null} diff --git a/plugins/main/public/components/common/search-bar/use-search-bar.test.ts b/plugins/main/public/components/common/search-bar/use-search-bar.test.ts index 6b0fc60ab1..e0c04a6315 100644 --- a/plugins/main/public/components/common/search-bar/use-search-bar.test.ts +++ b/plugins/main/public/components/common/search-bar/use-search-bar.test.ts @@ -16,6 +16,8 @@ import { getDataPlugin } from '../../../kibana-services'; import * as timeFilterHook from '../hooks/use-time-filter'; import * as queryManagerHook from '../hooks/use-query'; import { AppState } from '../../../react-services/app-state'; +import NavigationService from '../../../react-services/navigation-service'; +import { createHashHistory, History } from 'history'; /** * Mocking Data Plugin @@ -23,8 +25,12 @@ import { AppState } from '../../../react-services/app-state'; jest.mock('../../../kibana-services', () => { return { getDataPlugin: jest.fn(), + getUiSettings: jest.fn().mockImplementation(() => ({ + get: () => true, + })), }; }); + /* using osd mock utils */ const mockDataPlugin = dataPluginMock.createStartContract(); const mockedGetDataPlugin = getDataPlugin as jest.Mock; @@ -42,10 +48,25 @@ mockedGetDataPlugin.mockImplementation( unsubscribe: jest.fn(), })), }, + timefilter: { + ...mockDataPlugin.query.queryString.timefilter, + timefilter: { + getRefreshInterval: jest.fn().mockImplementation(() => ({ + value: 0, + pause: false, + })), + getAutoRefreshFetch$: jest.fn().mockImplementation(() => ({ + subscribe: jest + .fn() + .mockImplementation(() => ({ unsubscribe: jest.fn() })), + })), + }, + }, }, }, } as Start), ); + /////////////////////////////////////////////////////////// const mockedDefaultIndexPatternData: Partial = { @@ -55,6 +76,9 @@ const mockedDefaultIndexPatternData: Partial = { }; describe('[hook] useSearchBarConfiguration', () => { + let history: History; + let navigationService: NavigationService; + beforeAll(() => { /***** mock use-time-filter hook *****/ const spyUseTimeFilter = jest.spyOn(timeFilterHook, 'useTimeFilter'); @@ -76,6 +100,11 @@ describe('[hook] useSearchBarConfiguration', () => { spyUseQueryManager.mockImplementation(() => [mockQueryResult, jest.fn()]); }); + beforeEach(() => { + history = createHashHistory(); + navigationService = NavigationService.getInstance(history); + }); + it('should return default app index pattern when not receiving a default index pattern', async () => { jest .spyOn(AppState, 'getCurrentPattern') @@ -87,7 +116,11 @@ describe('[hook] useSearchBarConfiguration', () => { .spyOn(mockDataPlugin.query.filterManager, 'getFilters') .mockReturnValue([]); // @ts-ignore - const { result, waitForNextUpdate } = renderHook(() => useSearchBar({})); + const { result, waitForNextUpdate } = renderHook(() => + useSearchBar({ + setFilters: jest.fn(), + }), + ); await waitForNextUpdate(); expect(mockDataPlugin.indexPatterns.getDefault).toBeCalled(); expect(result.current.searchBarProps.indexPatterns).toMatchObject([ @@ -143,7 +176,7 @@ describe('[hook] useSearchBarConfiguration', () => { const { result, waitForNextUpdate } = renderHook(() => useSearchBar({ indexPattern: mockedExampleIndexPatternData as IndexPattern, - setFilters: jest.fn() + setFilters: jest.fn(), }), ); expect(result.current.searchBarProps.indexPatterns).toMatchObject([ @@ -174,11 +207,11 @@ describe('[hook] useSearchBarConfiguration', () => { .mockReturnValue([]); const { result, waitForNextUpdate, rerender } = renderHook( // @ts-ignore - (props) => useSearchBar(props), + props => useSearchBar(props), { initialProps: { indexPattern: mockedExampleIndexPatternData as IndexPattern, - setFilters: jest.fn() + setFilters: jest.fn(), }, }, ); @@ -195,10 +228,10 @@ describe('[hook] useSearchBarConfiguration', () => { .mockResolvedValue(newExampleIndexPatternData); rerender({ indexPattern: newExampleIndexPatternData as IndexPattern, - setFilters: jest.fn() + setFilters: jest.fn(), }); expect(result.current.searchBarProps.indexPatterns).toMatchObject([ newExampleIndexPatternData, ]); - }) + }); }); diff --git a/plugins/main/public/components/common/search-bar/use-search-bar.ts b/plugins/main/public/components/common/search-bar/use-search-bar.ts index b11c0e5113..747527e217 100644 --- a/plugins/main/public/components/common/search-bar/use-search-bar.ts +++ b/plugins/main/public/components/common/search-bar/use-search-bar.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import { isEqual } from 'lodash'; import { SearchBarProps, TimeRange, @@ -9,14 +10,14 @@ import { } from '../../../../../../src/plugins/data/public'; import { getDataPlugin } from '../../../kibana-services'; import { useQueryManager, useTimeFilter } from '../hooks'; -import { transformDateRange } from './search-bar-service'; +import { useSavedQuery } from '../hooks/saved_query/use_saved_query'; // Input - types type tUseSearchBarCustomInputs = { indexPattern: IndexPattern; setFilters: (filters: Filter[]) => void; setTimeFilter?: (timeRange: TimeRange) => void; - setQuery?: (query: Query) => void; + setQuery?: (query?: Query) => void; onFiltersUpdated?: (filters: Filter[]) => void; onQuerySubmitted?: ( payload: { dateRange: TimeRange; query?: Query }, @@ -31,9 +32,10 @@ type tUserSearchBarResponse = { searchBarProps: Partial< SearchBarProps & { useDefaultBehaviors: boolean; - absoluteDateRange: TimeRange; } >; + fingerprint: number; + autoRefreshFingerprint: number; }; /** @@ -44,25 +46,40 @@ type tUserSearchBarResponse = { const useSearchBarConfiguration = ( props: tUseSearchBarProps, ): tUserSearchBarResponse => { - const { indexPattern, filters: defaultFilters, setFilters } = props; + const { indexPattern, filters = [], setFilters } = props; // dependencies const { timeFilter: globalTimeFilter, timeHistory, setTimeFilter: setGlobalTimeFilter, + setRefreshInterval, } = useTimeFilter(); - const filters = defaultFilters ?? []; const [timeFilter, setTimeFilter] = useState(globalTimeFilter); const [query, setQuery] = props?.setQuery ? useState(props?.query || { query: '', language: 'kuery' }) : useQueryManager(); - // This absoluteDateRange is used to ensure that the date range is the same when we make the - // pagination request with relative dates like "Last 24 hours" - const [absoluteDateRange, setAbsoluteDateRange] = useState( - transformDateRange(globalTimeFilter), + /* The state of the fingerprint is meant to pass this value to "lastReloadRequestTime" in + * the Dashboards embeddables so they refresh when the user clicks on the Update button in the search bar. + */ + const [fingerprint, setFingerprint] = useState(Date.now()); + + /* + This fingerprint is used for auto refresh of time filter + */ + const [autoRefreshFingerprint, setAutoRefreshFingerprint] = useState( + Date.now(), ); + + const { query: queryService } = getDataPlugin(); + const { savedQuery, setSavedQuery, clearSavedQuery } = useSavedQuery({ + queryService, + setTimeFilter, + setRefreshInterval, + setFilters, + setQuery, + }); // states const [isLoading, setIsLoading] = useState(true); const [indexPatternSelected, setIndexPatternSelected] = @@ -74,10 +91,20 @@ const useSearchBarConfiguration = ( } }, [indexPattern]); + useEffect(() => setTimeFilter(globalTimeFilter), [globalTimeFilter]); + useEffect(() => { initSearchBar(); }, []); + // Subscribe to changes in the search bar auto refresh feature (every 5 seconds, etc.) + useEffect(() => { + const subscription = queryService.timefilter.timefilter + .getAutoRefreshFetch$() + .subscribe(() => setAutoRefreshFingerprint(Date.now())); + return () => subscription.unsubscribe(); + }, []); + /** * Initialize the searchbar props with the corresponding index pattern and filters */ @@ -106,10 +133,10 @@ const useSearchBarConfiguration = ( /** * Search bar properties necessary to render and initialize the osd search bar component */ + const searchBarProps: Partial< SearchBarProps & { useDefaultBehaviors: boolean; - absoluteDateRange: TimeRange; } > = { isLoading, @@ -117,7 +144,6 @@ const useSearchBarConfiguration = ( filters, query, timeHistory, - absoluteDateRange, dateRangeFrom: timeFilter.from, dateRangeTo: timeFilter.to, onFiltersUpdated: (userFilters: Filter[]) => { @@ -126,28 +152,51 @@ const useSearchBarConfiguration = ( : console.warn('setFilters function is not defined'); props?.onFiltersUpdated && props?.onFiltersUpdated(userFilters); }, + refreshInterval: + queryService.timefilter.timefilter.getRefreshInterval().value, + isRefreshPaused: + queryService.timefilter.timefilter.getRefreshInterval().pause, + onRefreshChange: (options: { + isPaused: boolean; + refreshInterval: number; + }) => { + const { timefilter } = queryService.timefilter; + timefilter.setRefreshInterval({ + value: options.refreshInterval, + pause: options.isPaused, + }); + }, onQuerySubmit: ( payload: { dateRange: TimeRange; query?: Query }, _isUpdate?: boolean, ): void => { - const { dateRange, query } = payload; + const { dateRange: newDateRange, query: newQuery } = payload; // its necessary execute setter to apply query filters // when the hook receives the dateRange use the setter instead the global setTimeFilter props?.setTimeFilter - ? props?.setTimeFilter(dateRange) - : setGlobalTimeFilter(dateRange); - props?.setQuery ? props?.setQuery(query) : setQuery(query); + ? props?.setTimeFilter(newDateRange) + : setGlobalTimeFilter(newDateRange); + props?.setQuery ? props?.setQuery(newQuery) : setQuery(newQuery); props?.onQuerySubmitted && props?.onQuerySubmitted(payload); - setTimeFilter(dateRange); - setAbsoluteDateRange(transformDateRange(dateRange)); - setQuery(query); + // Change the fingerprint only when the search parameter are all the same. This should happen only when the user clicks on Update button + if (isEqual(newDateRange, timeFilter) && isEqual(query, newQuery)) { + setFingerprint(Date.now()); + } + + setTimeFilter(newDateRange); + setQuery(newQuery); }, // its necessary to use saved queries. if not, the load saved query not work - useDefaultBehaviors: true, + onClearSavedQuery: clearSavedQuery, + onSaved: setSavedQuery, + onSavedQueryUpdated: setSavedQuery, + savedQuery, }; return { searchBarProps, + fingerprint, + autoRefreshFingerprint, }; }; diff --git a/plugins/main/public/components/common/wazuh-discover/config/histogram-chart.ts b/plugins/main/public/components/common/wazuh-discover/config/histogram-chart.ts index 5c7966dfbd..db8a791986 100644 --- a/plugins/main/public/components/common/wazuh-discover/config/histogram-chart.ts +++ b/plugins/main/public/components/common/wazuh-discover/config/histogram-chart.ts @@ -135,6 +135,7 @@ export const histogramChartInput = ( query, dateRangeFrom, dateRangeTo, + lastReloadRequestTime, ) => ({ viewMode: ViewMode.VIEW, panels: getDiscoverPanels(indexPatternId), @@ -154,4 +155,5 @@ export const histogramChartInput = ( value: 15, }, hidePanelTitles: true, + lastReloadRequestTime, }); 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 f679f0a142..cfd96a987b 100644 --- a/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx +++ b/plugins/main/public/components/common/wazuh-discover/wz-discover.tsx @@ -12,6 +12,7 @@ import { EuiFlyoutHeader, EuiPanel, } from '@elastic/eui'; +import { TimeRange } from '../../../../../../src/plugins/data/public'; import { IntlProvider } from 'react-intl'; import { IndexPattern } from '../../../../../../src/plugins/data/common'; import { SearchResponse } from '../../../../../../src/core/server'; @@ -48,6 +49,7 @@ import { import DiscoverDataGridAdditionalControls from './components/data-grid-additional-controls'; import { wzDiscoverRenderColumns } from './render-columns'; import { WzSearchBar } from '../search-bar'; +import { transformDateRange } from '../search-bar/search-bar-service'; import DocDetailsHeader from './components/doc-details-header'; export const MAX_ENTRIES_PER_QUERY = 10000; @@ -110,13 +112,15 @@ const WazuhDiscoverComponent = (props: WazuhDiscoverProps) => { ); }; - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; - + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; + const [absoluteDateRange, setAbsoluteDateRange] = useState( + transformDateRange({ from: dateRangeFrom, to: dateRangeTo }), + ); const dataGridProps = useDataGrid({ ariaLabelledBy: 'Discover events table', defaultColumns: defaultTableColumns, @@ -129,13 +133,15 @@ const WazuhDiscoverComponent = (props: WazuhDiscoverProps) => { setFilters, }); - const { pagination, sorting, columnVisibility } = dataGridProps; + const { pagination, setPagination, sorting, columnVisibility } = + dataGridProps; useEffect(() => { if (isDataSourceLoading) { return; } setIndexPattern(dataSource?.indexPattern); + fetchData({ query, pagination, @@ -150,12 +156,27 @@ const WazuhDiscoverComponent = (props: WazuhDiscoverProps) => { }); ErrorHandler.handleError(searchError); }); + }, [absoluteDateRange, JSON.stringify(sorting), JSON.stringify(pagination)]); + + useEffect(() => { + if (isDataSourceLoading) { + return; + } + setIndexPattern(dataSource?.indexPattern); + setPagination(pagination => ({ + ...pagination, + pageIndex: 0, + })); + setAbsoluteDateRange( + transformDateRange({ from: dateRangeFrom, to: dateRangeTo }), + ); }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(sorting), - JSON.stringify(pagination), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); const timeField = indexPattern?.timeFieldName @@ -239,8 +260,9 @@ const WazuhDiscoverComponent = (props: WazuhDiscoverProps) => { AlertsRepository.getStoreIndexPatternId(), fetchFilters, query, - absoluteDateRange.from, - absoluteDateRange.to, + dateRangeFrom, + dateRangeTo, + fingerprint, )} /> diff --git a/plugins/main/public/components/common/wazuh-discover/wz-flyout-discover.tsx b/plugins/main/public/components/common/wazuh-discover/wz-flyout-discover.tsx index 93cb855a4f..f0e2e4199f 100644 --- a/plugins/main/public/components/common/wazuh-discover/wz-flyout-discover.tsx +++ b/plugins/main/public/components/common/wazuh-discover/wz-flyout-discover.tsx @@ -9,6 +9,7 @@ import { EuiPanel, EuiText, } from '@elastic/eui'; +import { TimeRange } from '../../../../../../src/plugins/data/public'; import { HitsCounter } from '../../../kibana-integrations/discover/application/components/hits_counter'; import { formatNumWithCommas } from '../../../kibana-integrations/discover/application/helpers'; import { IntlProvider } from 'react-intl'; @@ -36,6 +37,7 @@ import { } from '../data-source'; import DocDetails from './components/doc-details'; import { WzSearchBar } from '../search-bar/search-bar'; +import { transformDateRange } from '../search-bar/search-bar-service'; import { MAX_ENTRIES_PER_QUERY } from '../data-grid/data-grid-service'; export const DEFAULT_PAGE_SIZE_OPTIONS = [20, 50, 100]; export const DEFAULT_PAGE_SIZE = 20; @@ -116,7 +118,7 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { to: timeFilter.to, }); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, @@ -124,7 +126,9 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { setTimeFilter: setDateRange, } as tUseSearchBarProps); - const { absoluteDateRange } = searchBarProps; + const [absoluteDateRange, setAbsoluteDateRange] = useState( + transformDateRange({ from: dateRange.from, to: dateRange.to }), + ); const parseSorting = useMemo(() => { if (!sorting) { @@ -142,11 +146,12 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { return; } setIndexPattern(dataSource?.indexPattern); + fetchData({ query, - dateRange: absoluteDateRange, pagination, sorting: parseSorting, + dateRange: absoluteDateRange, }) .then((response: SearchResponse) => { setPagination({ @@ -154,20 +159,35 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { }); setResults(response); }) - .catch((error: HttpError) => { + .catch(error => { const searchError = ErrorFactory.create(HttpError, { error, message: 'Error fetching data', }); ErrorHandler.handleError(searchError); }); + }, [absoluteDateRange, JSON.stringify(sorting), JSON.stringify(pagination)]); + + useEffect(() => { + if (isDataSourceLoading) { + return; + } + + setPagination(pagination => ({ + ...pagination, + pageIndex: 0, + })); + setAbsoluteDateRange( + transformDateRange({ from: dateRange.from, to: dateRange.to }), + ); }, [ isDataSourceLoading, JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(sorting), - JSON.stringify(pagination), - JSON.stringify(absoluteDateRange), + dateRange.from, + dateRange.to, + fingerprint, + autoRefreshFingerprint, ]); const toggleDetails = item => { @@ -278,6 +298,7 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { {...searchBarProps} useDefaultBehaviors={false} hideFixedFilters + showSaveQueryButton={false} /> {!isDataSourceLoading && results?.hits?.total === 0 && ( @@ -307,21 +328,21 @@ const WazuhFlyoutDiscoverComponent = (props: WazuhDiscoverProps) => { : undefined } /> - {absoluteDateRange ? ( - - - - {formatUIDate(absoluteDateRange?.from)} -{' '} - {formatUIDate(absoluteDateRange?.to)} - - - - ) : null} + + + + + {`${formatUIDate( + absoluteDateRange?.from, + )} - ${formatUIDate(absoluteDateRange?.to)}`} + + + { const configurationItemsList = [ { @@ -126,6 +128,7 @@ export const ConfigurationCards = ({ value: 15, }, hidePanelTitles: false, + lastReloadRequestTime, }} /> ) : ( diff --git a/plugins/main/public/components/management/cluster/components/overview_cards.tsx b/plugins/main/public/components/management/cluster/components/overview_cards.tsx index a68bfc0d89..5b6db7ac3f 100644 --- a/plugins/main/public/components/management/cluster/components/overview_cards.tsx +++ b/plugins/main/public/components/management/cluster/components/overview_cards.tsx @@ -31,6 +31,7 @@ interface OverviewCardsProps { indexPattern: tParsedIndexPattern; clusterName?: string; filters: tFilter[]; + lastReloadRequestTime: number; } const plugins = getPlugins(); @@ -52,6 +53,7 @@ export const OverviewCards = ({ indexPattern, clusterName, filters, + lastReloadRequestTime, }: OverviewCardsProps) => { return ( <> @@ -211,7 +213,10 @@ export const OverviewCards = ({ filters: filters, useMargins: true, id: 'ct-dashboard-tab', - timeRange: searchBarProps?.absoluteDateRange, + timeRange: { + from: searchBarProps?.dateRangeFrom, + to: searchBarProps?.dateRangeTo, + }, title: 'Cluster Timelions dashboard', description: 'Dashboard of the Cluster Timelions', query: searchBarProps.query, @@ -220,6 +225,7 @@ export const OverviewCards = ({ value: 15, }, hidePanelTitles: false, + lastReloadRequestTime, }} /> diff --git a/plugins/main/public/components/management/cluster/dashboard/dashboard.tsx b/plugins/main/public/components/management/cluster/dashboard/dashboard.tsx index c4a8e64b9a..963a008e57 100644 --- a/plugins/main/public/components/management/cluster/dashboard/dashboard.tsx +++ b/plugins/main/public/components/management/cluster/dashboard/dashboard.tsx @@ -67,12 +67,12 @@ const DashboardCT: React.FC = ({ statusRunning }) => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useEffect(() => { if (isDataSourceLoading) { @@ -80,7 +80,10 @@ const DashboardCT: React.FC = ({ statusRunning }) => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { + from: dateRangeFrom, + to: dateRangeTo, + }, }) .then(results => { setResults(results); @@ -95,7 +98,10 @@ const DashboardCT: React.FC = ({ statusRunning }) => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); const setBooleans = (component: string | null) => { @@ -182,6 +188,7 @@ const DashboardCT: React.FC = ({ statusRunning }) => { results={results} indexPattern={dataSource?.indexPattern} filters={fetchFilters ?? []} + lastReloadRequestTime={fingerprint} /> ) : null} {state.showConfig ? ( @@ -192,6 +199,7 @@ const DashboardCT: React.FC = ({ statusRunning }) => { results={results} indexPatternId={dataSource?.id} filters={fetchFilters ?? []} + lastReloadRequestTime={fingerprint} /> ) : null} {state.showNodes ? : null} diff --git a/plugins/main/public/components/overview/amazon-web-services/dashboards/dashboard.tsx b/plugins/main/public/components/overview/amazon-web-services/dashboards/dashboard.tsx index 6692bdd095..c472f7bb18 100644 --- a/plugins/main/public/components/overview/amazon-web-services/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/amazon-web-services/dashboards/dashboard.tsx @@ -48,13 +48,13 @@ const DashboardAWSComponents: React.FC = ({}) => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -62,7 +62,7 @@ const DashboardAWSComponents: React.FC = ({}) => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -71,7 +71,7 @@ const DashboardAWSComponents: React.FC = ({}) => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => setResults(results)) .catch(error => { @@ -84,7 +84,10 @@ const DashboardAWSComponents: React.FC = ({}) => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( <> @@ -121,7 +124,7 @@ const DashboardAWSComponents: React.FC = ({}) => { filters: fetchFilters || [], useMargins: true, id: 'aws-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'AWS dashboard', description: 'Dashboard of the AWS', query: query, @@ -130,6 +133,7 @@ const DashboardAWSComponents: React.FC = ({}) => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/compliance-table/compliance-table.tsx b/plugins/main/public/components/overview/compliance-table/compliance-table.tsx index d186be87a9..045ad5a32c 100644 --- a/plugins/main/public/components/overview/compliance-table/compliance-table.tsx +++ b/plugins/main/public/components/overview/compliance-table/compliance-table.tsx @@ -156,13 +156,13 @@ export const ComplianceTable = withAgentSupportModule(props => { repository: new AlertsDataSourceRepository(), }); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { absoluteDateRange } = searchBarProps; + const { dateRangeFrom, dateRangeTo } = searchBarProps; const [complianceData, setComplianceData] = useState({ descriptions: {}, complianceObject: {}, @@ -232,7 +232,7 @@ export const ComplianceTable = withAgentSupportModule(props => { const data = await fetchData({ aggs, query, - dateRange: absoluteDateRange, + dateRange: dateRange, }); return data?.aggregations?.tactics?.buckets || []; @@ -257,7 +257,7 @@ export const ComplianceTable = withAgentSupportModule(props => { props.section, dataSource, searchBarProps.query, - absoluteDateRange, + { from: dateRangeFrom, to: dateRangeTo }, ]); useEffect(() => { @@ -274,14 +274,17 @@ export const ComplianceTable = withAgentSupportModule(props => { section: props.section, fetchData, query: searchBarProps.query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }); } }, [ dataSource, JSON.stringify(searchBarProps.query), JSON.stringify(fetchFilters), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( diff --git a/plugins/main/public/components/overview/docker/dashboards/dashboard.tsx b/plugins/main/public/components/overview/docker/dashboards/dashboard.tsx index e95a8a46d6..319b09994f 100644 --- a/plugins/main/public/components/overview/docker/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/docker/dashboards/dashboard.tsx @@ -48,13 +48,13 @@ const DashboardDockerComponent: React.FC = ({}) => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -62,7 +62,7 @@ const DashboardDockerComponent: React.FC = ({}) => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -71,7 +71,7 @@ const DashboardDockerComponent: React.FC = ({}) => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => setResults(results)) .catch(error => { @@ -84,7 +84,10 @@ const DashboardDockerComponent: React.FC = ({}) => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -123,7 +126,7 @@ const DashboardDockerComponent: React.FC = ({}) => { filters: fetchFilters ?? [], useMargins: true, id: 'docker-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'Docker dashboard', description: 'Dashboard of Docker', query: query, @@ -132,6 +135,7 @@ const DashboardDockerComponent: React.FC = ({}) => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/fim/dashboard/dashboard.tsx b/plugins/main/public/components/overview/fim/dashboard/dashboard.tsx index 371bfb503a..cbecbf7704 100644 --- a/plugins/main/public/components/overview/fim/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/fim/dashboard/dashboard.tsx @@ -48,13 +48,13 @@ const DashboardFIMComponent: React.FC = ({}) => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -62,7 +62,7 @@ const DashboardFIMComponent: React.FC = ({}) => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -71,7 +71,7 @@ const DashboardFIMComponent: React.FC = ({}) => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => setResults(results)) .catch(error => { @@ -84,7 +84,10 @@ const DashboardFIMComponent: React.FC = ({}) => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -125,7 +128,7 @@ const DashboardFIMComponent: React.FC = ({}) => { filters: fetchFilters ?? [], useMargins: true, id: 'fim-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'File Integrity Monitoring dashboard', description: 'Dashboard of the File Integrity Monitoring', query: query, @@ -134,6 +137,7 @@ const DashboardFIMComponent: React.FC = ({}) => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/gdpr/dashboards/dashboard.tsx b/plugins/main/public/components/overview/gdpr/dashboards/dashboard.tsx index 382ecb0af6..5d43106d47 100644 --- a/plugins/main/public/components/overview/gdpr/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/gdpr/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardGDPRComponent: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardGDPRComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardGDPRComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -85,7 +85,10 @@ const DashboardGDPRComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -124,7 +127,7 @@ const DashboardGDPRComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'gdpr-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'GDPR dashboard', description: 'Dashboard of the GDPR', query: searchBarProps.query, @@ -133,6 +136,7 @@ const DashboardGDPRComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/github/dashboards/dashboard.tsx b/plugins/main/public/components/overview/github/dashboards/dashboard.tsx index 393def651b..90a37518e6 100644 --- a/plugins/main/public/components/overview/github/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/github/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardGitHubComponent: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardGitHubComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardGitHubComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -85,7 +85,10 @@ const DashboardGitHubComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -124,7 +127,7 @@ const DashboardGitHubComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'github-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'GitHub dashboard', description: 'Dashboard of the GitHub', query: searchBarProps.query, @@ -133,6 +136,7 @@ const DashboardGitHubComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/github/panel/config/drilldown-action.tsx b/plugins/main/public/components/overview/github/panel/config/drilldown-action.tsx index 37fc626b55..d5e571faa5 100644 --- a/plugins/main/public/components/overview/github/panel/config/drilldown-action.tsx +++ b/plugins/main/public/components/overview/github/panel/config/drilldown-action.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -23,7 +23,6 @@ import { getVisStateTopRepositories, } from './visualizations'; import { ModuleConfigProps } from './module-config'; -import DrillDownDataGrid from './drilldown-data-grid'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -130,7 +129,10 @@ export const DrilldownConfigAction = (drilldownProps: ModuleConfigProps) => { filters: fetchFilters ?? [], useMargins: true, id: 'github-drilldown-action-dashboard-tab', - timeRange: searchBarProps?.absoluteDateRange, + timeRange: { + from: searchBarProps.dateRangeFrom, + to: searchBarProps.dateRangeTo, + }, title: 'GitHub drilldown action dashboard', description: 'Dashboard of the GitHub drilldown action', query: searchBarProps.query, @@ -148,38 +150,6 @@ export const DrilldownConfigAction = (drilldownProps: ModuleConfigProps) => { }, ], }, - { - columns: [ - { - width: 100, - component: () => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description' }, - { id: 'data.github.org', displayAsText: 'Organization' }, - { id: 'data.github.repo', displayAsText: 'Repository' }, - { id: 'data.github.actor', displayAsText: 'Actor' }, - { id: 'rule.level' }, - { id: 'rule.id' }, - ]; - - return ( - - ); - }, - }, - ], - }, ], }; }; diff --git a/plugins/main/public/components/overview/github/panel/config/drilldown-actor.tsx b/plugins/main/public/components/overview/github/panel/config/drilldown-actor.tsx index bcc3eb720c..42cb7381b8 100644 --- a/plugins/main/public/components/overview/github/panel/config/drilldown-actor.tsx +++ b/plugins/main/public/components/overview/github/panel/config/drilldown-actor.tsx @@ -10,18 +10,9 @@ * Find more information about this on the LICENSE file. */ -import React, { useState, useMemo, useEffect } from 'react'; -import { - EuiFlexItem, - EuiPanel, - EuiToolTip, - EuiButtonIcon, - EuiDataGridCellValueElementProps, - EuiDataGrid, - EuiLink, -} from '@elastic/eui'; +import React from 'react'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -32,14 +23,6 @@ import { getVisStateTopRepositories, } from './visualizations'; import { ModuleConfigProps } from './module-config'; -import { - ErrorFactory, - HttpError, - ErrorHandler, -} from '../../../../../react-services/error-management'; -import DrillDownDataGrid from './drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -146,7 +129,10 @@ export const DrilldownConfigActor = (drilldownProps: ModuleConfigProps) => { filters: fetchFilters ?? [], useMargins: true, id: 'github-drilldown-action-dashboard-tab', - timeRange: searchBarProps?.absoluteDateRange, + timeRange: { + from: searchBarProps.dateRangeFrom, + to: searchBarProps.dateRangeTo, + }, title: 'GitHub drilldown action dashboard', description: 'Dashboard of the GitHub drilldown action', query: searchBarProps.query, @@ -164,38 +150,6 @@ export const DrilldownConfigActor = (drilldownProps: ModuleConfigProps) => { }, ], }, - { - columns: [ - { - width: 100, - component: () => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description' }, - { id: 'data.github.org', displayAsText: 'Organization' }, - { id: 'data.github.repo', displayAsText: 'Repository' }, - { id: 'data.github.action', displayAsText: 'Action' }, - { id: 'rule.level' }, - { id: 'rule.id' }, - ]; - - return ( - - ); - }, - }, - ], - }, ], }; }; diff --git a/plugins/main/public/components/overview/github/panel/config/drilldown-data-grid.tsx b/plugins/main/public/components/overview/github/panel/config/drilldown-data-grid.tsx deleted file mode 100644 index 0a5c8aa15d..0000000000 --- a/plugins/main/public/components/overview/github/panel/config/drilldown-data-grid.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { EuiFlexItem } from '@elastic/eui'; -import { ModuleConfigProps } from './module-config'; -import { - ErrorFactory, - HttpError, - ErrorHandler, -} from '../../../../../react-services/error-management'; -import WazuhDataGrid from '../../../../common/wazuh-data-grid/wz-data-grid'; -import { tDataGridColumn } from '../../../../common/data-grid'; - -type tDrillDownDataGridProps = { - defaultTableColumns: tDataGridColumn[]; -} & ModuleConfigProps; - -export default function DrillDownDataGrid(props: tDrillDownDataGridProps) { - const [results, setResults] = useState([]); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 15, - pageSizeOptions: [15, 25, 50, 100], - }); - const [sorting, setSorting] = useState([]); - - const { - fetchData, - searchBarProps, - indexPattern, - fetchFilters, - defaultTableColumns, - } = props; - - useEffect(() => { - if (!indexPattern) { - return; - } - fetchData({ - query: searchBarProps.query, - filters: fetchFilters, - pagination, - sorting, - dateRange: searchBarProps.absoluteDateRange, - }) - .then(results => { - setResults(results); - }) - .catch(error => { - const searchError = ErrorFactory.create(HttpError, { - error, - message: 'Error fetching data', - }); - ErrorHandler.handleError(searchError); - }); - }, [ - JSON.stringify(fetchFilters), - JSON.stringify(searchBarProps.query), - JSON.stringify(pagination), - JSON.stringify(sorting), - JSON.stringify(searchBarProps.absoluteDateRange), - ]); - - return ( - - setPagination(pagination)} - onChangeSorting={sorting => { - setSorting(sorting); - }} - dateRange={searchBarProps?.absoluteDateRange} - /> - - ); -} diff --git a/plugins/main/public/components/overview/github/panel/config/drilldown-organization.tsx b/plugins/main/public/components/overview/github/panel/config/drilldown-organization.tsx index 37b5427ae2..ece1caad00 100644 --- a/plugins/main/public/components/overview/github/panel/config/drilldown-organization.tsx +++ b/plugins/main/public/components/overview/github/panel/config/drilldown-organization.tsx @@ -10,19 +10,9 @@ * Find more information about this on the LICENSE file. */ -import React, { useState, useMemo, useEffect } from 'react'; -import { - EuiFlexItem, - EuiPanel, - EuiToolTip, - EuiButtonIcon, - EuiDataGridCellValueElementProps, - EuiDataGrid, - EuiLink, -} from '@elastic/eui'; -import { SecurityAlerts } from '../../../../visualize/components'; +import React from 'react'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -33,14 +23,6 @@ import { getVisStateTopActions, } from './visualizations'; import { ModuleConfigProps } from './module-config'; -import { - ErrorFactory, - HttpError, - ErrorHandler, -} from '../../../../../react-services/error-management'; -import DrillDownDataGrid from './drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -149,7 +131,10 @@ export const DrilldownConfigOrganization = ( filters: fetchFilters ?? [], useMargins: true, id: 'github-drilldown-action-dashboard-tab', - timeRange: searchBarProps?.absoluteDateRange, + timeRange: { + from: searchBarProps.dateRangeFrom, + to: searchBarProps.dateRangeTo, + }, title: 'GitHub drilldown action dashboard', description: 'Dashboard of the GitHub drilldown action', query: searchBarProps.query, @@ -167,38 +152,6 @@ export const DrilldownConfigOrganization = ( }, ], }, - { - columns: [ - { - width: 100, - component: () => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description' }, - { id: 'data.github.repo', displayAsText: 'Repository' }, - { id: 'data.github.actor', displayAsText: 'Actor' }, - { id: 'data.github.action', displayAsText: 'Action' }, - { id: 'rule.level' }, - { id: 'rule.id' }, - ]; - - return ( - - ); - }, - }, - ], - }, ], }; }; diff --git a/plugins/main/public/components/overview/github/panel/config/drilldown-repository.tsx b/plugins/main/public/components/overview/github/panel/config/drilldown-repository.tsx index 83639b34fb..28bf58517e 100644 --- a/plugins/main/public/components/overview/github/panel/config/drilldown-repository.tsx +++ b/plugins/main/public/components/overview/github/panel/config/drilldown-repository.tsx @@ -11,9 +11,8 @@ */ import React from 'react'; -import { EuiLink } from '@elastic/eui'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -24,13 +23,6 @@ import { getVisStateTopOrganizations, } from './visualizations'; import { ModuleConfigProps } from './module-config'; -import { - ErrorFactory, - HttpError, - ErrorHandler, -} from '../../../../../react-services/error-management'; -import DrillDownDataGrid from './drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -139,7 +131,10 @@ export const DrilldownConfigRepository = ( filters: fetchFilters ?? [], useMargins: true, id: 'github-drilldown-action-dashboard-tab', - timeRange: searchBarProps?.absoluteDateRange, + timeRange: { + from: searchBarProps.dateRangeFrom, + to: searchBarProps.dateRangeTo, + }, title: 'GitHub drilldown action dashboard', description: 'Dashboard of the GitHub drilldown action', query: searchBarProps.query, @@ -157,47 +152,6 @@ export const DrilldownConfigRepository = ( }, ], }, - { - columns: [ - { - width: 100, - component: () => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description' }, - { id: 'data.github.org', displayAsText: 'Organization' }, - { id: 'data.github.actor', displayAsText: 'Actor' }, - { id: 'data.github.action', displayAsText: 'Action' }, - { id: 'rule.level' }, - { - id: 'rule.id', - render: value => ( - - {value} - - ), - }, - ]; - - return ( - - ); - }, - }, - ], - }, ], }; }; diff --git a/plugins/main/public/components/overview/google-cloud/dashboards/dashboard.tsx b/plugins/main/public/components/overview/google-cloud/dashboards/dashboard.tsx index 1566f0d965..630bfb4c74 100644 --- a/plugins/main/public/components/overview/google-cloud/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/google-cloud/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardGoogleCloudComponent: React.FC = () => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardGoogleCloudComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardGoogleCloudComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => setResults(results)) .catch(error => { @@ -83,7 +83,10 @@ const DashboardGoogleCloudComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -123,7 +126,7 @@ const DashboardGoogleCloudComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'google-cloud-detector-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'Google Cloud detector dashboard', description: 'Dashboard of the Google Cloud', query: searchBarProps.query, @@ -132,6 +135,7 @@ const DashboardGoogleCloudComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/hipaa/dashboards/dashboard.tsx b/plugins/main/public/components/overview/hipaa/dashboards/dashboard.tsx index 812b515537..7327d8bf44 100644 --- a/plugins/main/public/components/overview/hipaa/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/hipaa/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardHIPAAComponent: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardHIPAAComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardHIPAAComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -85,7 +85,10 @@ const DashboardHIPAAComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -124,7 +127,7 @@ const DashboardHIPAAComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'hipaa-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'HIPAA dashboard', description: 'Dashboard of the HIPAA', query: searchBarProps.query, @@ -133,6 +136,7 @@ const DashboardHIPAAComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/malware-detection/dashboard/dashboard.tsx b/plugins/main/public/components/overview/malware-detection/dashboard/dashboard.tsx index 8d5b4b12df..37a60ea493 100644 --- a/plugins/main/public/components/overview/malware-detection/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/malware-detection/dashboard/dashboard.tsx @@ -48,13 +48,13 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -62,7 +62,7 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -71,7 +71,7 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => setResults(results)) .catch(error => { @@ -84,7 +84,10 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -125,7 +128,7 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { filters: fetchFilters ?? [], useMargins: true, id: 'malware-detection-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'Malware Detection dashboard', description: 'Dashboard of the Malware Detection', query: query, @@ -134,6 +137,7 @@ const DashboardMalwareDetectionComponent: React.FC = ({}) => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/mitre/dashboard/dashboard.tsx b/plugins/main/public/components/overview/mitre/dashboard/dashboard.tsx index deaf0f5056..3d4fb28912 100644 --- a/plugins/main/public/components/overview/mitre/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/mitre/dashboard/dashboard.tsx @@ -45,12 +45,12 @@ export const DashboardMITRE: React.FC = () => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -58,7 +58,7 @@ export const DashboardMITRE: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -67,7 +67,7 @@ export const DashboardMITRE: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -82,7 +82,10 @@ export const DashboardMITRE: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -121,7 +124,7 @@ export const DashboardMITRE: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'mitre-dashboard-tab-filters', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'MITRE dashboard filters', description: 'Dashboard of the MITRE filters', query: query, @@ -130,6 +133,7 @@ export const DashboardMITRE: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/mitre/framework/mitre.tsx b/plugins/main/public/components/overview/mitre/framework/mitre.tsx index 9a37658387..7ed5f4aee0 100644 --- a/plugins/main/public/components/overview/mitre/framework/mitre.tsx +++ b/plugins/main/public/components/overview/mitre/framework/mitre.tsx @@ -68,13 +68,13 @@ const MitreComponent = props => { repository: new AlertsDataSourceRepository(), }); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters: setFilters, }); - const { absoluteDateRange } = searchBarProps; + const { dateRangeFrom, dateRangeTo } = searchBarProps; const [mitreState, setMitreState] = useState({ tacticsObject: {}, selectedTactics: {}, @@ -83,7 +83,10 @@ const MitreComponent = props => { const [filterParams, setFilterParams] = useState({ filters: fetchFilters, query: searchBarProps?.query, - time: absoluteDateRange, + time: { + from: dateRangeFrom, + to: dateRangeTo, + }, }); const [indexPattern, setIndexPattern] = useState(); //Todo: Add correct type const [isLoading, setIsLoading] = useState(true); @@ -93,7 +96,10 @@ const MitreComponent = props => { let filterParams = { filters: fetchFilters, // pass the fetchFilters to use it as initial filters in the technique flyout query: searchBarProps?.query, - time: absoluteDateRange, + time: { + from: dateRangeFrom, + to: dateRangeTo, + }, }; setFilterParams(filterParams); setIsLoading(true); @@ -108,7 +114,10 @@ const MitreComponent = props => { dataSource, searchBarProps.query, JSON.stringify(filters), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); const buildTacticsObject = async () => { diff --git a/plugins/main/public/components/overview/nist/dashboards/dashboard.tsx b/plugins/main/public/components/overview/nist/dashboards/dashboard.tsx index 017efa65f3..8f22366375 100644 --- a/plugins/main/public/components/overview/nist/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/nist/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardNIST80053Component: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardNIST80053Component: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardNIST80053Component: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -85,7 +85,10 @@ const DashboardNIST80053Component: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -124,7 +127,7 @@ const DashboardNIST80053Component: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'nist-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'NIST 800-53 dashboard', description: 'Dashboard of the NIST 800-53', query: searchBarProps.query, @@ -133,6 +136,7 @@ const DashboardNIST80053Component: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/office/dashboard/dashboard.tsx b/plugins/main/public/components/overview/office/dashboard/dashboard.tsx index b3b48d1e5b..c95b9bb26a 100644 --- a/plugins/main/public/components/overview/office/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/office/dashboard/dashboard.tsx @@ -47,12 +47,12 @@ const DashboardOffice365Component: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -60,7 +60,7 @@ const DashboardOffice365Component: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -69,7 +69,7 @@ const DashboardOffice365Component: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -84,7 +84,10 @@ const DashboardOffice365Component: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -123,7 +126,7 @@ const DashboardOffice365Component: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'kpis-th-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'KPIs Office 365 dashboard', description: 'KPIs Dashboard of the Office 365', query: searchBarProps.query, @@ -132,6 +135,7 @@ const DashboardOffice365Component: React.FC = () => { value: 15, }, hidePanelTitles: true, + lastReloadRequestTime: fingerprint, }} /> { filters: fetchFilters ?? [], useMargins: true, id: 'office-365-detector-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'Office 365 detector dashboard', description: 'Dashboard of the Office 365', query: searchBarProps.query, @@ -153,6 +157,7 @@ const DashboardOffice365Component: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/office/panel/config/drilldown-ip-config.tsx b/plugins/main/public/components/overview/office/panel/config/drilldown-ip-config.tsx index c0946559b7..837f6cd0b0 100644 --- a/plugins/main/public/components/overview/office/panel/config/drilldown-ip-config.tsx +++ b/plugins/main/public/components/overview/office/panel/config/drilldown-ip-config.tsx @@ -13,9 +13,8 @@ */ import React from 'react'; -import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -24,9 +23,6 @@ import { getVisStateOfficeUserOperationLevel, getVisStateOfficeAlertsEvolutionByUser, } from './visualizations'; -import DrillDownDataGrid from '../../../github/panel/config/drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -99,7 +95,7 @@ const getDashboardPanels = ( }; export const drilldownIPConfig = props => { - const { fetchData, fetchFilters, searchBarProps, indexPattern } = props; + const { fetchFilters, searchBarProps, indexPattern } = props; return { rows: [ @@ -108,33 +104,6 @@ export const drilldownIPConfig = props => { { width: 100, component: props => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description', displayAsText: 'Description' }, - { id: 'data.office365.UserId', displayAsText: 'User ID' }, - { - id: 'data.office365.Operation', - displayAsText: 'Operation', - }, - { id: 'rule.level', displayAsText: 'Level' }, - { - id: 'rule.id', - render: value => ( - - - {value} - - - ), - }, - ]; - return (
{ }} onInputUpdated={() => {}} /> - - -
); }, diff --git a/plugins/main/public/components/overview/office/panel/config/drilldown-operations-config.tsx b/plugins/main/public/components/overview/office/panel/config/drilldown-operations-config.tsx index 4a700d8b28..f12d4c42bb 100644 --- a/plugins/main/public/components/overview/office/panel/config/drilldown-operations-config.tsx +++ b/plugins/main/public/components/overview/office/panel/config/drilldown-operations-config.tsx @@ -12,9 +12,8 @@ */ import React from 'react'; -import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -22,9 +21,6 @@ import { getVisStateOfficeCountryTagCloud, getVisStateOfficeAlertsEvolutionByUserID, } from './visualizations'; -import DrillDownDataGrid from '../../../github/panel/config/drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -83,7 +79,7 @@ const getDashboardPanels = ( }; export const drilldownOperationsConfig = props => { - const { fetchData, fetchFilters, searchBarProps, indexPattern } = props; + const { fetchFilters, searchBarProps, indexPattern } = props; return { rows: [ @@ -92,32 +88,6 @@ export const drilldownOperationsConfig = props => { { width: 100, component: props => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description', displayAsText: 'Description' }, - { id: 'data.office365.UserId', displayAsText: 'User ID' }, - { - id: 'data.office365.ClientIP', - displayAsText: 'Client IP address', - }, - { id: 'rule.level', displayAsText: 'Level' }, - { - id: 'rule.id', - render: value => ( - - - {value} - - - ), - }, - ]; return (
{ }} onInputUpdated={() => {}} /> - - -
); }, diff --git a/plugins/main/public/components/overview/office/panel/config/drilldown-rules-config.tsx b/plugins/main/public/components/overview/office/panel/config/drilldown-rules-config.tsx index 04fba33db7..7990b1a64c 100644 --- a/plugins/main/public/components/overview/office/panel/config/drilldown-rules-config.tsx +++ b/plugins/main/public/components/overview/office/panel/config/drilldown-rules-config.tsx @@ -12,9 +12,8 @@ */ import React from 'react'; -import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -23,9 +22,6 @@ import { getVisStateOfficeCountryTagCloud, getVisStateOfficeAlertsEvolutionByUserID, } from './visualizations'; -import DrillDownDataGrid from '../../../github/panel/config/drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -98,7 +94,7 @@ const getDashboardPanels = ( }; export const drilldownRulesConfig = props => { - const { fetchData, fetchFilters, searchBarProps, indexPattern } = props; + const { fetchFilters, searchBarProps, indexPattern } = props; return { rows: [ @@ -107,37 +103,6 @@ export const drilldownRulesConfig = props => { { width: 100, component: props => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description', displayAsText: 'Description' }, - { id: 'data.office365.UserId', displayAsText: 'User ID' }, - { - id: 'data.office365.ClientIP', - displayAsText: 'Client IP address', - }, - { - id: 'data.office365.Operation', - displayAsText: 'Operation', - }, - { id: 'rule.level', displayAsText: 'Level' }, - { - id: 'rule.id', - render: value => ( - - - {value} - - - ), - }, - ]; - return (
{ }} onInputUpdated={() => {}} /> - - -
); }, diff --git a/plugins/main/public/components/overview/office/panel/config/drilldown-user-config.tsx b/plugins/main/public/components/overview/office/panel/config/drilldown-user-config.tsx index 6e7ec543c8..4e91891993 100644 --- a/plugins/main/public/components/overview/office/panel/config/drilldown-user-config.tsx +++ b/plugins/main/public/components/overview/office/panel/config/drilldown-user-config.tsx @@ -13,9 +13,8 @@ */ import React from 'react'; -import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { ViewMode } from '../../../../../../../../src/plugins/embeddable/public'; -import { getPlugins, getCore } from '../../../../../kibana-services'; +import { getPlugins } from '../../../../../kibana-services'; import { DashboardPanelState } from '../../../../../../../../src/plugins/dashboard/public/application'; import { EmbeddableInput } from '../../../../../../../../src/plugins/embeddable/public'; import { @@ -24,9 +23,6 @@ import { getVisStateOfficeTopsEventsPie, getVisStateOfficeMetricStats, } from './visualizations'; -import DrillDownDataGrid from '../../../github/panel/config/drilldown-data-grid'; -import { rules } from '../../../../../utils/applications'; -import { RedirectAppLinks } from '../../../../../../../../src/plugins/opensearch_dashboards_react/public'; const DashboardByRenderer = getPlugins().dashboard.DashboardContainerByValueRenderer; @@ -99,7 +95,7 @@ const getDashboardPanels = ( }; export const drilldownUserConfig = props => { - const { fetchData, fetchFilters, searchBarProps, indexPattern } = props; + const { fetchFilters, searchBarProps, indexPattern } = props; return { rows: [ @@ -108,36 +104,6 @@ export const drilldownUserConfig = props => { { width: 100, component: props => { - const defaultTableColumns = [ - { - id: 'timestamp', - isSortable: true, - defaultSortDirection: 'desc', - }, - { id: 'rule.description', displayAsText: 'Description' }, - { - id: 'data.office365.ClientIP', - displayAsText: 'Client IP address', - }, - { - id: 'data.office365.Operation', - displayAsText: 'Operation', - }, - { id: 'rule.level', displayAsText: 'Level' }, - { - id: 'rule.id', - render: value => ( - - - {value} - - - ), - }, - ]; - return (
{ }} onInputUpdated={() => {}} /> - - -
); }, diff --git a/plugins/main/public/components/overview/overview.tsx b/plugins/main/public/components/overview/overview.tsx index 56afe727c8..de7a53e7de 100644 --- a/plugins/main/public/components/overview/overview.tsx +++ b/plugins/main/public/components/overview/overview.tsx @@ -5,7 +5,10 @@ import { Stats } from '../../controllers/overview/components/stats'; import { AppState, WzRequest } from '../../react-services'; import { OverviewWelcome } from '../common/welcome/overview-welcome'; import { MainModule } from '../common/modules/main'; -import { OSD_URL_STATE_STORAGE_ID } from '../../../common/constants'; +import { + APP_STATE_URL_KEY, + OSD_URL_STATE_STORAGE_ID, +} from '../../../common/constants'; import { WzCurrentOverviewSectionWrapper } from '../common/modules/overview-current-section-wrapper'; import { connectToQueryState, @@ -57,7 +60,9 @@ export const Overview: React.FC = withRouteResolvers({ history: history, }); - const appStateFromUrl = osdUrlStateStorage.get('_a') as AppState; + const appStateFromUrl = osdUrlStateStorage.get( + APP_STATE_URL_KEY, + ) as AppState; let initialAppState = { query: migrateLegacyQuery(data.query.queryString.getDefaultQuery()), ...appStateFromUrl, @@ -74,11 +79,11 @@ export const Overview: React.FC = withRouteResolvers({ const replaceUrlAppState = async (newPartial: AppState = {}) => { const state = { ...appStateContainer.getState(), ...newPartial }; - await osdUrlStateStorage.set('_a', state, { replace: true }); + await osdUrlStateStorage.set(APP_STATE_URL_KEY, state, { replace: true }); }; const { start, stop } = syncState({ - storageKey: '_a', + storageKey: APP_STATE_URL_KEY, stateContainer: appStateContainerModified, stateStorage: osdUrlStateStorage, }); diff --git a/plugins/main/public/components/overview/pci/dashboards/dashboard.tsx b/plugins/main/public/components/overview/pci/dashboards/dashboard.tsx index 64305d0b5c..c13e878cc4 100644 --- a/plugins/main/public/components/overview/pci/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/pci/dashboards/dashboard.tsx @@ -48,13 +48,13 @@ const DashboardPCIDSSComponent: React.FC = () => { const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -62,7 +62,7 @@ const DashboardPCIDSSComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -71,7 +71,7 @@ const DashboardPCIDSSComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -86,7 +86,10 @@ const DashboardPCIDSSComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -125,7 +128,7 @@ const DashboardPCIDSSComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'pci-dss-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'PCI DSS dashboard', description: 'Dashboard of the PCI DSS', query: searchBarProps.query, @@ -134,6 +137,7 @@ const DashboardPCIDSSComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboardTabsPanels.tsx b/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboardTabsPanels.tsx index b261d69619..ad78f306d1 100644 --- a/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboardTabsPanels.tsx +++ b/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboardTabsPanels.tsx @@ -72,13 +72,13 @@ export const DashboardTabsPanels = ({ "Analysisd statistics refer to the data stored from the period indicated in the variable 'analysisd.state_interval'.", }; - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useEffect(() => { if (isDataSourceLoading) { @@ -86,7 +86,10 @@ export const DashboardTabsPanels = ({ } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { + from: dateRangeFrom, + to: dateRangeTo, + }, }) .then(results => { setResults(results); @@ -101,7 +104,10 @@ export const DashboardTabsPanels = ({ }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); const selectedNodeFilter: tFilter = { @@ -168,6 +174,7 @@ export const DashboardTabsPanels = ({ = ({ @@ -22,6 +23,7 @@ const DashboardStatistics: React.FC = ({ indexPatternId, filters, searchBarProps, + lastReloadRequestTime, }) => { return (
@@ -48,6 +50,7 @@ const DashboardStatistics: React.FC = ({ value: 15, }, hidePanelTitles: false, + lastReloadRequestTime, }} />
diff --git a/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboard_listener_engine.tsx b/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboard_listener_engine.tsx index 8396e180f8..0ba50b68c7 100644 --- a/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboard_listener_engine.tsx +++ b/plugins/main/public/components/overview/server-management-statistics/dashboards/dashboard_listener_engine.tsx @@ -14,12 +14,14 @@ interface DashboardStatisticsProps { indexPatternId: string; filters: tFilter[]; searchBarProps: any; + lastReloadRequestTime: number; } const DashboardStatistics: React.FC = ({ indexPatternId, filters, searchBarProps, + lastReloadRequestTime, }) => { return (
@@ -43,6 +45,7 @@ const DashboardStatistics: React.FC = ({ value: 15, }, hidePanelTitles: false, + lastReloadRequestTime, }} />
diff --git a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx index ba380ff059..6ab8a40b54 100644 --- a/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx +++ b/plugins/main/public/components/overview/threat-hunting/dashboard/dashboard.tsx @@ -1,5 +1,5 @@ -import React, { useState, useEffect, useMemo } from 'react'; -import { getPlugins, getWazuhCorePlugin } from '../../../../kibana-services'; +import React, { useState, useEffect } from 'react'; +import { getPlugins } from '../../../../kibana-services'; import { ViewMode } from '../../../../../../../src/plugins/embeddable/public'; import { SearchResponse } from '../../../../../../../src/core/server'; import { IndexPattern } from '../../../../../../../src/plugins/data/common'; @@ -7,39 +7,14 @@ import { getDashboardPanels } from './dashboard_panels'; import { I18nProvider } from '@osd/i18n/react'; import useSearchBar from '../../../common/search-bar/use-search-bar'; import { getKPIsPanel } from './dashboard_panels_kpis'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiButtonIcon, - EuiDataGrid, - EuiToolTip, - EuiDataGridCellValueElementProps, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiTitle, - EuiButtonEmpty, -} from '@elastic/eui'; import { ErrorFactory, ErrorHandler, HttpError, } from '../../../../react-services/error-management'; -import { - MAX_ENTRIES_PER_QUERY, - exportSearchToCSV, - getAllCustomRenders, -} from '../../../common/data-grid/data-grid-service'; -import { useDocViewer } from '../../../common/doc-viewer/use-doc-viewer'; -import { useDataGrid } from '../../../common/data-grid/use-data-grid'; -import DocViewer from '../../../common/doc-viewer/doc-viewer'; import { withErrorBoundary } from '../../../common/hocs/error-boundary/with-error-boundary'; import './threat_hunting_dashboard.scss'; import { SampleDataWarning } from '../../../visualize/components/sample-data-warning'; -import { - threatHuntingTableAgentColumns, - threatHuntingTableDefaultColumns, -} from '../events/threat-hunting-columns'; import { AlertsDataSourceRepository, ThreatHuntingDataSource, @@ -51,11 +26,7 @@ import { import { DiscoverNoResults } from '../../../common/no-results/no-results'; import { LoadingSearchbarProgress } from '../../../common/loading-searchbar-progress/loading-searchbar-progress'; import { useReportingCommunicateSearchContext } from '../../../common/hooks/use-reporting-communicate-search-context'; -import { wzDiscoverRenderColumns } from '../../../common/wazuh-discover/render-columns'; import { WzSearchBar } from '../../../common/search-bar'; -import DiscoverDataGridAdditionalControls from '../../../common/wazuh-discover/components/data-grid-additional-controls'; - -import DocDetailsHeader from '../../../common/wazuh-discover/components/doc-details-header'; const plugins = getPlugins(); @@ -75,80 +46,25 @@ const DashboardTH: React.FC = () => { DataSource: ThreatHuntingDataSource, repository: AlertsRepository, }); - const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ - indexPattern: dataSource?.indexPattern as IndexPattern, - filters, - setFilters, - }); - const { query, absoluteDateRange } = searchBarProps; - - const [inspectedHit, setInspectedHit] = useState(undefined); - const [isExporting, setIsExporting] = useState(false); - - const sideNavDocked = getWazuhCorePlugin().hooks.useDockedSideNav(); - - const onClickInspectDoc = useMemo( - () => (index: number) => { - const rowClicked = results.hits.hits[index]; - setInspectedHit(rowClicked); - }, - [results], - ); - - const DocViewInspectButton = ({ - rowIndex, - }: EuiDataGridCellValueElementProps) => { - const inspectHintMsg = 'Inspect document details'; - return ( - - onClickInspectDoc(rowIndex)} - iconType='inspect' - aria-label={inspectHintMsg} - /> - - ); - }; - - const dataGridProps = useDataGrid({ - ariaLabelledBy: 'Threat Hunting Table', - defaultColumns: threatHuntingTableDefaultColumns, - renderColumns: wzDiscoverRenderColumns, - results, + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, - DocViewInspectButton, filters, setFilters, }); - - const { pagination, sorting, columnVisibility } = dataGridProps; - - const docViewerProps = useDocViewer({ - doc: inspectedHit, - indexPattern: dataSource?.indexPattern as IndexPattern, - }); - + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; const pinnedAgent = PatternDataSourceFilterManager.getPinnedAgentFilter(dataSource?.id!) .length > 0; - useEffect(() => { - const currentColumns = !pinnedAgent - ? threatHuntingTableDefaultColumns - : threatHuntingTableAgentColumns; - columnVisibility.setVisibleColumns(currentColumns.map(({ id }) => id)); - }, [pinnedAgent]); - useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, totalResults: results?.hits?.total ?? 0, indexPattern: dataSource?.indexPattern as IndexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -157,9 +73,7 @@ const DashboardTH: React.FC = () => { } fetchData({ query, - pagination, - sorting, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -174,37 +88,12 @@ const DashboardTH: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(pagination), - JSON.stringify(sorting), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + autoRefreshFingerprint, + fingerprint, ]); - const onClickExportResults = async () => { - const params = { - indexPattern: dataSource?.indexPattern, - filters: fetchFilters ?? [], - query, - fields: columnVisibility.visibleColumns, - pagination: { - pageIndex: 0, - pageSize: results.hits.total, - }, - sorting, - }; - try { - setIsExporting(true); - await exportSearchToCSV(params); - } catch (error) { - const searchError = ErrorFactory.create(HttpError, { - error, - message: 'Error downloading csv report', - }); - ErrorHandler.handleError(searchError); - } finally { - setIsExporting(false); - } - }; - return ( {isDataSourceLoading && !dataSource ? ( @@ -242,7 +131,7 @@ const DashboardTH: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'kpis-th-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'KPIs Threat Hunting dashboard', description: 'KPIs Dashboard of the Threat Hunting', query: query, @@ -251,6 +140,7 @@ const DashboardTH: React.FC = () => { value: 15, }, hidePanelTitles: true, + lastReloadRequestTime: fingerprint, }} /> { filters: fetchFilters ?? [], useMargins: true, id: 'th-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'Threat Hunting dashboard', description: 'Dashboard of the Threat Hunting', query: query, @@ -273,52 +163,9 @@ const DashboardTH: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> -
- {!isDataSourceLoading ? ( - - - - ), - }} - /> - ) : null} -
- {inspectedHit && ( - setInspectedHit(undefined)} size='m'> - - - - - - - - - - - - )} diff --git a/plugins/main/public/components/overview/tsc/dashboards/dashboard.tsx b/plugins/main/public/components/overview/tsc/dashboards/dashboard.tsx index dfb3da8ee1..0d931901d6 100644 --- a/plugins/main/public/components/overview/tsc/dashboards/dashboard.tsx +++ b/plugins/main/public/components/overview/tsc/dashboards/dashboard.tsx @@ -47,13 +47,13 @@ const DashboardTSCComponent: React.FC = () => { }); const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint, autoRefreshFingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, }); - const { query, absoluteDateRange } = searchBarProps; + const { query, dateRangeFrom, dateRangeTo } = searchBarProps; useReportingCommunicateSearchContext({ isSearching: isDataSourceLoading, @@ -61,7 +61,7 @@ const DashboardTSCComponent: React.FC = () => { indexPattern: dataSource?.indexPattern, filters: fetchFilters, query: query, - time: absoluteDateRange, + time: { from: dateRangeFrom, to: dateRangeTo }, }); useEffect(() => { @@ -70,7 +70,7 @@ const DashboardTSCComponent: React.FC = () => { } fetchData({ query, - dateRange: absoluteDateRange, + dateRange: { from: dateRangeFrom, to: dateRangeTo }, }) .then(results => { setResults(results); @@ -85,7 +85,10 @@ const DashboardTSCComponent: React.FC = () => { }, [ JSON.stringify(fetchFilters), JSON.stringify(query), - JSON.stringify(absoluteDateRange), + dateRangeFrom, + dateRangeTo, + fingerprint, + autoRefreshFingerprint, ]); return ( @@ -124,7 +127,7 @@ const DashboardTSCComponent: React.FC = () => { filters: fetchFilters ?? [], useMargins: true, id: 'tsc-dashboard-tab', - timeRange: absoluteDateRange, + timeRange: { from: dateRangeFrom, to: dateRangeTo }, title: 'TSC dashboard', description: 'Dashboard of the TSC', query: searchBarProps.query, @@ -133,6 +136,7 @@ const DashboardTSCComponent: React.FC = () => { value: 15, }, hidePanelTitles: false, + lastReloadRequestTime: fingerprint, }} /> diff --git a/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx b/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx index 4786bf71a1..e4b46f97be 100644 --- a/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx +++ b/plugins/main/public/components/overview/vulnerabilities/dashboards/inventory/inventory.tsx @@ -69,7 +69,7 @@ const InventoryVulsComponent = () => { DataSource: VulnerabilitiesDataSource, repository: new VulnerabilitiesDataSourceRepository(), }); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, @@ -174,6 +174,7 @@ const InventoryVulsComponent = () => { JSON.stringify(query), JSON.stringify(pagination), JSON.stringify(sorting), + fingerprint, ]); /** diff --git a/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard.tsx b/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard.tsx index 7398da1bb4..5a54969f05 100644 --- a/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard.tsx +++ b/plugins/main/public/components/overview/vulnerabilities/dashboards/overview/dashboard.tsx @@ -66,7 +66,7 @@ const DashboardVulsComponent: React.FC = ({ const [results, setResults] = useState({} as SearchResponse); - const { searchBarProps } = useSearchBar({ + const { searchBarProps, fingerprint } = useSearchBar({ indexPattern: dataSource?.indexPattern as IndexPattern, filters, setFilters, @@ -130,117 +130,125 @@ const DashboardVulsComponent: React.FC = ({ {isDataSourceLoading && !dataSource ? ( ) : ( - ( - - ), - ]} - showDatePicker={false} - showQueryInput={true} - showQueryBar={true} - showSaveQuery={true} - /> - )} - {dataSource && results?.hits?.total === 0 ? ( - - ) : null} -
0 ? '' : 'wz-no-display' - }`} - > - -
- + ( + ), - isFullScreenMode: false, - filters: fetchFilters ?? [], - useMargins: false, - id: 'vulnerability-detector-dashboard-tab-filters', - timeRange: { - from: searchBarProps.dateRangeFrom, - to: searchBarProps.dateRangeTo, - }, - title: 'Vulnerability detector dashboard filters', - description: - 'Dashboard of the Vulnerability detector filters', - query: searchBarProps.query, - refreshConfig: { - pause: false, - value: 15, - }, - hidePanelTitles: true, - }} + ]} + showDatePicker={false} + showQueryInput={true} + showQueryBar={true} + showSaveQuery={true} /> -
- -
+ + {dataSource && results?.hits?.total === 0 ? ( + + ) : null} +
0 ? '' : 'wz-no-display' + }`} + > + +
+ +
+ +
+ + )}
diff --git a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts index f0b57c0625..5832153eff 100644 --- a/plugins/main/public/controllers/management/components/management/common/resources-handler.ts +++ b/plugins/main/public/controllers/management/components/management/common/resources-handler.ts @@ -63,9 +63,8 @@ export class ResourcesHandler { /** * Get the content of any type of file Rules, Decoders, CDB lists... - * @param {String} fileName */ - async getFileContent(fileName, relativeDirname) { + async getFileContent(fileName: string, relativeDirname?: string) { try { const result: any = await WzRequest.apiReq( 'GET', diff --git a/plugins/main/public/kibana-services.ts b/plugins/main/public/kibana-services.ts index 1c536dc5e1..f8d96e0301 100644 --- a/plugins/main/public/kibana-services.ts +++ b/plugins/main/public/kibana-services.ts @@ -8,7 +8,7 @@ import { ScopedHistory, ToastsStart, AppMountParameters, -} from 'opensearch_dashboards/public'; +} from '../../../src/core/public'; import { createGetterSetter } from '../../../src/plugins/opensearch_dashboards_utils/common'; import { DataPublicPluginStart } from '../../../src/plugins/data/public'; import { VisualizationsStart } from '../../../src/plugins/visualizations/public'; diff --git a/plugins/main/public/react-services/index.ts b/plugins/main/public/react-services/index.ts index 8c4e47644b..5a14164e9d 100644 --- a/plugins/main/public/react-services/index.ts +++ b/plugins/main/public/react-services/index.ts @@ -22,3 +22,4 @@ export * from './wz-user-permissions'; export * from './query-config'; export * from './elastic_helpers'; export * from './check-index'; +export * from './state-storage'; diff --git a/plugins/main/public/react-services/state-storage.ts b/plugins/main/public/react-services/state-storage.ts new file mode 100644 index 0000000000..d0ca3d63dc --- /dev/null +++ b/plugins/main/public/react-services/state-storage.ts @@ -0,0 +1,42 @@ +import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; +import { + createStateContainer, + IOsdUrlStateStorage, + syncState as _syncState, +} from '../../../../src/plugins/opensearch_dashboards_utils/public'; +import { AppState } from './app-state'; +import { migrateLegacyQuery } from '../utils/migrate_legacy_query'; +import { APP_STATE_URL_KEY } from '../../common/constants'; + +const OsdUrlStateStorage = ( + data: DataPublicPluginStart, + osdUrlStateStorage: IOsdUrlStateStorage, +) => { + const getAppStateFromUrl = () => { + return osdUrlStateStorage.get(APP_STATE_URL_KEY) as AppState; + }; + + const getAppStateContainer = () => { + const defaultQuery = migrateLegacyQuery( + data.query.queryString.getDefaultQuery(), + ); + let initialAppState = { + query: defaultQuery, + ...getAppStateFromUrl(), + }; + return createStateContainer(initialAppState); + }; + + const replaceUrlAppState = async (newPartial: AppState = {}) => { + const state = { ...getAppStateContainer().getState(), ...newPartial }; + await osdUrlStateStorage.set(APP_STATE_URL_KEY, state, { replace: true }); + }; + + return { + getAppStateFromUrl, + getAppStateContainer, + replaceUrlAppState, + }; +}; + +export default OsdUrlStateStorage;