From 557451ed815b2d2fe3d1a42721986d41d29e7437 Mon Sep 17 00:00:00 2001 From: Ishan Date: Wed, 11 Mar 2026 12:53:30 +0530 Subject: [PATCH] feat: Option to zoom out OR reset zoom in the explorer pages (#10464) * feat: zoom out func ladder added * feat: zoom out feature with testcases * fix: comments resolved moved to signoz btn added testcase for querydelete * feat: updated btn compoent to use prefix icon * feat: historical enddate preset as null to preserve custom * fix: cursor bot callback and localstorage * feat: common util for local storage * feat: rename and testcase * feat: avoid persist for non preset --- .../CustomTimePicker.styles.scss | 27 ++- .../CustomTimePicker.test.tsx | 9 + .../CustomTimePicker/CustomTimePicker.tsx | 34 +++- .../customTimePickerZoomOut.test.tsx | 169 ++++++++++++++++++ .../TopNav/DateTimeSelectionV2/index.tsx | 17 +- .../src/hooks/__tests__/useZoomOut.test.ts | 160 +++++++++++++++++ frontend/src/hooks/useZoomOut.ts | 79 ++++++++ .../src/lib/__tests__/zoomOutUtils.test.ts | 147 +++++++++++++++ frontend/src/lib/zoomOutUtils.ts | 139 ++++++++++++++ frontend/src/utils/metricsTimeStorageUtils.ts | 28 +++ 10 files changed, 793 insertions(+), 16 deletions(-) create mode 100644 frontend/src/components/CustomTimePicker/__tests__/customTimePickerZoomOut.test.tsx create mode 100644 frontend/src/hooks/__tests__/useZoomOut.test.ts create mode 100644 frontend/src/hooks/useZoomOut.ts create mode 100644 frontend/src/lib/__tests__/zoomOutUtils.test.ts create mode 100644 frontend/src/lib/zoomOutUtils.ts create mode 100644 frontend/src/utils/metricsTimeStorageUtils.ts diff --git a/frontend/src/components/CustomTimePicker/CustomTimePicker.styles.scss b/frontend/src/components/CustomTimePicker/CustomTimePicker.styles.scss index adf6e98269..38d8456467 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePicker.styles.scss +++ b/frontend/src/components/CustomTimePicker/CustomTimePicker.styles.scss @@ -1,6 +1,31 @@ .custom-time-picker { display: flex; - flex-direction: column; + flex-direction: row; + align-items: center; + gap: 4px; + + .zoom-out-btn { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + color: var(--foreground); + border: 1px solid var(--border); + border-radius: 2px; + box-shadow: none; + padding: 10px; + height: 33px; + + &:hover:not(:disabled) { + color: var(--bg-vanilla-100); + background: var(--primary); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } .timeSelection-input { &:hover { diff --git a/frontend/src/components/CustomTimePicker/CustomTimePicker.test.tsx b/frontend/src/components/CustomTimePicker/CustomTimePicker.test.tsx index a752f49361..78387187ac 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePicker.test.tsx +++ b/frontend/src/components/CustomTimePicker/CustomTimePicker.test.tsx @@ -16,6 +16,15 @@ jest.mock('react-router-dom', () => { }; }); +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useDispatch: jest.fn(() => jest.fn()), + useSelector: jest.fn(() => ({ + minTime: 0, + maxTime: Date.now(), + })), +})); + jest.mock('providers/Timezone', () => { const actual = jest.requireActual('providers/Timezone'); diff --git a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx index a1b2c582ec..008f63357f 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx +++ b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx @@ -7,9 +7,11 @@ import { useState, } from 'react'; import { useLocation } from 'react-router-dom'; +import { Button } from '@signozhq/button'; import { Input, InputRef, Popover, Tooltip } from 'antd'; import cx from 'classnames'; import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats'; +import { QueryParams } from 'constants/query'; import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal'; import { FixedDurationSuggestionOptions, @@ -17,9 +19,11 @@ import { RelativeDurationSuggestionOptions, } from 'container/TopNav/DateTimeSelectionV2/constants'; import dayjs from 'dayjs'; +import { useZoomOut } from 'hooks/useZoomOut'; import { isValidShortHandDateTimeFormat } from 'lib/getMinMax'; +import { isZoomOutDisabled } from 'lib/zoomOutUtils'; import { defaultTo, isFunction, noop } from 'lodash-es'; -import { ChevronDown, ChevronUp } from 'lucide-react'; +import { ChevronDown, ChevronUp, ZoomOut } from 'lucide-react'; import { useTimezone } from 'providers/Timezone'; import { getTimeDifference, validateEpochRange } from 'utils/epochUtils'; import { popupContainer } from 'utils/selectPopupContainer'; @@ -66,6 +70,8 @@ interface CustomTimePickerProps { showRecentlyUsed?: boolean; minTime: number; maxTime: number; + /** When true, zoom-out button is hidden (e.g. in drawer/modal time selection) */ + isModalTimeSelection?: boolean; } function CustomTimePicker({ @@ -88,6 +94,7 @@ function CustomTimePicker({ showRecentlyUsed = true, minTime, maxTime, + isModalTimeSelection = false, }: CustomTimePickerProps): JSX.Element { const [ selectedTimePlaceholderValue, @@ -116,6 +123,14 @@ function CustomTimePicker({ const [isOpenedFromFooter, setIsOpenedFromFooter] = useState(false); + const durationMs = (maxTime - minTime) / 1e6; + const zoomOutDisabled = showLiveLogs || isZoomOutDisabled(durationMs); + + const handleZoomOut = useZoomOut({ + isDisabled: zoomOutDisabled, + urlParamsToDelete: [QueryParams.activeLogId], + }); + // function to get selected time in Last 1m, Last 2h, Last 3d, Last 4w format // 1m, 2h, 3d, 4w -> Last 1 minute, Last 2 hours, Last 3 days, Last 4 weeks const getSelectedTimeRangeLabelInRelativeFormat = ( @@ -631,6 +646,23 @@ function CustomTimePicker({ /> + {!showLiveLogs && !isModalTimeSelection && ( + + +