Fix the time range for queries created by the assistant

This commit is contained in:
Aleksandar Petrov
2025-12-03 12:13:20 -04:00
parent cd0d3a8d0a
commit 0b5a7b91fc
3 changed files with 42 additions and 26 deletions
@@ -4,6 +4,8 @@
* Conflict-Free Replicated Data Types for collaborative Explore Map editing
*/
/* eslint-disable no-barrel-files/no-barrel-files */
// Core CRDT types
export { HybridLogicalClock, compareHLC, happensBefore, happensAfter, timestampEquals, maxTimestamp } from './hlc';
export type { HLCTimestamp } from './hlc';
@@ -86,9 +86,12 @@ export function useExploreStateReceiver(options: UseExploreStateReceiverOptions)
// Apply time range if it's changed
if (exploreState.range && JSON.stringify(exploreState.range) !== JSON.stringify(explorePane.range)) {
console.log('[ExploreReceiver] Updating time range', exploreState.range);
// If range.raw exists, use it (for properly structured TimeRange objects)
// Otherwise, treat the range itself as a RawTimeRange (for backward compatibility)
const rawRange = (exploreState.range as any).raw || exploreState.range;
dispatch(updateTime({
exploreId,
rawRange: exploreState.range,
rawRange: rawRange,
}));
}
@@ -8,7 +8,8 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { v4 as uuidv4 } from 'uuid';
import { dateTime, DataQuery } from '@grafana/data';
import { TimeRange } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
import { generateExploreId } from 'app/core/utils/explore';
import { CRDTStateManager } from '../crdt/state';
@@ -230,7 +231,7 @@ const crdtSlice = createSlice({
const canvasCenterY = (-state.local.viewport.panY + viewportSize.height / 2) / state.local.viewport.zoom;
const mode = action.payload.kind || 'explore';
// Set default panel size based on panel type
// Drilldown panels are larger to accommodate the iframe content
const isDrilldownPanel =
@@ -240,7 +241,7 @@ const crdtSlice = createSlice({
mode === 'logs-drilldown';
const defaultWidth = isDrilldownPanel ? 1000 : 600;
const defaultHeight = isDrilldownPanel ? 550 : 400;
const panelWidth = action.payload.position?.width || defaultWidth;
const panelHeight = action.payload.position?.height || defaultHeight;
const panelCount = manager.getPanelIds().length;
@@ -257,28 +258,38 @@ const crdtSlice = createSlice({
const panelId = uuidv4();
const exploreId = generateExploreId();
// Build initial explore state if datasource/query provided
let initialExploreState: SerializedExploreState | undefined;
if (action.payload.datasourceUid || action.payload.query) {
initialExploreState = {
queries: action.payload.query
? [
{
refId: 'A',
datasource: { uid: action.payload.datasourceUid, type: 'prometheus' },
// Using index signature to add query-specific field
...{ expr: action.payload.query },
} as DataQuery,
]
: [],
datasourceUid: action.payload.datasourceUid,
range: {
from: dateTime('now-1h'),
to: dateTime('now'),
raw: { from: 'now-1h', to: 'now' },
},
};
}
// Build initial explore state with default time range
// Always set a default time range (last 1 hour) to ensure panels work correctly
// Note: We store strings instead of DateTime objects because they serialize properly through CRDT.
// The receiver (useExploreStateReceiver) will extract the raw values and pass them to updateTime.
// Type assertion needed because DataQuery doesn't include 'expr', but Prometheus queries use it
const queries: DataQuery[] = action.payload.query
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
([
{
refId: 'A',
datasource: { uid: action.payload.datasourceUid, type: 'prometheus' },
expr: action.payload.query,
},
] as unknown as DataQuery[])
: [];
// Create a time range that will serialize properly through CRDT.
// We use strings for from/to instead of DateTime objects, which the receiver handles correctly.
// Type assertion is necessary here because we're intentionally using strings for serialization.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const timeRange = {
from: 'now-1h',
to: 'now',
raw: { from: 'now-1h', to: 'now' },
} as unknown as TimeRange;
const initialExploreState: SerializedExploreState = {
queries,
datasourceUid: action.payload.datasourceUid,
range: timeRange,
};
const operation = manager.createAddPanelOperation(panelId, exploreId, position, mode, action.payload.createdBy, initialExploreState);