From b97bf4c632cfcd9a18e72fc1f186552cff346889 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:54:27 +0300 Subject: [PATCH] [v11.1.x] Scenes: Setting default_home_dashboard_path returns blank page and no controls (#89360) Scenes: Setting default_home_dashboard_path returns blank page and no controls (#89304) (cherry picked from commit 3fdc66d284ed4d6dbdbfca2a76d9b30abb27cd85) Co-authored-by: Ivan Ortega Alba --- .../pages/DashboardScenePage.test.tsx | 49 +++++++++++++++++-- .../pages/DashboardScenePage.tsx | 7 ++- .../scene/DashboardControls.test.tsx | 22 +++++++-- .../scene/DashboardControls.tsx | 11 +++-- .../scene/DashboardSceneRenderer.tsx | 2 +- .../MonacoFieldWrapper.test.tsx | 6 ++- 6 files changed, 80 insertions(+), 17 deletions(-) diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx index 3fe7ba89db6..51777c2fd7a 100644 --- a/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx +++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx @@ -11,9 +11,11 @@ import { config, getPluginLinkExtensions, locationService, setPluginImportUtils import { VizPanel } from '@grafana/scenes'; import { Dashboard } from '@grafana/schema'; import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps'; +import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; import store from 'app/core/store'; import { DashboardLoaderSrv, setDashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv'; import { DASHBOARD_FROM_LS_KEY } from 'app/features/dashboard/state/initDashboard'; +import { DashboardRoutes } from 'app/types'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; @@ -24,6 +26,11 @@ jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), setPluginExtensionGetter: jest.fn(), getPluginLinkExtensions: jest.fn(), + getBackendSrv: () => { + return { + get: jest.fn().mockResolvedValue({ dashboard: simpleDashboard, meta: { url: '' } }), + }; + }, getDataSourceSrv: () => { return { get: jest.fn().mockResolvedValue({}), @@ -37,12 +44,19 @@ jest.mock('@grafana/runtime', () => ({ const getPluginLinkExtensionsMock = jest.mocked(getPluginLinkExtensions); -function setup() { +function setup({ routeProps }: { routeProps?: Partial } = {}) { const context = getGrafanaContextMock(); + const defaultRouteProps = getRouteComponentProps(); const props: Props = { - ...getRouteComponentProps(), + ...defaultRouteProps, + match: { + ...defaultRouteProps.match, + params: { + uid: 'my-dash-uid', + }, + }, + ...routeProps, }; - props.match.params.uid = 'my-dash-uid'; const renderResult = render( @@ -258,14 +272,39 @@ describe('DashboardScenePage', () => { }); describe('home page', () => { - it('should not show controls', async () => { + it('should render the dashboard when the route is home', async () => { + setup({ + routeProps: { + route: { + ...getRouteComponentProps().route, + routeName: DashboardRoutes.Home, + }, + match: { + ...getRouteComponentProps().match, + path: '/', + params: {}, + }, + }, + }); + + await waitForDashbordToRender(); + + expect(await screen.findByTitle('Panel A')).toBeInTheDocument(); + expect(await screen.findByText('Content A')).toBeInTheDocument(); + + expect(await screen.findByTitle('Panel B')).toBeInTheDocument(); + expect(await screen.findByText('Content B')).toBeInTheDocument(); + }); + + it('should show controls', async () => { getDashboardScenePageStateManager().clearDashboardCache(); loadDashboardMock.mockClear(); loadDashboardMock.mockResolvedValue({ dashboard: { panels: [] }, meta: {} }); setup(); - await waitFor(() => expect(screen.queryByText('Refresh')).not.toBeInTheDocument()); + await waitFor(() => expect(screen.queryByText('Refresh')).toBeInTheDocument()); + await waitFor(() => expect(screen.queryByText('Last 6 hours')).toBeInTheDocument()); }); }); }); diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx index d4ba5135a91..c641cff3f11 100644 --- a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx +++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx @@ -75,7 +75,12 @@ export function DashboardScenePage({ match, route, queryParams, history }: Props } // Do not render anything when transitioning from one dashboard to another - if (match.params.type !== 'snapshot' && dashboard.state.uid && dashboard.state.uid !== match.params.uid) { + if ( + match.params.type !== 'snapshot' && + dashboard.state.uid && + dashboard.state.uid !== match.params.uid && + route.routeName !== DashboardRoutes.Home + ) { return null; } diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx index 52b46d49c99..30b391e0aba 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx @@ -104,17 +104,29 @@ describe('DashboardControls', () => { expect(scene.state.hideTimeControls).toBeTruthy(); expect(scene.state.hideVariableControls).toBeTruthy(); expect(scene.state.hideLinksControls).toBeTruthy(); + }); + + it('should not override state if no new state comes from url', () => { + const scene = buildTestScene({ hideTimeControls: true, hideVariableControls: true, hideLinksControls: true }); scene.updateFromUrl({}); - expect(scene.state.hideTimeControls).toBeFalsy(); - expect(scene.state.hideVariableControls).toBeFalsy(); - expect(scene.state.hideLinksControls).toBeFalsy(); + expect(scene.state.hideTimeControls).toBeTruthy(); + expect(scene.state.hideVariableControls).toBeTruthy(); + expect(scene.state.hideLinksControls).toBeTruthy(); }); it('should not call setState if no changes', () => { const scene = buildTestScene(); const setState = jest.spyOn(scene, 'setState'); - scene.updateFromUrl({}); - scene.updateFromUrl({}); + scene.updateFromUrl({ + '_dash.hideTimePicker': 'true', + '_dash.hideVariables': 'true', + '_dash.hideLinks': 'true', + }); + scene.updateFromUrl({ + '_dash.hideTimePicker': 'true', + '_dash.hideVariables': 'true', + '_dash.hideLinks': 'true', + }); expect(setState).toHaveBeenCalledTimes(1); }); }); diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx index 39db075bc44..5614c57bfd4 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx @@ -54,9 +54,14 @@ export class DashboardControls extends SceneObjectBase { updateFromUrl(values: SceneObjectUrlValues) { const update: Partial = {}; - update.hideTimeControls = values['_dash.hideTimePicker'] === 'true' || values['_dash.hideTimePicker'] === ''; - update.hideVariableControls = values['_dash.hideVariables'] === 'true' || values['_dash.hideVariables'] === ''; - update.hideLinksControls = values['_dash.hideLinks'] === 'true' || values['_dash.hideLinks'] === ''; + update.hideTimeControls = + values['_dash.hideTimePicker'] === 'true' || values['_dash.hideTimePicker'] === '' || this.state.hideTimeControls; + update.hideVariableControls = + values['_dash.hideVariables'] === 'true' || + values['_dash.hideVariables'] === '' || + this.state.hideVariableControls; + update.hideLinksControls = + values['_dash.hideLinks'] === 'true' || values['_dash.hideLinks'] === '' || this.state.hideLinksControls; if (Object.entries(update).some(([k, v]) => v !== this.state[k as keyof DashboardControlsState])) { this.setState(update); diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx index f8e77d21856..553710923cf 100644 --- a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx @@ -57,7 +57,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps {scopes && } - {!isHomePage && controls && hasControls && ( + {controls && hasControls && (
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx index e98e694f093..2276e1646ea 100644 --- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx +++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from '@testing-library/react'; +import { act, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; import { selectors } from '@grafana/e2e-selectors'; @@ -24,7 +24,9 @@ function renderComponent({ initialValue = '', onChange = jest.fn(), onRunQuery = describe('MonacoFieldWrapper', () => { test('Renders with no errors', async () => { - renderComponent(); + await act(() => { + renderComponent(); + }); await waitFor(async () => { const monacoEditor = await screen.findByTestId(selectors.components.ReactMonacoEditor.editorLazy);