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:
parent
7ba3b52e65
commit
bbe1767310
@ -2885,6 +2885,10 @@ exports[`better eslint`] = {
|
||||
"public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx:5381": [
|
||||
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
@ -257,7 +257,7 @@
|
||||
"@grafana/lezer-traceql": "0.0.8",
|
||||
"@grafana/monaco-logql": "^0.0.7",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^1.18.0",
|
||||
"@grafana/scenes": "^1.20.1",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"@kusto/monaco-kusto": "^7.4.0",
|
||||
|
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);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
10
yarn.lock
10
yarn.lock
@ -3304,9 +3304,9 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes@npm:^1.18.0":
|
||||
version: 1.20.0
|
||||
resolution: "@grafana/scenes@npm:1.20.0"
|
||||
"@grafana/scenes@npm:^1.20.1":
|
||||
version: 1.20.1
|
||||
resolution: "@grafana/scenes@npm:1.20.1"
|
||||
dependencies:
|
||||
"@grafana/e2e-selectors": 10.0.2
|
||||
react-grid-layout: 1.3.4
|
||||
@ -3318,7 +3318,7 @@ __metadata:
|
||||
"@grafana/runtime": 10.0.3
|
||||
"@grafana/schema": 10.0.3
|
||||
"@grafana/ui": 10.0.3
|
||||
checksum: cc56fa2aec1e31598a9cbb7f4837d25fc03f32879247fc2063269c1d9c8d8543c518f6cac3c4b64ea32b4f0841e334bd1af4bd38b45860c0a89473680385cafd
|
||||
checksum: 44f81303cc096885afb1bce32c3ce80739091c961dfd5a21268deb90cbbc2af2b8b5647357a833f1db4106eb4618b43e403e0fe127157ed1a302a68f89a59907
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17135,7 +17135,7 @@ __metadata:
|
||||
"@grafana/lezer-traceql": 0.0.8
|
||||
"@grafana/monaco-logql": ^0.0.7
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/scenes": ^1.18.0
|
||||
"@grafana/scenes": ^1.20.1
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/tsconfig": ^1.3.0-rc1
|
||||
"@grafana/ui": "workspace:*"
|
||||
|
Loading…
Reference in New Issue
Block a user