From 3c2bc06e6ae777de1664535e0fee3a65fbdf1fc8 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Thu, 23 May 2024 22:39:29 +0530 Subject: [PATCH] feat: added drag select in time series chart for logs explorer page (#5068) * feat: added drag select in time series chart for logs explorer page * fix: handle back navigation properly --- .../TimeSeriesView/TimeSeriesView.tsx | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/frontend/src/container/TimeSeriesView/TimeSeriesView.tsx b/frontend/src/container/TimeSeriesView/TimeSeriesView.tsx index bd7f32b153..973ea3a5c0 100644 --- a/frontend/src/container/TimeSeriesView/TimeSeriesView.tsx +++ b/frontend/src/container/TimeSeriesView/TimeSeriesView.tsx @@ -1,16 +1,24 @@ import './TimeSeriesView.styles.scss'; import Uplot from 'components/Uplot'; +import { QueryParams } from 'constants/query'; import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch'; import LogsError from 'container/LogsError/LogsError'; import { LogsLoading } from 'container/LogsLoading/LogsLoading'; import NoLogs from 'container/NoLogs/NoLogs'; +import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config'; import { useIsDarkMode } from 'hooks/useDarkMode'; +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 { isEmpty } from 'lodash-es'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; +import { 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 { SuccessResponse } from 'types/api'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; @@ -30,6 +38,10 @@ function TimeSeriesView({ }: TimeSeriesViewProps): JSX.Element { const graphRef = useRef(null); + const dispatch = useDispatch(); + const urlQuery = useUrlQuery(); + const location = useLocation(); + const chartData = useMemo(() => getUPlotChartData(data?.payload), [ data?.payload, ]); @@ -59,7 +71,60 @@ function TimeSeriesView({ setMaxTimeScale(endTime); }, [maxTime, minTime, globalSelectedInterval, data]); + const onDragSelect = useCallback( + (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, + ]); + + urlQuery.set(QueryParams.startTime, minTime.toString()); + urlQuery.set(QueryParams.endTime, maxTime.toString()); + urlQuery.delete(QueryParams.relativeTime); + const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; + history.push(generatedUrl); + }, + [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); + const relativeTime = searchParams.get( + QueryParams.relativeTime, + ) as CustomTimeType; + + if (relativeTime) { + dispatch(UpdateTimeInterval(relativeTime)); + } else 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 chartOptions = getUPlotChartOptions({ + onDragSelect, yAxisUnit: yAxisUnit || '', apiResponse: data?.payload, dimensions: {