diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts index 40d20b88c38..cc2a97b4a50 100644 --- a/packages/grafana-data/src/types/pluginExtensions.ts +++ b/packages/grafana-data/src/types/pluginExtensions.ts @@ -30,6 +30,7 @@ export type PluginExtensionLink = PluginExtensionBase & { onClick?: (event?: React.MouseEvent) => void; icon?: IconName; category?: string; + openInNewTab?: boolean; }; export type PluginExtensionComponentMeta = Omit; @@ -86,6 +87,7 @@ export type PluginExtensionAddedComponentConfig = PluginExtensionCon */ component: React.ComponentType; }; + export type PluginExtensionAddedFunctionConfig = PluginExtensionConfigBase & { /** * The target extension points where the component will be added @@ -106,6 +108,7 @@ export type PluginAddedLinksConfigureFunc = (context: Re onClick: (event: React.MouseEvent | undefined, helpers: PluginExtensionEventHelpers) => void; icon: IconName; category: string; + openInNewTab: boolean; }> | undefined; @@ -137,6 +140,10 @@ export type PluginExtensionAddedLinkConfig = Pl // (Optional) A category to be used when grouping the options in the ui category?: string; + + // (Optional) If true, opens the link in a new tab (renders with target="_blank") + // (Important: this is not guaranteed, depends on the extension point if it implements it.) + openInNewTab?: boolean; }; export type PluginExtensionExposedComponentConfig = PluginExtensionConfigBase & { diff --git a/public/app/features/plugins/extensions/registry/AddedLinksRegistry.test.ts b/public/app/features/plugins/extensions/registry/AddedLinksRegistry.test.ts index 63ab6b55090..07574745d71 100644 --- a/public/app/features/plugins/extensions/registry/AddedLinksRegistry.test.ts +++ b/public/app/features/plugins/extensions/registry/AddedLinksRegistry.test.ts @@ -95,6 +95,7 @@ describe('AddedLinksRegistry', () => { path: `/a/${pluginId}/declare-incident`, targets: 'plugins/myorg-basic-app/start', configure: jest.fn().mockImplementation((context) => ({ title: context?.title })), + openInNewTab: true, }, ], }); @@ -120,6 +121,7 @@ describe('AddedLinksRegistry', () => { path: `/a/${pluginId}/declare-incident`, extensionPointId: 'plugins/myorg-basic-app/start', configure: expect.any(Function), + openInNewTab: true, }, ], }); diff --git a/public/app/features/plugins/extensions/registry/AddedLinksRegistry.ts b/public/app/features/plugins/extensions/registry/AddedLinksRegistry.ts index b3f293675ce..c3dd9faf6f1 100644 --- a/public/app/features/plugins/extensions/registry/AddedLinksRegistry.ts +++ b/public/app/features/plugins/extensions/registry/AddedLinksRegistry.ts @@ -21,6 +21,7 @@ export type AddedLinkRegistryItem = { configure?: PluginAddedLinksConfigureFunc; icon?: IconName; category?: string; + openInNewTab?: boolean; }; export class AddedLinksRegistry extends Registry { @@ -40,13 +41,14 @@ export class AddedLinksRegistry extends Registry { title: '2', description: '2', path: `/a/${pluginId}/2`, + openInNewTab: true, }, { targets: 'plugins/another-extension/v1', @@ -181,7 +182,9 @@ describe('usePluginLinks()', () => { expect(result.current.links.length).toBe(2); expect(result.current.links[0].title).toBe('1'); + expect(result.current.links[0].openInNewTab).toBeUndefined(); expect(result.current.links[1].title).toBe('2'); + expect(result.current.links[1].openInNewTab).toBe(true); }); it('should dynamically update the extensions registered for a certain extension point', () => { diff --git a/public/app/features/plugins/extensions/usePluginLinks.tsx b/public/app/features/plugins/extensions/usePluginLinks.tsx index 70518ab9450..9ec5d215f94 100644 --- a/public/app/features/plugins/extensions/usePluginLinks.tsx +++ b/public/app/features/plugins/extensions/usePluginLinks.tsx @@ -51,6 +51,7 @@ export function usePluginLinks({ title: addedLink.title, description: addedLink.description ?? '', onClick: typeof addedLink.onClick, + openInNewTab: addedLink.openInNewTab ? 'true' : 'false', }); // Only limit if the `limitPerPlugin` is set @@ -84,6 +85,7 @@ export function usePluginLinks({ 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 9bc9171a49f..adb1ed8616d 100644 --- a/public/app/features/plugins/extensions/utils.tsx +++ b/public/app/features/plugins/extensions/utils.tsx @@ -474,12 +474,14 @@ export function getLinkExtensionOverrides( return undefined; } + // Only allowing to override the following properties let { title = config.title, description = config.description, path = config.path, icon = config.icon, category = config.category, + openInNewTab = config.openInNewTab, ...rest } = overrides; @@ -504,6 +506,7 @@ export function getLinkExtensionOverrides( path, icon, category, + openInNewTab, }; } catch (error) { if (error instanceof Error) {