From 23f17328558dc1bef6d38a242361fc999e5ceac6 Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Wed, 10 Apr 2024 15:39:51 +0300 Subject: [PATCH] DashboardScene: prevent panel hovel header crop with scenes (#85780) * add behaviour that adjusts hoverHeaderOffset * clean up behaviour logic * optimise and extract behaviour to separate file * fix hoverHeaderOffsetBehavior unsubscribe * update to latest scenes version * Fix PanelOptionsTest * fix: test value for adhoc filter url param * Fix transformation tab tests --------- Co-authored-by: Dominik Prokop Co-authored-by: Darren Janeczek Co-authored-by: oscarkilhed --- package.json | 2 +- .../PanelDataTransformationsTab.test.tsx | 34 +++++++++++++------ .../panel-edit/PanelOptions.test.tsx | 7 ++++ .../scene/hoverHeaderOffsetBehavior.ts | 18 ++++++++++ .../transformSaveModelToScene.ts | 3 ++ .../trails/TrailStore/TrailStore.test.ts | 2 +- yarn.lock | 10 +++--- 7 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 public/app/features/dashboard-scene/scene/hoverHeaderOffsetBehavior.ts diff --git a/package.json b/package.json index ed91c11fad3..2bc952ff84c 100644 --- a/package.json +++ b/package.json @@ -255,7 +255,7 @@ "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", "@grafana/saga-icons": "workspace:*", - "@grafana/scenes": "^4.5.4", + "@grafana/scenes": "^4.5.6", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx index 2b9766c54d1..d122180550e 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx @@ -7,16 +7,18 @@ import { FieldType, LoadingState, PanelData, - TimeRange, + getDefaultTimeRange, standardTransformersRegistry, toDataFrame, } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { SceneDataTransformer, SceneQueryRunner } from '@grafana/scenes'; +import { SceneDataTransformer, SceneQueryRunner, VizPanel } from '@grafana/scenes'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { getStandardTransformers } from 'app/features/transformers/standardTransformers'; import { DashboardDataDTO } from 'app/types'; +import { DashboardGridItem } from '../../scene/DashboardGridItem'; +import { DashboardScene } from '../../scene/DashboardScene'; import { transformSaveModelToScene } from '../../serialization/transformSaveModelToScene'; import { DashboardModelCompatibilityWrapper } from '../../utils/DashboardModelCompatibilityWrapper'; import { findVizPanelByKey } from '../../utils/utils'; @@ -29,17 +31,29 @@ function createModelMock( panelData: PanelData, transformations?: DataTransformerConfig[], onChangeTransformationsMock?: Function -) { - return { - getDataTransformer: () => new SceneDataTransformer({ data: panelData, transformations: transformations || [] }), - getQueryRunner: () => new SceneQueryRunner({ queries: [], data: panelData }), - onChangeTransformations: onChangeTransformationsMock, - } as unknown as PanelDataTransformationsTab; +): PanelDataTransformationsTab { + const panel = new VizPanel({ + $data: new SceneDataTransformer({ + $data: new SceneQueryRunner({ queries: [] }), + transformations: transformations || [], + }), + }); + const gridItem = new DashboardGridItem({ body: panel }); + const vizPanelManager = VizPanelManager.createFor(panel); + const scene = new DashboardScene({ body: gridItem }); + + // @ts-expect-error + getDashboardSrv().setCurrent(new DashboardModelCompatibilityWrapper(scene)); + + const transformationTab = new PanelDataTransformationsTab(vizPanelManager); + // @ts-expect-error + transformationTab.onChangeTransformations = onChangeTransformationsMock || transformationTab.onChangeTransformations; + return transformationTab; } const mockData = { - timeRange: {} as unknown as TimeRange, - state: {} as unknown as LoadingState, + timeRange: getDefaultTimeRange(), + state: LoadingState.Done, series: [ toDataFrame({ name: 'A', diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx index 973d6a433fb..e8d70ee76d7 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx @@ -22,6 +22,13 @@ jest.mock('react-router-dom', () => ({ }), })); +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getPluginImportUtils: () => ({ + getPanelPluginFromCache: jest.fn(), + }), +})); + // Needed when the panel is not part of an DashboardScene jest.spyOn(utils, 'getDashboardSceneFor').mockReturnValue(new DashboardScene({})); diff --git a/public/app/features/dashboard-scene/scene/hoverHeaderOffsetBehavior.ts b/public/app/features/dashboard-scene/scene/hoverHeaderOffsetBehavior.ts new file mode 100644 index 00000000000..9a8df0480ea --- /dev/null +++ b/public/app/features/dashboard-scene/scene/hoverHeaderOffsetBehavior.ts @@ -0,0 +1,18 @@ +import { VizPanel } from '@grafana/scenes'; + +import { DashboardGridItem } from './DashboardGridItem'; + +export const hoverHeaderOffsetBehavior = (grid: DashboardGridItem) => { + const sub = grid.subscribeToState((newState, prevState) => { + if ([newState.y, prevState.y].includes(0) && newState.y !== prevState.y) { + grid.forEachChild((child) => { + if (child instanceof VizPanel && child.state.hoverHeader) { + child.setState({ hoverHeaderOffset: grid.state.y === 0 ? 0 : undefined }); + } + }); + } + }); + return () => { + sub.unsubscribe(); + }; +}; diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index bbbae286968..68286638784 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -47,6 +47,7 @@ import { panelLinksBehavior, panelMenuBehavior } from '../scene/PanelMenuBehavio import { PanelNotices } from '../scene/PanelNotices'; import { PanelTimeRange } from '../scene/PanelTimeRange'; import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior'; +import { hoverHeaderOffsetBehavior } from '../scene/hoverHeaderOffsetBehavior'; import { RowActions } from '../scene/row-actions/RowActions'; import { setDashboardPanelContext } from '../scene/setDashboardPanelContext'; import { createPanelDataProvider } from '../utils/createPanelDataProvider'; @@ -506,6 +507,7 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem { displayMode: panel.transparent ? 'transparent' : undefined, // To be replaced with it's own option persited option instead derived hoverHeader: !panel.title && !panel.timeFrom && !panel.timeShift, + hoverHeaderOffset: (panel.gridPos?.y ?? 0) === 0 ? 0 : undefined, $data: createPanelDataProvider(panel), titleItems, @@ -539,6 +541,7 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem { body, maxPerRow: panel.maxPerRow, ...repeatOptions, + $behaviors: [hoverHeaderOffsetBehavior], }); } diff --git a/public/app/features/trails/TrailStore/TrailStore.test.ts b/public/app/features/trails/TrailStore/TrailStore.test.ts index 2aa5d1671e6..1b6c1447fa6 100644 --- a/public/app/features/trails/TrailStore/TrailStore.test.ts +++ b/public/app/features/trails/TrailStore/TrailStore.test.ts @@ -136,7 +136,7 @@ describe('TrailStore', () => { ['to', 'now-30m'], ['var-ds', '1234'], ['var-groupby', 'job'], - ['var-filters', 'test'], + ['var-filters', 'cluster|=|dev-eu-west-2'], ])(`new recent trails with a different '%p' value should insert new entry`, (key, differentValue) => { const store = getTrailStore(); // We expect the initialized trail to be there diff --git a/yarn.lock b/yarn.lock index 66aec6eea77..713b74235f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4183,9 +4183,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes@npm:^4.5.4": - version: 4.5.4 - resolution: "@grafana/scenes@npm:4.5.4" +"@grafana/scenes@npm:^4.5.6": + version: 4.5.6 + resolution: "@grafana/scenes@npm:4.5.6" dependencies: "@grafana/e2e-selectors": "npm:10.3.3" react-grid-layout: "npm:1.3.4" @@ -4199,7 +4199,7 @@ __metadata: "@grafana/ui": ^10.0.3 react: ^18.0.0 react-dom: ^18.0.0 - checksum: 10/db483dfd204b5b3f2d61b72e1a4209137734ed20d860f823e48a549fee2f2ef490ab26ed239a13aed095d74f929200cb18a666bb995aad6ef785fb806cac65ce + checksum: 10/eb576ee9097581f3a29722f09e2b3a763baeb425677c3ddec1ed7794dcda17ed6c3865dd79ea9fb8c6a25547678294e480fbfeca48983bb155f47373702f91d8 languageName: node linkType: hard @@ -18671,7 +18671,7 @@ __metadata: "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" "@grafana/saga-icons": "workspace:*" - "@grafana/scenes": "npm:^4.5.4" + "@grafana/scenes": "npm:^4.5.6" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/tsconfig": "npm:^1.3.0-rc1"