Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: (scenes-react) - VizPanel add missing props and tests #998

Merged
merged 7 commits into from
Dec 12, 2024
Merged
113 changes: 111 additions & 2 deletions packages/scenes-react/src/components/VizPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { render } from '@testing-library/react';
import { SceneContextObject } from '../contexts/SceneContextObject';
import { VizConfigBuilders, VizPanel as VizPanelObject } from '@grafana/scenes';
import { VizPanel } from './VizPanel';
import { VizConfigBuilders, VizPanel as VizPanelObject, VizPanelMenu } from '@grafana/scenes';
import { VizPanel, VizPanelProps } from './VizPanel';
import { PanelPlugin } from '@grafana/data';
import { TestContextProvider } from '../utils/testUtils';

Expand Down Expand Up @@ -55,4 +55,113 @@ describe('VizPanel', () => {

expect(scene.state.children.length).toBe(0);
});

it('Should render with titleItems', () => {
const scene = new SceneContextObject();
const viz = VizConfigBuilders.timeseries().build();
const titleItems = <div>Title Item</div>;

const { rerender, unmount } = render(
<TestContextProvider value={scene}>
<VizPanel titleItems={titleItems} title="Test" viz={viz} />
</TestContextProvider>
);

const panel = scene.state.children[0] as VizPanelObject;
expect(panel.state.titleItems).toEqual(titleItems);

rerender(
<TestContextProvider value={scene}>
<VizPanel titleItems={undefined} title="Test" viz={viz} />
</TestContextProvider>
);

expect(panel.state.titleItems).toEqual(undefined);

unmount();

expect(scene.state.children.length).toBe(0);
});

it('Should render with headerActions', () => {
const scene = new SceneContextObject();
const viz = VizConfigBuilders.timeseries().build();
const headerActions = <button>Action</button>;

const { rerender, unmount } = render(
<TestContextProvider value={scene}>
<VizPanel title="Test" viz={viz} headerActions={headerActions} />
</TestContextProvider>
);

const panel = scene.state.children[0] as VizPanelObject;
expect(panel.state.headerActions).toEqual(headerActions);

rerender(
<TestContextProvider value={scene}>
<VizPanel title="Test" viz={viz} />
</TestContextProvider>
);

unmount();

expect(scene.state.children.length).toBe(0);
});

