mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Panel links support (#77295)
* DashboardScene: PanelLinks support * Update public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx * Remove code * Use updated API * Bump scenes version
This commit is contained in:
48
public/app/features/dashboard-scene/scene/PanelLinks.tsx
Normal file
48
public/app/features/dashboard-scene/scene/PanelLinks.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
|
||||
import { LinkModel } from '@grafana/data';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
|
||||
import { Dropdown, Menu, ToolbarButton } from '@grafana/ui';
|
||||
|
||||
interface VizPanelLinksState extends SceneObjectState {
|
||||
links?: LinkModel[];
|
||||
menu: VizPanelLinksMenu;
|
||||
}
|
||||
|
||||
export class VizPanelLinks extends SceneObjectBase<VizPanelLinksState> {
|
||||
static Component = VizPanelLinksRenderer;
|
||||
}
|
||||
|
||||
function VizPanelLinksRenderer({ model }: SceneComponentProps<VizPanelLinks>) {
|
||||
const { menu } = model.useState();
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
overlay={() => {
|
||||
return <menu.Component model={menu} key={menu.state.key} />;
|
||||
}}
|
||||
>
|
||||
<ToolbarButton icon="external-link-alt" iconSize="md" aria-label="panel links" />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
export class VizPanelLinksMenu extends SceneObjectBase<Omit<VizPanelLinksState, 'menu'>> {
|
||||
static Component = VizPanelLinksMenuRenderer;
|
||||
}
|
||||
|
||||
function VizPanelLinksMenuRenderer({ model }: SceneComponentProps<VizPanelLinks>) {
|
||||
const { links } = model.useState();
|
||||
|
||||
if (!links) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
{links?.map((link, idx) => {
|
||||
return <Menu.Item key={idx} label={link.title} url={link.href} target={link.target} onClick={link.onClick} />;
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
import { PanelMenuItem } from '@grafana/data';
|
||||
import { InterpolateFunction, PanelMenuItem } from '@grafana/data';
|
||||
import { locationService, reportInteraction } from '@grafana/runtime';
|
||||
import { VizPanel, VizPanelMenu } from '@grafana/scenes';
|
||||
import { sceneGraph, VizPanel, VizPanelMenu } from '@grafana/scenes';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { InspectTab } from 'app/features/inspector/types';
|
||||
import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
|
||||
|
||||
import { ShareModal } from '../sharing/ShareModal';
|
||||
import { getDashboardUrl, getInspectUrl, getViewPanelUrl, tryGetExploreUrlForPanel } from '../utils/urlBuilders';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import { VizPanelLinks } from './PanelLinks';
|
||||
|
||||
/**
|
||||
* Behavior is called when VizPanelMenu is activated (ie when it's opened).
|
||||
@@ -81,3 +84,31 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
|
||||
asyncFunc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Behavior is called when VizPanelLinksMenu is activated (when it's opened).
|
||||
*/
|
||||
export function getPanelLinksBehavior(panel: PanelModel) {
|
||||
return (panelLinksMenu: VizPanelLinks) => {
|
||||
const interpolate: InterpolateFunction = (v, scopedVars) => {
|
||||
return sceneGraph.interpolate(panelLinksMenu, v, scopedVars);
|
||||
};
|
||||
|
||||
const linkSupplier = getPanelLinksSupplier(panel, interpolate);
|
||||
|
||||
if (!linkSupplier) {
|
||||
return;
|
||||
}
|
||||
|
||||
const panelLinks = linkSupplier && linkSupplier.getLinks(interpolate);
|
||||
|
||||
const links = panelLinks.map((panelLink) => ({
|
||||
...panelLink,
|
||||
onClick: (e: any, origin: any) => {
|
||||
reportInteraction('dashboards_panelheader_datalink_clicked', { has_multiple_links: panelLinks.length > 1 });
|
||||
panelLink.onClick?.(e, origin);
|
||||
},
|
||||
}));
|
||||
panelLinksMenu.setState({ links });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ import { DashboardDTO } from 'app/types';
|
||||
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
|
||||
import { getPanelLinksBehavior, panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
@@ -346,9 +347,19 @@ export function buildGridItemForLibPanel(panel: PanelModel) {
|
||||
}
|
||||
|
||||
export function buildGridItemForPanel(panel: PanelModel): SceneGridItemLike {
|
||||
const hasPanelLinks = panel.links && panel.links.length > 0;
|
||||
let panelLinks;
|
||||
|
||||
if (hasPanelLinks) {
|
||||
panelLinks = new VizPanelLinks({
|
||||
menu: new VizPanelLinksMenu({ $behaviors: [getPanelLinksBehavior(panel)] }),
|
||||
});
|
||||
}
|
||||
|
||||
const vizPanelState: VizPanelState = {
|
||||
key: getVizPanelKeyForPanelId(panel.id),
|
||||
title: panel.title,
|
||||
description: panel.description,
|
||||
pluginId: panel.type,
|
||||
options: panel.options ?? {},
|
||||
fieldConfig: panel.fieldConfig,
|
||||
@@ -360,6 +371,8 @@ export function buildGridItemForPanel(panel: PanelModel): SceneGridItemLike {
|
||||
menu: new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
}),
|
||||
titleItems: panelLinks,
|
||||
|
||||
extendPanelContext: setDashboardPanelContext,
|
||||
_UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel),
|
||||
};
|
||||
|
||||
@@ -139,7 +139,10 @@ export const getFieldLinksSupplier = (value: FieldDisplay): LinkModelSupplier<Fi
|
||||
};
|
||||
};
|
||||
|
||||
export const getPanelLinksSupplier = (panel: PanelModel): LinkModelSupplier<PanelModel> | undefined => {
|
||||
export const getPanelLinksSupplier = (
|
||||
panel: PanelModel,
|
||||
replaceVariables?: InterpolateFunction
|
||||
): LinkModelSupplier<PanelModel> | undefined => {
|
||||
const links = panel.links;
|
||||
|
||||
if (!links || links.length === 0) {
|
||||
@@ -149,7 +152,7 @@ export const getPanelLinksSupplier = (panel: PanelModel): LinkModelSupplier<Pane
|
||||
return {
|
||||
getLinks: () => {
|
||||
return links.map((link) => {
|
||||
return getLinkSrv().getDataLinkUIModel(link, panel.replaceVariables, panel);
|
||||
return getLinkSrv().getDataLinkUIModel(link, replaceVariables || panel.replaceVariables, panel);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user