From f4fa3e4ff45ab2c0381f65c93f293534fc27d033 Mon Sep 17 00:00:00 2001
From: Maria Alexandra <239999+axelavargas@users.noreply.github.com>
Date: Fri, 26 Aug 2022 15:36:42 +0200
Subject: [PATCH] Panel edit: Run queries when time range changes in table view
(#53111)
---
.../PanelEditor/PanelEditorTableView.test.tsx | 181 ++++++++++++++++++
.../PanelEditor/PanelEditorTableView.tsx | 5 +-
2 files changed, 183 insertions(+), 3 deletions(-)
create mode 100644 public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
new file mode 100644
index 00000000000..30b3f0ca4de
--- /dev/null
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
@@ -0,0 +1,181 @@
+import { act, render, screen } from '@testing-library/react';
+import React, { FC } from 'react';
+import { Provider } from 'react-redux';
+import configureMockStore from 'redux-mock-store';
+import { ReplaySubject } from 'rxjs';
+import { TimeSrvStub } from 'test/specs/helpers';
+
+import {
+ dateTime,
+ EventBusSrv,
+ getDefaultTimeRange,
+ LoadingState,
+ PanelData,
+ PanelPlugin,
+ PanelProps,
+ TimeRange,
+} from '@grafana/data';
+import { getTimeSrv, TimeSrv, setTimeSrv } from 'app/features/dashboard/services/TimeSrv';
+
+import { PanelQueryRunner } from '../../../query/state/PanelQueryRunner';
+import { DashboardModel, PanelModel } from '../../state';
+
+import { PanelEditorTableView, Props } from './PanelEditorTableView';
+
+jest.mock('../../utils/panel', () => ({
+ applyPanelTimeOverrides: jest.fn((panel, timeRange) => ({
+ ...timeRange,
+ })),
+}));
+
+jest.mock('app/features/panel/components/PanelRenderer', () => ({
+ PanelRenderer: jest.fn(() =>
PanelRenderer Mock
),
+}));
+
+function setupTestContext(options: Partial = {}) {
+ const mockStore = configureMockStore();
+ const subject: ReplaySubject = new ReplaySubject();
+ const panelQueryRunner = {
+ getData: () => subject,
+ run: () => {
+ subject.next({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
+ },
+ } as unknown as PanelQueryRunner;
+
+ const defaults = {
+ panel: new PanelModel({
+ id: 123,
+ hasTitle: jest.fn(),
+ replaceVariables: jest.fn(),
+ events: new EventBusSrv(),
+ getQueryRunner: () => panelQueryRunner,
+ getOptions: jest.fn(),
+ getDisplayTitle: jest.fn(),
+ runAllPanelQueries: jest.fn(),
+ }),
+ dashboard: new DashboardModel({
+ id: 1,
+ uid: 'super-unique-id',
+ panelInitialized: jest.fn(),
+ events: new EventBusSrv(),
+ meta: {
+ isPublic: false,
+ },
+ panels: [],
+ }),
+ plugin: {
+ meta: { skipDataQuery: false },
+ panel: TestPanelComponent,
+ } as unknown as PanelPlugin,
+ isViewing: false,
+ isEditing: true,
+ isInView: false,
+ width: 100,
+ height: 100,
+ onInstanceStateChange: () => {},
+ };
+
+ // Set up the mock store with the defaults
+ const store = mockStore({ dashboard: defaults.dashboard });
+ const timeSrv = getTimeSrv();
+
+ const props = { ...defaults, ...options };
+ const { rerender } = render(
+
+
+
+ );
+
+ return { rerender, props, subject, store, timeSrv };
+}
+
+describe('PanelEditorTableView', () => {
+ beforeAll(() => {
+ // Mock the timeSrv singleton
+ const timeSrvMock2 = new TimeSrvStub() as unknown as TimeSrv;
+ setTimeSrv(timeSrvMock2);
+ });
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should render', async () => {
+ const { rerender, props, subject, store } = setupTestContext({});
+
+ // only render the panel when loading is done
+ act(() => {
+ subject.next({ state: LoadingState.Loading, series: [], timeRange: getDefaultTimeRange() });
+ subject.next({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
+ });
+
+ const newProps = { ...props, isInView: true };
+ rerender(
+
+
+
+ );
+ expect(screen.getByText(/PanelRenderer Mock/i)).toBeInTheDocument();
+ });
+
+ it('should run all panel queries if time changes', async () => {
+ const { rerender, props, subject, store, timeSrv } = setupTestContext({});
+
+ const timeRangeUpdated = {
+ from: dateTime([2019, 1, 11, 12, 0]),
+ to: dateTime([2019, 1, 11, 18, 0]),
+ } as unknown as TimeRange;
+
+ // only render the panel when loading is done
+ act(() => {
+ subject.next({ state: LoadingState.Loading, series: [], timeRange: getDefaultTimeRange() });
+ subject.next({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
+ });
+
+ const newProps = { ...props, isInView: true };
+ rerender(
+
+
+
+ );
+
+ expect(screen.getByText(/PanelRenderer Mock/i)).toBeInTheDocument();
+
+ // updating the global time range
+ act(() => {
+ timeSrv.setTime(timeRangeUpdated);
+ props.panel.refresh();
+ });
+
+ // panel queries should have the updated time range
+ expect(props.panel.runAllPanelQueries).toHaveBeenNthCalledWith(1, {
+ dashboardId: props.dashboard.id,
+ dashboardTimezone: '',
+ dashboardUID: props.dashboard.uid,
+ timeData: timeRangeUpdated,
+ width: 100,
+ });
+
+ // update global time second time
+
+ const timeRangeUpdated2 = {
+ from: dateTime([2018, 1, 11, 12, 0]),
+ to: dateTime([2018, 1, 11, 18, 0]),
+ } as unknown as TimeRange;
+
+ act(() => {
+ timeSrv.setTime(timeRangeUpdated2);
+ props.panel.refresh();
+ });
+
+ // panel queries should have the updated time range
+ expect(props.panel.runAllPanelQueries).toHaveBeenLastCalledWith({
+ dashboardId: props.dashboard.id,
+ dashboardTimezone: '',
+ dashboardUID: props.dashboard.uid,
+ timeData: timeRangeUpdated2,
+ width: 100,
+ });
+ });
+});
+
+const TestPanelComponent: FC = () => Plugin Panel to Render
;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
index 633d75ceef7..501e6e9703a 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
@@ -12,7 +12,7 @@ import { DashboardModel, PanelModel } from '../../state';
import { usePanelLatestData } from './usePanelLatestData';
-interface Props {
+export interface Props {
width: number;
height: number;
panel: PanelModel;
@@ -30,9 +30,9 @@ export function PanelEditorTableView({ width, height, panel, dashboard }: Props)
// Subscribe to panel event
useEffect(() => {
const timeSrv = getTimeSrv();
- const timeData = applyPanelTimeOverrides(panel, timeSrv.timeRange());
const sub = panel.events.subscribe(RefreshEvent, () => {
+ const timeData = applyPanelTimeOverrides(panel, timeSrv.timeRange());
panel.runAllPanelQueries({
dashboardId: dashboard.id,
dashboardUID: dashboard.uid,
@@ -49,7 +49,6 @@ export function PanelEditorTableView({ width, height, panel, dashboard }: Props)
if (!data) {
return null;
}
-
return (
{(innerWidth, innerHeight) => (