From 0d1e0bc21cf690e5df837f765b21a5ab6c0a9467 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Wed, 14 Jan 2026 11:29:43 +0100 Subject: [PATCH] PanelMenu: use openInNewTab links extensions API correctly (#116200) * Extensons: Make links use openInNewTab API * Use openInNewTab api correctly in the UI * Bump scenes * Fx circular dep * test * Revert "test" This reverts commit 8784a7992c60889dda824433331b7072ea80b0cd. --- package.json | 4 ++-- packages/grafana-data/src/index.ts | 2 +- packages/grafana-data/src/types/dataLink.ts | 3 +-- packages/grafana-data/src/types/linkTarget.ts | 4 ++++ packages/grafana-data/src/types/navModel.ts | 2 +- packages/grafana-data/src/types/panel.ts | 2 ++ .../plugins/extensions/getPluginExtensions.ts | 1 + .../app/features/plugins/extensions/utils.tsx | 2 ++ yarn.lock | 22 +++++++++---------- 9 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 packages/grafana-data/src/types/linkTarget.ts diff --git a/package.json b/package.json index a6887b216e4..0a39ff67aea 100644 --- a/package.json +++ b/package.json @@ -293,8 +293,8 @@ "@grafana/plugin-ui": "^0.11.1", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "v6.52.1", - "@grafana/scenes-react": "v6.52.1", + "@grafana/scenes": "6.52.2", + "@grafana/scenes-react": "6.52.2", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 6027b566764..5ed081b00f0 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -844,7 +844,6 @@ export { DataLinkConfigOrigin, SupportedTransformationType, type InternalDataLink, - type LinkTarget, type LinkModel, type LinkModelSupplier, VariableOrigin, @@ -852,6 +851,7 @@ export { VariableSuggestionsScope, OneClickMode, } from './types/dataLink'; +export { type LinkTarget } from './types/linkTarget'; export { type Action, type ActionModel, diff --git a/packages/grafana-data/src/types/dataLink.ts b/packages/grafana-data/src/types/dataLink.ts index 815b67f0352..ad556a75c76 100644 --- a/packages/grafana-data/src/types/dataLink.ts +++ b/packages/grafana-data/src/types/dataLink.ts @@ -1,5 +1,6 @@ import { ScopedVars } from './ScopedVars'; import { ExploreCorrelationHelperData, ExplorePanelsState } from './explore'; +import { LinkTarget } from './linkTarget'; import { InterpolateFunction } from './panel'; import { DataQuery } from './query'; import { TimeRange } from './time'; @@ -88,8 +89,6 @@ export interface InternalDataLink { range?: TimeRange; } -export type LinkTarget = '_blank' | '_self' | undefined; - /** * Processed Link Model. The values are ready to use */ diff --git a/packages/grafana-data/src/types/linkTarget.ts b/packages/grafana-data/src/types/linkTarget.ts new file mode 100644 index 00000000000..2cdd963da7a --- /dev/null +++ b/packages/grafana-data/src/types/linkTarget.ts @@ -0,0 +1,4 @@ +/** + * Target for links - controls whether link opens in new tab or same tab + */ +export type LinkTarget = '_blank' | '_self' | undefined; diff --git a/packages/grafana-data/src/types/navModel.ts b/packages/grafana-data/src/types/navModel.ts index f9ebb23fc07..815b9d04e2d 100644 --- a/packages/grafana-data/src/types/navModel.ts +++ b/packages/grafana-data/src/types/navModel.ts @@ -1,7 +1,7 @@ import { ComponentType } from 'react'; -import { LinkTarget } from './dataLink'; import { IconName } from './icon'; +import { LinkTarget } from './linkTarget'; export interface NavLinkDTO { id?: string; diff --git a/packages/grafana-data/src/types/panel.ts b/packages/grafana-data/src/types/panel.ts index acf1e36c905..b9d6491cf9b 100644 --- a/packages/grafana-data/src/types/panel.ts +++ b/packages/grafana-data/src/types/panel.ts @@ -11,6 +11,7 @@ import { DataFrame } from './dataFrame'; import { DataQueryError, DataQueryRequest, DataQueryTimings } from './datasource'; import { FieldConfigSource } from './fieldOverrides'; import { IconName } from './icon'; +import { LinkTarget } from './linkTarget'; import { OptionEditorConfig } from './options'; import { PluginMeta } from './plugin'; import { AbsoluteTimeRange, TimeRange, TimeZone } from './time'; @@ -191,6 +192,7 @@ export interface PanelMenuItem { onClick?: (event: React.MouseEvent) => void; shortcut?: string; href?: string; + target?: LinkTarget; subMenu?: PanelMenuItem[]; } diff --git a/public/app/features/plugins/extensions/getPluginExtensions.ts b/public/app/features/plugins/extensions/getPluginExtensions.ts index c81fd7c26f4..6f02a7daf77 100644 --- a/public/app/features/plugins/extensions/getPluginExtensions.ts +++ b/public/app/features/plugins/extensions/getPluginExtensions.ts @@ -141,6 +141,7 @@ export const getPluginExtensions: GetExtensions = ({ description: overrides?.description || addedLink.description || '', path: isString(path) ? getLinkExtensionPathWithTracking(pluginId, path, extensionPointId) : undefined, category: overrides?.category || addedLink.category, + openInNewTab: overrides?.openInNewTab ?? addedLink.openInNewTab, }; extensions.push(extension); diff --git a/public/app/features/plugins/extensions/utils.tsx b/public/app/features/plugins/extensions/utils.tsx index adb1ed8616d..0046aab0fe6 100644 --- a/public/app/features/plugins/extensions/utils.tsx +++ b/public/app/features/plugins/extensions/utils.tsx @@ -420,6 +420,7 @@ export function createExtensionSubMenu(extensions: PluginExtensionLink[]): Panel href: extension.path, onClick: extension.onClick, iconClassName: extension.icon, + target: extension.openInNewTab ? '_blank' : undefined, }); continue; } @@ -433,6 +434,7 @@ export function createExtensionSubMenu(extensions: PluginExtensionLink[]): Panel href: extension.path, onClick: extension.onClick, iconClassName: extension.icon, + target: extension.openInNewTab ? '_blank' : undefined, }); } diff --git a/yarn.lock b/yarn.lock index 41cc10d8353..1069acd8544 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3789,11 +3789,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:v6.52.1": - version: 6.52.1 - resolution: "@grafana/scenes-react@npm:6.52.1" +"@grafana/scenes-react@npm:6.52.2": + version: 6.52.2 + resolution: "@grafana/scenes-react@npm:6.52.2" dependencies: - "@grafana/scenes": "npm:6.52.1" + "@grafana/scenes": "npm:6.52.2" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3805,7 +3805,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/2f7c6ca8e26befd331808afb0cb934e2991e889a4de78be1122c536219676261c59c6204510761a1d4250fd44a3767818f0f225d23b2e7243cfc17baf8ca6ca3 + checksum: 10/c393faf6612e78254dab79b15cc970448d74ba9784ccda623953c5dbc21d91a8da94b7ad7d0d294eac51314cc193c419a7cb48295fd50b1f9c4472699669eb3e languageName: node linkType: hard @@ -3835,9 +3835,9 @@ __metadata: languageName: node linkType: hard -"@grafana/scenes@npm:6.52.1, @grafana/scenes@npm:v6.52.1": - version: 6.52.1 - resolution: "@grafana/scenes@npm:6.52.1" +"@grafana/scenes@npm:6.52.2": + version: 6.52.2 + resolution: "@grafana/scenes@npm:6.52.2" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3857,7 +3857,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/d6172b51121e03c7dcbf30046772f99fc45922c1f7b360a7c3d2c0391300e378f306cb78251dda3b30895679379c38db30e4d52fee67a56cd95f18f38aadf3fb + checksum: 10/f6dbe20db78bb1aa09cc38025534917887713d73119a172febb44700837ed859363ee0436b5f4bda6bc063f9432115e32519ab4c8da7834cf1fc22d43fea7711 languageName: node linkType: hard @@ -19790,8 +19790,8 @@ __metadata: "@grafana/plugin-ui": "npm:^0.11.1" "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:v6.52.1" - "@grafana/scenes-react": "npm:v6.52.1" + "@grafana/scenes": "npm:6.52.2" + "@grafana/scenes-react": "npm:6.52.2" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/test-utils": "workspace:*"