it('Should render VizPanelProps', () => {
const scene = new SceneContextObject();
const viz = VizConfigBuilders.timeseries().build();
const headerActions = <button>Action</button>;
const seriesLimit = 1;
const collapsed = true;
const collapsible = true;
const hoverHeader = true;
const description = 'description';
const menu = new VizPanelMenu({});
const title = 'title';
const props: VizPanelProps = {
title,
viz,
headerActions,
seriesLimit,
collapsed,
collapsible,
hoverHeader,
description,
menu,
};

const { rerender, unmount } = render(
<TestContextProvider value={scene}>
<VizPanel {...props} headerActions={headerActions} />
</TestContextProvider>
);

const panel = scene.state.children[0] as VizPanelObject;
expect(panel.state.headerActions).toEqual(headerActions);
expect(panel.state.collapsed).toEqual(collapsed);
expect(panel.state.seriesLimit).toEqual(seriesLimit);
expect(panel.state.collapsible).toEqual(collapsible);
expect(panel.state.hoverHeader).toEqual(hoverHeader);
expect(panel.state.description).toEqual(description);
expect(panel.state.menu).toEqual(menu);

rerender(
<TestContextProvider value={scene}>
<VizPanel title="Test" viz={viz} />
</TestContextProvider>
);

expect(panel.state.headerActions).toEqual(undefined);
expect(panel.state.collapsed).toEqual(undefined);
expect(panel.state.seriesLimit).toEqual(undefined);
expect(panel.state.collapsible).toEqual(undefined);
expect(panel.state.hoverHeader).toEqual(undefined);
expect(panel.state.description).toEqual(undefined);
expect(panel.state.menu).toEqual(undefined);

unmount();

expect(scene.state.children.length).toBe(0);
});
});
106 changes: 102 additions & 4 deletions packages/scenes-react/src/components/VizPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useId } from 'react';
import {
VizPanelMenu,
SceneDataProvider,
VizPanel as VizPanelObject,
VizPanelState,
Expand All @@ -9,18 +10,47 @@ import {
} from '@grafana/scenes';
import { usePrevious } from 'react-use';
import { getPanelOptionsWithDefaults } from '@grafana/data';
import { PanelContext } from '@grafana/ui';
import { writeSceneLog } from '../utils';
import { useSceneContext } from '../hooks/hooks';

export interface VizPanelProps {
title: string;
description?: string;
dataProvider?: SceneDataProvider;
viz: VizConfig;
displayMode?: 'default' | 'transparent';
hoverHeader?: boolean;
hoverHeaderOffset?: number;
menu?: VizPanelMenu;
titleItems?: React.ReactNode;
seriesLimit?: number;
seriesLimitShowAll?: boolean;
headerActions?: React.ReactNode;
extendPanelContext?: (vizPanel: VizPanelObject, context: PanelContext) => void;
collapsible?: boolean;
collapsed?: boolean;
}

export function VizPanel(props: VizPanelProps) {
const { title, viz, dataProvider, headerActions } = props;
const {
title,
description,
viz,
dataProvider,
displayMode,
hoverHeader,
hoverHeaderOffset,
headerActions,
menu,
titleItems,
extendPanelContext,
seriesLimit,
seriesLimitShowAll,
collapsible,
collapsed,
} = props;

const scene = useSceneContext();
const key = useId();
const prevProps = usePrevious(props);
Expand All @@ -30,13 +60,24 @@ export function VizPanel(props: VizPanelProps) {
if (!panel) {
panel = new VizPanelObject({
key: key,
title: title,
pluginId: viz.pluginId,
pluginVersion: viz.pluginVersion,
title: title,
titleItems: titleItems,
description: description,
options: viz.options,
fieldConfig: viz.fieldConfig,
pluginVersion: viz.pluginVersion,
$data: getDataProviderForVizPanel(dataProvider),
displayMode: displayMode,
hoverHeader: hoverHeader,
hoverHeaderOffset: hoverHeaderOffset,
headerActions: headerActions,
menu: menu,
extendPanelContext: extendPanelContext,
collapsible: collapsible,
collapsed: collapsed,
seriesLimit: seriesLimit,
seriesLimitShowAll: seriesLimitShowAll,
});
}

Expand All @@ -54,6 +95,30 @@ export function VizPanel(props: VizPanelProps) {
stateUpdate.title = title;
}

if (description !== prevProps.description) {
stateUpdate.description = description;
}

if (displayMode !== prevProps.displayMode) {
stateUpdate.displayMode = displayMode;
}

if (hoverHeader !== prevProps.hoverHeader) {
stateUpdate.hoverHeader = hoverHeader;
}

if (hoverHeaderOffset !== prevProps.hoverHeaderOffset) {
stateUpdate.hoverHeaderOffset = hoverHeaderOffset;
}

if (menu !== prevProps.menu) {
stateUpdate.menu = menu;
}

if (titleItems !== prevProps.titleItems) {
stateUpdate.titleItems = titleItems;
}

if (headerActions !== prevProps.headerActions) {
stateUpdate.headerActions = headerActions;
}
Expand All @@ -62,6 +127,22 @@ export function VizPanel(props: VizPanelProps) {
stateUpdate.$data = getDataProviderForVizPanel(dataProvider);
}

if (seriesLimit !== prevProps.seriesLimit) {
stateUpdate.seriesLimit = seriesLimit;
}

if (seriesLimitShowAll !== prevProps.seriesLimitShowAll) {
stateUpdate.seriesLimitShowAll = seriesLimitShowAll;
}

if (collapsible !== prevProps.collapsible) {
stateUpdate.collapsible = collapsible;
}

if (collapsed !== prevProps.collapsed) {
stateUpdate.collapsed = collapsed;
}

if (viz !== prevProps.viz) {
if (viz.pluginId === prevProps.viz.pluginId) {
const plugin = panel.getPlugin();
Expand All @@ -84,7 +165,24 @@ export function VizPanel(props: VizPanelProps) {
panel.setState(stateUpdate);
writeSceneLog('VizPanel', 'Updating VizPanel state', stateUpdate);
}
}, [panel, title, headerActions, viz, dataProvider, prevProps]);
}, [
panel,
title,
description,
displayMode,
hoverHeader,
hoverHeaderOffset,
headerActions,
menu,
titleItems,
viz,
dataProvider,
seriesLimit,
seriesLimitShowAll,
collapsible,
collapsed,
prevProps,
]);

return <panel.Component model={panel} />;
}
Expand Down
Loading