From d18766e88bb5c475b45feed844edaa97bd81fc5b Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Fri, 13 Oct 2023 14:43:45 +0200 Subject: [PATCH] PluginExtensions: Make sure to pass default timeZone in context (#76513) * Fixed so we will return default timeZone to extensions if empty is provided. * Update public/app/features/dashboard/utils/getPanelMenu.test.ts Co-authored-by: Dominik Prokop --------- Co-authored-by: Dominik Prokop --- packages/grafana-data/src/datetime/common.ts | 7 +- .../dashboard/utils/getPanelMenu.test.ts | 91 +++++++++++++++++++ .../features/dashboard/utils/getPanelMenu.ts | 5 +- .../extensions/ToolbarExtensionPoint.test.tsx | 15 +++ .../extensions/ToolbarExtensionPoint.tsx | 4 +- 5 files changed, 118 insertions(+), 4 deletions(-) diff --git a/packages/grafana-data/src/datetime/common.ts b/packages/grafana-data/src/datetime/common.ts index fa7fb9454ec..9f9b3722f3e 100644 --- a/packages/grafana-data/src/datetime/common.ts +++ b/packages/grafana-data/src/datetime/common.ts @@ -1,3 +1,5 @@ +import { isEmpty } from 'lodash'; + import { TimeZone, DefaultTimeZone } from '../types/time'; /** @@ -57,5 +59,8 @@ export const setTimeZoneResolver = (resolver: TimeZoneResolver) => { * @public */ export const getTimeZone = (options?: T): TimeZone => { - return options?.timeZone ?? defaultTimeZoneResolver() ?? DefaultTimeZone; + if (options?.timeZone && !isEmpty(options.timeZone)) { + return options.timeZone; + } + return defaultTimeZoneResolver() ?? DefaultTimeZone; }; diff --git a/public/app/features/dashboard/utils/getPanelMenu.test.ts b/public/app/features/dashboard/utils/getPanelMenu.test.ts index afffadcd47f..2afb76ce4d4 100644 --- a/public/app/features/dashboard/utils/getPanelMenu.test.ts +++ b/public/app/features/dashboard/utils/getPanelMenu.test.ts @@ -295,6 +295,97 @@ describe('getPanelMenu()', () => { expect(getPluginLinkExtensionsMock).toBeCalledWith(expect.objectContaining({ context })); }); + it('should pass context with default time zone values when configuring extension', () => { + const data: PanelData = { + series: [ + toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time }, + { name: 'score', type: FieldType.number }, + ], + }), + ], + timeRange: { + from: dateTime(), + to: dateTime(), + raw: { + from: 'now', + to: 'now-1h', + }, + }, + state: LoadingState.Done, + }; + + const panel = new PanelModel({ + type: 'timeseries', + id: 1, + title: 'My panel', + targets: [ + { + refId: 'A', + datasource: { + type: 'testdata', + }, + }, + ], + scopedVars: { + a: { + text: 'a', + value: 'a', + }, + }, + queryRunner: { + getLastResult: jest.fn(() => data), + }, + }); + + const dashboard = createDashboardModelFixture({ + timezone: '', + time: { + from: 'now-5m', + to: 'now', + }, + tags: ['database', 'panel'], + uid: '123', + title: 'My dashboard', + }); + + getPanelMenu(dashboard, panel); + + const context: PluginExtensionPanelContext = { + pluginId: 'timeseries', + id: 1, + title: 'My panel', + timeZone: 'browser', + timeRange: { + from: 'now-5m', + to: 'now', + }, + targets: [ + { + refId: 'A', + datasource: { + type: 'testdata', + }, + }, + ], + dashboard: { + tags: ['database', 'panel'], + uid: '123', + title: 'My dashboard', + }, + scopedVars: { + a: { + text: 'a', + value: 'a', + }, + }, + data, + }; + + expect(getPluginLinkExtensionsMock).toBeCalledWith(expect.objectContaining({ context })); + }); + it('should contain menu item with category', () => { getPluginLinkExtensionsMock.mockReturnValue({ extensions: [ diff --git a/public/app/features/dashboard/utils/getPanelMenu.ts b/public/app/features/dashboard/utils/getPanelMenu.ts index 64e5d2eeff2..f5725cc1f36 100644 --- a/public/app/features/dashboard/utils/getPanelMenu.ts +++ b/public/app/features/dashboard/utils/getPanelMenu.ts @@ -1,4 +1,5 @@ import { + getTimeZone, PanelMenuItem, PluginExtensionLink, PluginExtensionPoints, @@ -326,7 +327,9 @@ function createExtensionContext(panel: PanelModel, dashboard: DashboardModel): P pluginId: panel.type, title: panel.title, timeRange: dashboard.time, - timeZone: dashboard.timezone, + timeZone: getTimeZone({ + timeZone: dashboard.timezone, + }), dashboard: { uid: dashboard.uid, title: dashboard.title, diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx index 6b0de23b4af..4d410612675 100644 --- a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx +++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx @@ -151,6 +151,21 @@ describe('ToolbarExtensionPoint', () => { }); }); + it('should pass a context with correct timeZone when fetching extensions', async () => { + const targets = [{ refId: 'A' }]; + const data = createEmptyQueryResponse(); + + renderWithExploreStore(, { + targets, + data, + }); + + const [options] = getPluginLinkExtensionsMock.mock.calls[0]; + const { context } = options; + + expect(context).toHaveProperty('timeZone', 'browser'); + }); + it('should correct extension point id when fetching extensions', async () => { renderWithExploreStore(); diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx index 59a713c7ac3..5e45b4977b5 100644 --- a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx +++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx @@ -1,6 +1,6 @@ import React, { lazy, ReactElement, Suspense, useMemo, useState } from 'react'; -import { type PluginExtensionLink, PluginExtensionPoints, RawTimeRange } from '@grafana/data'; +import { type PluginExtensionLink, PluginExtensionPoints, RawTimeRange, getTimeZone } from '@grafana/data'; import { getPluginLinkExtensions, config } from '@grafana/runtime'; import { DataQuery, TimeZone } from '@grafana/schema'; import { Dropdown, ToolbarButton } from '@grafana/ui'; @@ -101,7 +101,7 @@ function useExtensionPointContext(props: Props): PluginExtensionExploreContext { targets: queries, data: queryResponse, timeRange: range.raw, - timeZone: timeZone, + timeZone: getTimeZone({ timeZone }), shouldShowAddCorrelation: config.featureToggles.correlations === true && canWriteCorrelations &&