Compare commits

..

2 Commits

Author SHA1 Message Date
Naman Verma
d5ea5d448a Merge branch 'main' into nv/8189 2026-03-02 08:57:16 +05:30
Naman Verma
be243006c9 fix: exclude internal attributes from promQL results 2026-03-02 08:52:23 +05:30
5 changed files with 3 additions and 203 deletions

View File

@@ -1,9 +1,7 @@
import { MutableRefObject, useEffect } from 'react';
import { useQueryClient } from 'react-query';
import { Button, Tooltip } from 'antd';
import { LogsExplorerShortcuts } from 'constants/shortcuts/logsExplorerShortcuts';
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
import { ZoomOut } from 'lucide-react';
import RunQueryBtn from '../RunQueryBtn/RunQueryBtn';
@@ -15,7 +13,6 @@ interface RightToolbarActionsProps {
listQueryKeyRef?: MutableRefObject<any>;
chartQueryKeyRef?: MutableRefObject<any>;
showLiveLogs?: boolean;
onZoomOut?: () => void;
}
export default function RightToolbarActions({
@@ -24,7 +21,6 @@ export default function RightToolbarActions({
listQueryKeyRef,
chartQueryKeyRef,
showLiveLogs,
onZoomOut,
}: RightToolbarActionsProps): JSX.Element {
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
@@ -62,14 +58,6 @@ export default function RightToolbarActions({
return (
<div className="right-toolbar-actions-container">
<Tooltip title="Zoom out">
<Button
type="text"
icon={<ZoomOut size={16} />}
className="zoom-out-btn"
onClick={(): void => onZoomOut?.()}
/>
</Tooltip>
<RunQueryBtn
isLoadingQueries={isLoadingQueries}
handleCancelQuery={handleCancelQuery}

View File

@@ -19,20 +19,6 @@
display: flex;
align-items: center;
gap: 8px;
.zoom-out-btn {
display: flex;
align-items: center;
justify-content: center;
color: var(--bg-vanilla-100);
border: none;
box-shadow: none;
&:hover {
color: var(--bg-vanilla-100);
background: rgba(255, 255, 255, 0.1);
}
}
}
}
@@ -63,16 +49,5 @@
.toolbar {
border-top: 1px solid var(--bg-vanilla-300);
border-bottom: 1px solid var(--bg-vanilla-300);
.right-toolbar-actions-container {
.zoom-out-btn {
color: var(--bg-ink-200);
&:hover {
color: var(--bg-ink-300);
background: rgba(0, 0, 0, 0.06);
}
}
}
}
}

View File

@@ -1,111 +0,0 @@
/**
* Logs Explorer zoom-out ladder:
* - 3x until 1 day: 15m → 45m → 2h15m → 6h45m → 20h15m
* - Then fixed: 1d → 2d → 3d → 1w → 2w → 1m
* - After 1 month: wrap to 15m
*/
import type { Time } from 'container/TopNav/DateTimeSelectionV2/types';
const MS_PER_MIN = 60 * 1000;
const MS_PER_HOUR = 60 * MS_PER_MIN;
const MS_PER_DAY = 24 * MS_PER_HOUR;
const MS_PER_WEEK = 7 * MS_PER_DAY;
/** Ladder steps in milliseconds (ordered from smallest to largest) */
const ZOOM_OUT_LADDER_MS: number[] = [
15 * MS_PER_MIN, // 15m
45 * MS_PER_MIN, // 45m
2 * MS_PER_HOUR + 15 * MS_PER_MIN, // 2h15m
6 * MS_PER_HOUR + 45 * MS_PER_MIN, // 6h45m
20 * MS_PER_HOUR + 15 * MS_PER_MIN, // 20h15m
1 * MS_PER_DAY, // 1d
2 * MS_PER_DAY, // 2d
3 * MS_PER_DAY, // 3d
1 * MS_PER_WEEK, // 1w
2 * MS_PER_WEEK, // 2w
30 * MS_PER_DAY, // 1m (approx)
];
const LADDER_LAST_INDEX = ZOOM_OUT_LADDER_MS.length - 1;
const MIN_DURATION = ZOOM_OUT_LADDER_MS[0];
const MAX_DURATION = ZOOM_OUT_LADDER_MS[LADDER_LAST_INDEX];
/** Preset labels for ladder steps supported by GetMinMax (shows "Last 15 minutes" etc. instead of "Custom") */
const PRESET_FOR_DURATION_MS: Record<number, Time> = {
[15 * MS_PER_MIN]: '15m',
[45 * MS_PER_MIN]: '45m',
[1 * MS_PER_DAY]: '1d',
[3 * MS_PER_DAY]: '3d',
[1 * MS_PER_WEEK]: '1w',
[2 * MS_PER_WEEK]: '2w',
[30 * MS_PER_DAY]: '1month',
};
/**
* Returns the next duration in the zoom-out ladder for the given current duration.
* If at or past 1 month, returns 15m (wrap).
*/
export function getNextDurationInLadder(durationMs: number): number {
if (durationMs >= MAX_DURATION) {
return MIN_DURATION; // Wrap: 1m → 15m
}
// Find the smallest ladder step that is strictly greater than current duration
for (let i = 0; i < ZOOM_OUT_LADDER_MS.length; i++) {
if (ZOOM_OUT_LADDER_MS[i] > durationMs) {
return ZOOM_OUT_LADDER_MS[i];
}
}
return MIN_DURATION;
}
export interface ZoomOutResult {
range: [number, number];
/** Preset key (e.g. '15m') when range matches a preset - use for display instead of "Custom Date Range" */
preset: Time | null;
}
/**
* Computes the next zoomed-out time range.
* Phase 1 (center-anchored): While new end <= now, expand from center.
* Phase 2 (end-anchored at now): When new end would exceed now, anchor end at now and move start backward.
*
* @returns ZoomOutResult with range and preset (or null if no change)
*/
export function getNextZoomOutRange(
startMs: number,
endMs: number,
): ZoomOutResult | null {
const nowMs = Date.now();
const durationMs = endMs - startMs;
if (durationMs <= 0) {
return null;
}
const newDurationMs = getNextDurationInLadder(durationMs);
const centerMs = startMs + durationMs / 2;
const computedEndMs = centerMs + newDurationMs / 2;
let newStartMs: number;
let newEndMs: number;
if (computedEndMs <= nowMs) {
// Phase 1: center-anchored
newStartMs = centerMs - newDurationMs / 2;
newEndMs = computedEndMs;
} else {
// Phase 2: end-anchored at now
newStartMs = nowMs - newDurationMs;
newEndMs = nowMs;
}
const preset = PRESET_FOR_DURATION_MS[newDurationMs] ?? null;
return {
range: [Math.round(newStartMs), Math.round(newEndMs)],
preset,
};
}

View File

@@ -1,7 +1,4 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import * as Sentry from '@sentry/react';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
@@ -12,7 +9,6 @@ import QuickFilters from 'components/QuickFilters/QuickFilters';
import { QuickFiltersSource, SignalType } from 'components/QuickFilters/types';
import WarningPopover from 'components/WarningPopover/WarningPopover';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import LogExplorerQuerySection from 'container/LogExplorerQuerySection';
import LogsExplorerViewsContainer from 'container/LogsExplorerViews';
@@ -31,19 +27,13 @@ import {
ICurrentQueryData,
useHandleExplorerTabChange,
} from 'hooks/useHandleExplorerTabChange';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { getNextZoomOutRange } from 'lib/logsZoomOutUtils';
import { defaultTo, isEmpty, isEqual, isNull } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { EventSourceProvider } from 'providers/EventSource';
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
import { UpdateTimeInterval } from 'store/actions';
import { AppState } from 'store/reducers';
import { Warning } from 'types/api';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime';
import {
explorerViewToPanelType,
panelTypeToExplorerView,
@@ -273,50 +263,6 @@ function LogsExplorer(): JSX.Element {
setShowLiveLogs(false);
}, []);
const dispatch = useDispatch();
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
(state) => state.globalTime,
);
const urlQuery = useUrlQuery();
const location = useLocation();
const { safeNavigate } = useSafeNavigate();
const handleZoomOut = useCallback((): void => {
if (showLiveLogs) {
return;
}
const minMs = Math.floor((minTime ?? 0) / 1e6);
const maxMs = Math.floor((maxTime ?? 0) / 1e6);
const result = getNextZoomOutRange(minMs, maxMs);
if (!result) {
return;
}
const [newStartMs, newEndMs] = result.range;
const { preset } = result;
if (preset) {
dispatch(UpdateTimeInterval(preset));
urlQuery.delete(QueryParams.startTime);
urlQuery.delete(QueryParams.endTime);
urlQuery.set(QueryParams.relativeTime, preset);
} else {
dispatch(UpdateTimeInterval('custom', [newStartMs, newEndMs]));
urlQuery.set(QueryParams.startTime, String(newStartMs));
urlQuery.set(QueryParams.endTime, String(newEndMs));
urlQuery.delete(QueryParams.relativeTime);
}
urlQuery.delete(QueryParams.activeLogId);
safeNavigate(`${location.pathname}?${urlQuery.toString()}`);
}, [
dispatch,
location.pathname,
maxTime,
minTime,
safeNavigate,
showLiveLogs,
urlQuery,
]);
return (
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
<EventSourceProvider>
@@ -355,7 +301,6 @@ function LogsExplorer(): JSX.Element {
chartQueryKeyRef={chartQueryKeyRef}
isLoadingQueries={isLoadingQueries}
showLiveLogs={showLiveLogs}
onZoomOut={handleZoomOut}
/>
}
showLiveLogs={showLiveLogs}

View File

@@ -242,6 +242,9 @@ func (q *promqlQuery) Execute(ctx context.Context) (*qbv5.Result, error) {
var s qbv5.TimeSeries
lbls := make([]*qbv5.Label, 0, len(v.Metric))
for name, value := range v.Metric.Copy().Map() {
if strings.HasPrefix(name, "__") || name == "fingerprint" {
continue
}
lbls = append(lbls, &qbv5.Label{
Key: telemetrytypes.TelemetryFieldKey{Name: name},
Value: value,