Compare commits

...

2 Commits

Author SHA1 Message Date
Yunus M
fce3198f68 feat: implement useUrlYAxisUnit hook for y-axis unit management 2026-03-09 15:03:48 +05:30
Yunus M
8c58905c80 feat: update url with y-axis unit 2026-03-09 13:41:24 +05:30
5 changed files with 72 additions and 26 deletions

View File

@@ -55,4 +55,5 @@ export enum QueryParams {
source = 'source',
showClassicCreateAlertsPage = 'showClassicCreateAlertsPage',
isTestAlert = 'isTestAlert',
yAxisUnit = 'yAxisUnit',
}

View File

@@ -39,6 +39,7 @@ import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQuery
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQueryData from 'hooks/useUrlQueryData';
import useUrlYAxisUnit from 'hooks/useUrlYAxisUnit';
import { isEmpty, isUndefined } from 'lodash-es';
import LiveLogs from 'pages/LiveLogs';
import { UpdateTimeInterval } from 'store/actions';
@@ -59,6 +60,7 @@ import LogsActionsContainer from './LogsActionsContainer';
import './LogsExplorerViews.styles.scss';
// eslint-disable-next-line sonarjs/cognitive-complexity
function LogsExplorerViewsContainer({
setIsLoadingQueries,
listQueryKeyRef,
@@ -109,7 +111,7 @@ function LogsExplorerViewsContainer({
const [orderBy, setOrderBy] = useState<string>('timestamp:desc');
const [yAxisUnit, setYAxisUnit] = useState<string>('');
const { yAxisUnit, onUnitChange } = useUrlYAxisUnit('');
const listQuery = useMemo(() => getListQuery(stagedQuery) || null, [
stagedQuery,
@@ -367,10 +369,6 @@ function LogsExplorerViewsContainer({
orderBy,
]);
const onUnitChangeHandler = useCallback((value: string): void => {
setYAxisUnit(value);
}, []);
const chartData = useMemo(() => {
if (!stagedQuery) {
return [];
@@ -488,10 +486,7 @@ function LogsExplorerViewsContainer({
{selectedPanelType === PANEL_TYPES.TIME_SERIES && !showLiveLogs && (
<div className="time-series-view-container">
<div className="time-series-view-container-header">
<BuilderUnitsFilter
onChange={onUnitChangeHandler}
yAxisUnit={yAxisUnit}
/>
<BuilderUnitsFilter onChange={onUnitChange} yAxisUnit={yAxisUnit} />
</div>
<TimeSeriesView
isLoading={isLoading || isFetching}

View File

@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useMemo } from 'react';
import { useQueries } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
@@ -11,6 +11,7 @@ import { BuilderUnitsFilter } from 'container/QueryBuilder/filters/BuilderUnitsF
import TimeSeriesView from 'container/TimeSeriesView/TimeSeriesView';
import { convertDataValueToMs } from 'container/TimeSeriesView/utils';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useUrlYAxisUnit from 'hooks/useUrlYAxisUnit';
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
import { useErrorModal } from 'providers/ErrorModalProvider';
import { AppState } from 'store/reducers';
@@ -22,14 +23,13 @@ import { GlobalReducer } from 'types/reducer/globalTime';
function TimeSeries(): JSX.Element {
const { stagedQuery, currentQuery } = useQueryBuilder();
const { yAxisUnit, onUnitChange } = useUrlYAxisUnit('');
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const [yAxisUnit, setYAxisUnit] = useState<string>('');
const isValidToConvertToMs = useMemo(() => {
const isValid: boolean[] = [];
@@ -112,10 +112,6 @@ function TimeSeries(): JSX.Element {
[data, isValidToConvertToMs],
);
const onUnitChangeHandler = (value: string): void => {
setYAxisUnit(value);
};
const hasMetricSelected = useMemo(
() => currentQuery.builder.queryData.some((q) => q.aggregateAttribute?.key),
[currentQuery],
@@ -123,7 +119,7 @@ function TimeSeries(): JSX.Element {
return (
<div className="meter-time-series-container">
<BuilderUnitsFilter onChange={onUnitChangeHandler} yAxisUnit={yAxisUnit} />
<BuilderUnitsFilter onChange={onUnitChange} yAxisUnit={yAxisUnit} />
<div className="time-series-container">
{!hasMetricSelected && <EmptyMetricsSearch />}
{hasMetricSelected &&

View File

@@ -0,0 +1,59 @@
import { useCallback, useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { QueryParams } from 'constants/query';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
interface UseUrlYAxisUnitResult {
yAxisUnit: string;
onUnitChange: (value: string) => void;
}
/**
* Hook to manage y-axis unit synchronized with the URL query param.
* It:
* - Initializes from `QueryParams.yAxisUnit` or a provided default
* - Keeps local state in sync when the URL changes (e.g. back/forward, shared links)
* - Writes updates back to the URL while preserving existing query params
*/
function useUrlYAxisUnit(defaultUnit = ''): UseUrlYAxisUnitResult {
const urlQuery = useUrlQuery();
const location = useLocation();
const { safeNavigate } = useSafeNavigate();
const initialUnit = urlQuery.get(QueryParams.yAxisUnit) ?? defaultUnit;
const [yAxisUnit, setYAxisUnit] = useState<string>(initialUnit);
// Sync yAxisUnit when URL param changes (e.g. browser back or shared link)
useEffect(() => {
const fromUrl = urlQuery.get(QueryParams.yAxisUnit) ?? defaultUnit;
if (fromUrl !== yAxisUnit) {
setYAxisUnit(fromUrl);
}
// Only react to URL param changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [location.search]);
const onUnitChange = useCallback(
(value: string): void => {
setYAxisUnit(value);
const params = new URLSearchParams(urlQuery);
if (value) {
params.set(QueryParams.yAxisUnit, value);
} else {
params.delete(QueryParams.yAxisUnit);
}
safeNavigate({
pathname: location.pathname,
search: `?${params.toString()}`,
});
},
[location.pathname, safeNavigate, urlQuery],
);
return { yAxisUnit, onUnitChange };
}
export default useUrlYAxisUnit;

View File

@@ -4,7 +4,6 @@ import {
SetStateAction,
useEffect,
useMemo,
useState,
} from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
@@ -16,6 +15,7 @@ import TimeSeriesView from 'container/TimeSeriesView/TimeSeriesView';
import { convertDataValueToMs } from 'container/TimeSeriesView/utils';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useUrlYAxisUnit from 'hooks/useUrlYAxisUnit';
import { AppState } from 'store/reducers';
import { Warning } from 'types/api';
import APIError from 'types/api/error';
@@ -52,13 +52,8 @@ function TimeSeriesViewContainer({
return isValid.every(Boolean);
}, [currentQuery]);
const [yAxisUnit, setYAxisUnit] = useState<string>(
isValidToConvertToMs ? 'ms' : 'short',
);
const onUnitChangeHandler = (value: string): void => {
setYAxisUnit(value);
};
const defaultUnit = isValidToConvertToMs ? 'ms' : 'short';
const { yAxisUnit, onUnitChange } = useUrlYAxisUnit(defaultUnit);
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
AppState,
@@ -121,7 +116,7 @@ function TimeSeriesViewContainer({
return (
<div className="trace-explorer-time-series-view-container">
<div className="trace-explorer-time-series-view-container-header">
<BuilderUnitsFilter onChange={onUnitChangeHandler} yAxisUnit={yAxisUnit} />
<BuilderUnitsFilter onChange={onUnitChange} yAxisUnit={yAxisUnit} />
</div>
<TimeSeriesView
isFilterApplied={isFilterApplied}