mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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 <dominik.prokop@grafana.com> Co-authored-by: Darren Janeczek <darren.janeczek@grafana.com> Co-authored-by: oscarkilhed <oscar.kilhed@grafana.com>
This commit is contained in:
parent
c602d9d6ad
commit
23f1732855
@ -255,7 +255,7 @@
|
|||||||
"@grafana/prometheus": "workspace:*",
|
"@grafana/prometheus": "workspace:*",
|
||||||
"@grafana/runtime": "workspace:*",
|
"@grafana/runtime": "workspace:*",
|
||||||
"@grafana/saga-icons": "workspace:*",
|
"@grafana/saga-icons": "workspace:*",
|
||||||
"@grafana/scenes": "^4.5.4",
|
"@grafana/scenes": "^4.5.6",
|
||||||
"@grafana/schema": "workspace:*",
|
"@grafana/schema": "workspace:*",
|
||||||
"@grafana/sql": "workspace:*",
|
"@grafana/sql": "workspace:*",
|
||||||
"@grafana/ui": "workspace:*",
|
"@grafana/ui": "workspace:*",
|
||||||
|
@ -7,16 +7,18 @@ import {
|
|||||||
FieldType,
|
FieldType,
|
||||||
LoadingState,
|
LoadingState,
|
||||||
PanelData,
|
PanelData,
|
||||||
TimeRange,
|
getDefaultTimeRange,
|
||||||
standardTransformersRegistry,
|
standardTransformersRegistry,
|
||||||
toDataFrame,
|
toDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
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 { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
|
import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
|
||||||
import { DashboardDataDTO } from 'app/types';
|
import { DashboardDataDTO } from 'app/types';
|
||||||
|
|
||||||
|
import { DashboardGridItem } from '../../scene/DashboardGridItem';
|
||||||
|
import { DashboardScene } from '../../scene/DashboardScene';
|
||||||
import { transformSaveModelToScene } from '../../serialization/transformSaveModelToScene';
|
import { transformSaveModelToScene } from '../../serialization/transformSaveModelToScene';
|
||||||
import { DashboardModelCompatibilityWrapper } from '../../utils/DashboardModelCompatibilityWrapper';
|
import { DashboardModelCompatibilityWrapper } from '../../utils/DashboardModelCompatibilityWrapper';
|
||||||
import { findVizPanelByKey } from '../../utils/utils';
|
import { findVizPanelByKey } from '../../utils/utils';
|
||||||
@ -29,17 +31,29 @@ function createModelMock(
|
|||||||
panelData: PanelData,
|
panelData: PanelData,
|
||||||
transformations?: DataTransformerConfig[],
|
transformations?: DataTransformerConfig[],
|
||||||
onChangeTransformationsMock?: Function
|
onChangeTransformationsMock?: Function
|
||||||
) {
|
): PanelDataTransformationsTab {
|
||||||
return {
|
const panel = new VizPanel({
|
||||||
getDataTransformer: () => new SceneDataTransformer({ data: panelData, transformations: transformations || [] }),
|
$data: new SceneDataTransformer({
|
||||||
getQueryRunner: () => new SceneQueryRunner({ queries: [], data: panelData }),
|
$data: new SceneQueryRunner({ queries: [] }),
|
||||||
onChangeTransformations: onChangeTransformationsMock,
|
transformations: transformations || [],
|
||||||
} as unknown as PanelDataTransformationsTab;
|
}),
|
||||||
|
});
|
||||||
|
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 = {
|
const mockData = {
|
||||||
timeRange: {} as unknown as TimeRange,
|
timeRange: getDefaultTimeRange(),
|
||||||
state: {} as unknown as LoadingState,
|
state: LoadingState.Done,
|
||||||
series: [
|
series: [
|
||||||
toDataFrame({
|
toDataFrame({
|
||||||
name: 'A',
|
name: 'A',
|
||||||
|
@ -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
|
// Needed when the panel is not part of an DashboardScene
|
||||||
jest.spyOn(utils, 'getDashboardSceneFor').mockReturnValue(new DashboardScene({}));
|
jest.spyOn(utils, 'getDashboardSceneFor').mockReturnValue(new DashboardScene({}));
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
};
|
||||||
|
};
|
@ -47,6 +47,7 @@ import { panelLinksBehavior, panelMenuBehavior } from '../scene/PanelMenuBehavio
|
|||||||
import { PanelNotices } from '../scene/PanelNotices';
|
import { PanelNotices } from '../scene/PanelNotices';
|
||||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||||
|
import { hoverHeaderOffsetBehavior } from '../scene/hoverHeaderOffsetBehavior';
|
||||||
import { RowActions } from '../scene/row-actions/RowActions';
|
import { RowActions } from '../scene/row-actions/RowActions';
|
||||||
import { setDashboardPanelContext } from '../scene/setDashboardPanelContext';
|
import { setDashboardPanelContext } from '../scene/setDashboardPanelContext';
|
||||||
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||||
@ -506,6 +507,7 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem {
|
|||||||
displayMode: panel.transparent ? 'transparent' : undefined,
|
displayMode: panel.transparent ? 'transparent' : undefined,
|
||||||
// To be replaced with it's own option persited option instead derived
|
// To be replaced with it's own option persited option instead derived
|
||||||
hoverHeader: !panel.title && !panel.timeFrom && !panel.timeShift,
|
hoverHeader: !panel.title && !panel.timeFrom && !panel.timeShift,
|
||||||
|
hoverHeaderOffset: (panel.gridPos?.y ?? 0) === 0 ? 0 : undefined,
|
||||||
$data: createPanelDataProvider(panel),
|
$data: createPanelDataProvider(panel),
|
||||||
titleItems,
|
titleItems,
|
||||||
|
|
||||||
@ -539,6 +541,7 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem {
|
|||||||
body,
|
body,
|
||||||
maxPerRow: panel.maxPerRow,
|
maxPerRow: panel.maxPerRow,
|
||||||
...repeatOptions,
|
...repeatOptions,
|
||||||
|
$behaviors: [hoverHeaderOffsetBehavior],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ describe('TrailStore', () => {
|
|||||||
['to', 'now-30m'],
|
['to', 'now-30m'],
|
||||||
['var-ds', '1234'],
|
['var-ds', '1234'],
|
||||||
['var-groupby', 'job'],
|
['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) => {
|
])(`new recent trails with a different '%p' value should insert new entry`, (key, differentValue) => {
|
||||||
const store = getTrailStore();
|
const store = getTrailStore();
|
||||||
// We expect the initialized trail to be there
|
// We expect the initialized trail to be there
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -4183,9 +4183,9 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@grafana/scenes@npm:^4.5.4":
|
"@grafana/scenes@npm:^4.5.6":
|
||||||
version: 4.5.4
|
version: 4.5.6
|
||||||
resolution: "@grafana/scenes@npm:4.5.4"
|
resolution: "@grafana/scenes@npm:4.5.6"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@grafana/e2e-selectors": "npm:10.3.3"
|
"@grafana/e2e-selectors": "npm:10.3.3"
|
||||||
react-grid-layout: "npm:1.3.4"
|
react-grid-layout: "npm:1.3.4"
|
||||||
@ -4199,7 +4199,7 @@ __metadata:
|
|||||||
"@grafana/ui": ^10.0.3
|
"@grafana/ui": ^10.0.3
|
||||||
react: ^18.0.0
|
react: ^18.0.0
|
||||||
react-dom: ^18.0.0
|
react-dom: ^18.0.0
|
||||||
checksum: 10/db483dfd204b5b3f2d61b72e1a4209137734ed20d860f823e48a549fee2f2ef490ab26ed239a13aed095d74f929200cb18a666bb995aad6ef785fb806cac65ce
|
checksum: 10/eb576ee9097581f3a29722f09e2b3a763baeb425677c3ddec1ed7794dcda17ed6c3865dd79ea9fb8c6a25547678294e480fbfeca48983bb155f47373702f91d8
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -18671,7 +18671,7 @@ __metadata:
|
|||||||
"@grafana/prometheus": "workspace:*"
|
"@grafana/prometheus": "workspace:*"
|
||||||
"@grafana/runtime": "workspace:*"
|
"@grafana/runtime": "workspace:*"
|
||||||
"@grafana/saga-icons": "workspace:*"
|
"@grafana/saga-icons": "workspace:*"
|
||||||
"@grafana/scenes": "npm:^4.5.4"
|
"@grafana/scenes": "npm:^4.5.6"
|
||||||
"@grafana/schema": "workspace:*"
|
"@grafana/schema": "workspace:*"
|
||||||
"@grafana/sql": "workspace:*"
|
"@grafana/sql": "workspace:*"
|
||||||
"@grafana/tsconfig": "npm:^1.3.0-rc1"
|
"@grafana/tsconfig": "npm:^1.3.0-rc1"
|
||||||
|
Loading…
Reference in New Issue
Block a user