diff --git a/frontend/src/container/GridCardLayout/GridCard/index.tsx b/frontend/src/container/GridCardLayout/GridCard/index.tsx index 1b388e0802..cf8d106224 100644 --- a/frontend/src/container/GridCardLayout/GridCard/index.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/index.tsx @@ -1,10 +1,15 @@ +import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { useStepInterval } from 'hooks/queryBuilder/useStepInterval'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { useResizeObserver } from 'hooks/useDimensions'; import { useIntersectionObserver } from 'hooks/useIntersectionObserver'; +import useUrlQuery from 'hooks/useUrlQuery'; import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; +import GetMinMax from 'lib/getMinMax'; +import getTimeString from 'lib/getTimeString'; +import history from 'lib/history'; import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions'; import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData'; import isEmpty from 'lodash-es/isEmpty'; @@ -12,6 +17,7 @@ import _noop from 'lodash-es/noop'; import { useDashboard } from 'providers/Dashboard/Dashboard'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { useLocation } from 'react-router-dom'; import { UpdateTimeInterval } from 'store/actions'; import { AppState } from 'store/reducers'; import { GlobalReducer } from 'types/reducer/globalTime'; @@ -37,6 +43,12 @@ function GridCardGraph({ const { toScrollWidgetId, setToScrollWidgetId } = useDashboard(); const [minTimeScale, setMinTimeScale] = useState(); const [maxTimeScale, setMaxTimeScale] = useState(); + const urlQuery = useUrlQuery(); + const location = useLocation(); + const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector< + AppState, + GlobalReducer + >((state) => state.globalTime); const onDragSelect = useCallback( (start: number, end: number): void => { @@ -46,10 +58,44 @@ function GridCardGraph({ if (startTimestamp !== endTimestamp) { dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp])); } + + const { maxTime, minTime } = GetMinMax('custom', [ + startTimestamp, + endTimestamp, + ]); + + urlQuery.set(QueryParams.startTime, minTime.toString()); + urlQuery.set(QueryParams.endTime, maxTime.toString()); + const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; + history.push(generatedUrl); }, - [dispatch], + [dispatch, location.pathname, urlQuery], ); + const handleBackNavigation = (): void => { + const searchParams = new URLSearchParams(window.location.search); + const startTime = searchParams.get(QueryParams.startTime); + const endTime = searchParams.get(QueryParams.endTime); + + if (startTime && endTime && startTime !== endTime) { + dispatch( + UpdateTimeInterval('custom', [ + parseInt(getTimeString(startTime), 10), + parseInt(getTimeString(endTime), 10), + ]), + ); + } + }; + + useEffect(() => { + window.addEventListener('popstate', handleBackNavigation); + + return (): void => { + window.removeEventListener('popstate', handleBackNavigation); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const graphRef = useRef(null); const isVisible = useIntersectionObserver(graphRef, undefined, true); @@ -70,11 +116,6 @@ function GridCardGraph({ const isEmptyWidget = widget?.id === PANEL_TYPES.EMPTY_WIDGET || isEmpty(widget); - const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector< - AppState, - GlobalReducer - >((state) => state.globalTime); - const queryResponse = useGetQueryRange( { selectedTime: widget?.timePreferance, diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index b73b78411c..36db03b567 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -13,6 +13,7 @@ import { convertRawQueriesToTraceSelectedTags, resourceAttributesToTagFilterItems, } from 'hooks/useResourceAttribute/utils'; +import useUrlQuery from 'hooks/useUrlQuery'; import history from 'lib/history'; import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin'; import { useCallback, useMemo, useState } from 'react'; @@ -52,8 +53,10 @@ function Application(): JSX.Element { ); const { servicename } = useParams(); const [selectedTimeStamp, setSelectedTimeStamp] = useState(0); - const { search } = useLocation(); + const { search, pathname } = useLocation(); const { queries } = useResourceAttribute(); + const urlQuery = useUrlQuery(); + const selectedTags = useMemo( () => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [], [queries], @@ -157,11 +160,16 @@ function Application(): JSX.Element { const startTimestamp = Math.trunc(start); const endTimestamp = Math.trunc(end); + urlQuery.set(QueryParams.startTime, startTimestamp.toString()); + urlQuery.set(QueryParams.endTime, endTimestamp.toString()); + const generatedUrl = `${pathname}?${urlQuery.toString()}`; + history.replace(generatedUrl); + if (startTimestamp !== endTimestamp) { dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp])); } }, - [dispatch], + [dispatch, pathname, urlQuery], ); const onErrorTrackHandler = (timestamp: number): (() => void) => (): void => { diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx index 08b65fa9c1..f4a8ed1b22 100644 --- a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx @@ -1,14 +1,19 @@ +import { QueryParams } from 'constants/query'; import GridPanelSwitch from 'container/GridPanelSwitch'; import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { useResizeObserver } from 'hooks/useDimensions'; import useUrlQuery from 'hooks/useUrlQuery'; +import GetMinMax from 'lib/getMinMax'; +import getTimeString from 'lib/getTimeString'; +import history from 'lib/history'; import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions'; import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { UseQueryResult } from 'react-query'; import { useDispatch, useSelector } from 'react-redux'; +import { useLocation } from 'react-router-dom'; import { UpdateTimeInterval } from 'store/actions'; import { AppState } from 'store/reducers'; import { SuccessResponse } from 'types/api'; @@ -35,6 +40,7 @@ function WidgetGraph({ const [minTimeScale, setMinTimeScale] = useState(); const [maxTimeScale, setMaxTimeScale] = useState(); + const location = useLocation(); useEffect((): void => { const { startTime, endTime } = getTimeRange(getWidgetQueryRange); @@ -64,14 +70,47 @@ function WidgetGraph({ (start: number, end: number): void => { const startTimestamp = Math.trunc(start); const endTimestamp = Math.trunc(end); - if (startTimestamp !== endTimestamp) { dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp])); } + + const { maxTime, minTime } = GetMinMax('custom', [ + startTimestamp, + endTimestamp, + ]); + + params.set(QueryParams.startTime, minTime.toString()); + params.set(QueryParams.endTime, maxTime.toString()); + const generatedUrl = `${location.pathname}?${params.toString()}`; + history.push(generatedUrl); }, - [dispatch], + [dispatch, location.pathname, params], ); + const handleBackNavigation = (): void => { + const searchParams = new URLSearchParams(window.location.search); + const startTime = searchParams.get(QueryParams.startTime); + const endTime = searchParams.get(QueryParams.endTime); + + if (startTime && endTime && startTime !== endTime) { + dispatch( + UpdateTimeInterval('custom', [ + parseInt(getTimeString(startTime), 10), + parseInt(getTimeString(endTime), 10), + ]), + ); + } + }; + + useEffect(() => { + window.addEventListener('popstate', handleBackNavigation); + + return (): void => { + window.removeEventListener('popstate', handleBackNavigation); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const options = useMemo( () => getUPlotChartOptions({ diff --git a/frontend/src/container/TopNav/DateTimeSelection/index.tsx b/frontend/src/container/TopNav/DateTimeSelection/index.tsx index 2c93e9eebd..c72ff7b82d 100644 --- a/frontend/src/container/TopNav/DateTimeSelection/index.tsx +++ b/frontend/src/container/TopNav/DateTimeSelection/index.tsx @@ -196,7 +196,7 @@ function DateTimeSelection({ urlQuery.set(QueryParams.startTime, minTime.toString()); urlQuery.set(QueryParams.endTime, maxTime.toString()); const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; - history.replace(generatedUrl); + history.push(generatedUrl); } if (!stagedQuery) { @@ -233,7 +233,7 @@ function DateTimeSelection({ endTimeMoment?.toDate().getTime().toString(), ); const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; - history.replace(generatedUrl); + history.push(generatedUrl); } } }