mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Add inspect submenu to panel menu (#78679)
* DashboardScene: Add inspect submenu to panel menu * Test fix
This commit is contained in:
parent
7a5f76d547
commit
5015b5b2b0
@ -1,4 +1,4 @@
|
|||||||
import { act, render, screen } from '@testing-library/react';
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TestProvider } from 'test/helpers/TestProvider';
|
import { TestProvider } from 'test/helpers/TestProvider';
|
||||||
@ -122,12 +122,8 @@ describe('DashboardScenePage', () => {
|
|||||||
// Somethig with Dropdown that is not working inside react-testing
|
// Somethig with Dropdown that is not working inside react-testing
|
||||||
await userEvent.click(screen.getByLabelText('Menu for panel with title Panel B'));
|
await userEvent.click(screen.getByLabelText('Menu for panel with title Panel B'));
|
||||||
|
|
||||||
const inspectLink = (await screen.findByRole('link', { name: /Inspect/ })).getAttribute('href')!;
|
const inspectMenuItem = await screen.findAllByText('Inspect');
|
||||||
act(() => locationService.push(inspectLink));
|
act(() => fireEvent.click(inspectMenuItem[0]));
|
||||||
|
|
||||||
// I get not implemented exception here (from navigation / js-dom).
|
|
||||||
// Mocking window.location.assign did not help
|
|
||||||
//await userEvent.click(await screen.findByRole('link', { name: /Inspect/ }));
|
|
||||||
|
|
||||||
expect(await screen.findByText('Inspect: Panel B')).toBeInTheDocument();
|
expect(await screen.findByText('Inspect: Panel B')).toBeInTheDocument();
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
|
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel, VizPanelMenu } from '@grafana/scenes';
|
||||||
import { PanelModel } from 'app/features/dashboard/state';
|
import { PanelModel } from 'app/features/dashboard/state';
|
||||||
import { getLibraryPanel } from 'app/features/library-panels/state/api';
|
import { getLibraryPanel } from 'app/features/library-panels/state/api';
|
||||||
|
|
||||||
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||||
|
|
||||||
|
import { panelMenuBehavior } from './PanelMenuBehavior';
|
||||||
|
|
||||||
interface LibraryVizPanelState extends SceneObjectState {
|
interface LibraryVizPanelState extends SceneObjectState {
|
||||||
// Library panels use title from dashboard JSON's panel model, not from library panel definition, hence we pass it.
|
// Library panels use title from dashboard JSON's panel model, not from library panel definition, hence we pass it.
|
||||||
title: string;
|
title: string;
|
||||||
@ -39,6 +41,9 @@ export class LibraryVizPanel extends SceneObjectBase<LibraryVizPanelState> {
|
|||||||
pluginVersion: libPanelModel.pluginVersion,
|
pluginVersion: libPanelModel.pluginVersion,
|
||||||
displayMode: libPanelModel.transparent ? 'transparent' : undefined,
|
displayMode: libPanelModel.transparent ? 'transparent' : undefined,
|
||||||
$data: createPanelDataProvider(libPanelModel),
|
$data: createPanelDataProvider(libPanelModel),
|
||||||
|
menu: new VizPanelMenu({
|
||||||
|
$behaviors: [panelMenuBehavior],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
vizPanel.setState({
|
vizPanel.setState({
|
||||||
|
@ -29,7 +29,7 @@ describe('panelMenuBehavior', () => {
|
|||||||
it('Given standard panel', async () => {
|
it('Given standard panel', async () => {
|
||||||
const { menu, panel } = await buildTestScene({});
|
const { menu, panel } = await buildTestScene({});
|
||||||
|
|
||||||
Object.assign(panel, 'getPlugin', () => getPanelPlugin({}));
|
panel.getPlugin = () => getPanelPlugin({ skipDataQuery: false });
|
||||||
|
|
||||||
mocks.contextSrv.hasAccessToExplore.mockReturnValue(true);
|
mocks.contextSrv.hasAccessToExplore.mockReturnValue(true);
|
||||||
mocks.getExploreUrl.mockReturnValue(Promise.resolve('/explore'));
|
mocks.getExploreUrl.mockReturnValue(Promise.resolve('/explore'));
|
||||||
@ -56,6 +56,9 @@ describe('panelMenuBehavior', () => {
|
|||||||
|
|
||||||
// verify inspect url keeps url params and adds inspect=<panel-key>
|
// verify inspect url keeps url params and adds inspect=<panel-key>
|
||||||
expect(menu.state.items?.[4].href).toBe('/scenes/dashboard/dash-1?from=now-5m&to=now&inspect=panel-12');
|
expect(menu.state.items?.[4].href).toBe('/scenes/dashboard/dash-1?from=now-5m&to=now&inspect=panel-12');
|
||||||
|
expect(menu.state.items?.[4].subMenu).toBeDefined();
|
||||||
|
|
||||||
|
expect(menu.state.items?.[4].subMenu?.length).toBe(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,9 +23,12 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
|||||||
// hm.. add another generic param to SceneObject to specify parent type?
|
// hm.. add another generic param to SceneObject to specify parent type?
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
const panel = menu.parent as VizPanel;
|
const panel = menu.parent as VizPanel;
|
||||||
|
const plugin = panel.getPlugin();
|
||||||
|
|
||||||
const location = locationService.getLocation();
|
const location = locationService.getLocation();
|
||||||
const items: PanelMenuItem[] = [];
|
const items: PanelMenuItem[] = [];
|
||||||
const moreSubMenu: PanelMenuItem[] = [];
|
const moreSubMenu: PanelMenuItem[] = [];
|
||||||
|
const inspectSubMenu: PanelMenuItem[] = [];
|
||||||
const panelId = getPanelIdForVizPanel(panel);
|
const panelId = getPanelIdForVizPanel(panel);
|
||||||
const dashboard = panel.getRoot();
|
const dashboard = panel.getRoot();
|
||||||
|
|
||||||
@ -65,8 +68,8 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
|||||||
shortcut: 'p s',
|
shortcut: 'p s',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (panel instanceof LibraryVizPanel) {
|
if (panel.parent instanceof LibraryVizPanel) {
|
||||||
// TODO: Implement unlinking library panel
|
// TODO: Implement lib panel unlinking
|
||||||
} else {
|
} else {
|
||||||
moreSubMenu.push({
|
moreSubMenu.push({
|
||||||
text: t('panel.header-menu.create-library-panel', `Create library panel`),
|
text: t('panel.header-menu.create-library-panel', `Create library panel`),
|
||||||
@ -100,12 +103,52 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (plugin && !plugin.meta.skipDataQuery) {
|
||||||
|
inspectSubMenu.push({
|
||||||
|
text: t('panel.header-menu.inspect-data', `Data`),
|
||||||
|
href: getInspectUrl(panel, InspectTab.Data),
|
||||||
|
onClick: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
|
||||||
|
reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Data });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dashboard instanceof DashboardScene && dashboard.state.meta.canEdit) {
|
||||||
|
inspectSubMenu.push({
|
||||||
|
text: t('panel.header-menu.query', `Query`),
|
||||||
|
href: getInspectUrl(panel, InspectTab.Query),
|
||||||
|
onClick: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Query });
|
||||||
|
reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Query });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inspectSubMenu.push({
|
||||||
|
text: t('panel.header-menu.inspect-json', `Panel JSON`),
|
||||||
|
href: getInspectUrl(panel, InspectTab.JSON),
|
||||||
|
onClick: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.JSON });
|
||||||
|
reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.JSON });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
text: t('panel.header-menu.inspect', `Inspect`),
|
text: t('panel.header-menu.inspect', `Inspect`),
|
||||||
iconClassName: 'info-circle',
|
iconClassName: 'info-circle',
|
||||||
shortcut: 'i',
|
shortcut: 'i',
|
||||||
onClick: () => reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Data }),
|
|
||||||
href: getInspectUrl(panel),
|
href: getInspectUrl(panel),
|
||||||
|
onClick: (e) => {
|
||||||
|
if (!e.isDefaultPrevented()) {
|
||||||
|
locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
|
||||||
|
reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Data });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subMenu: inspectSubMenu.length > 0 ? inspectSubMenu : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (moreSubMenu.length) {
|
if (moreSubMenu.length) {
|
||||||
|
@ -3,6 +3,7 @@ import { config, locationSearchToObject, locationService } from '@grafana/runtim
|
|||||||
import { sceneGraph, VizPanel } from '@grafana/scenes';
|
import { sceneGraph, VizPanel } from '@grafana/scenes';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { getExploreUrl } from 'app/core/utils/explore';
|
import { getExploreUrl } from 'app/core/utils/explore';
|
||||||
|
import { InspectTab } from 'app/features/inspector/types';
|
||||||
|
|
||||||
import { getQueryRunnerFor } from './utils';
|
import { getQueryRunnerFor } from './utils';
|
||||||
|
|
||||||
@ -71,8 +72,8 @@ export function getViewPanelUrl(vizPanel: VizPanel) {
|
|||||||
return locationUtil.getUrlForPartial(locationService.getLocation(), { viewPanel: vizPanel.state.key });
|
return locationUtil.getUrlForPartial(locationService.getLocation(), { viewPanel: vizPanel.state.key });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInspectUrl(vizPanel: VizPanel) {
|
export function getInspectUrl(vizPanel: VizPanel, inspectTab?: InspectTab) {
|
||||||
return locationUtil.getUrlForPartial(locationService.getLocation(), { inspect: vizPanel.state.key });
|
return locationUtil.getUrlForPartial(locationService.getLocation(), { inspect: vizPanel.state.key, inspectTab });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tryGetExploreUrlForPanel(vizPanel: VizPanel): Promise<string | undefined> {
|
export function tryGetExploreUrlForPanel(vizPanel: VizPanel): Promise<string | undefined> {
|
||||||
|
Loading…
Reference in New Issue
Block a user