Plugins: Renamed parts of the UI extension APIs (#63070)

* Renamed target -> id and href -> path after feedback.

* fixed type issues in test page.

* chore(pluginschemajson): update extensions props target -> id

* this is the final.

* fixed typings...again...

---------

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
This commit is contained in:
Marcus Andersson 2023-02-08 11:33:28 +01:00 committed by GitHub
parent b88206d98f
commit f46f8bdd3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 46 additions and 46 deletions

View File

@ -480,7 +480,7 @@
"type": "object", "type": "object",
"description": "Expose a page link that can be used by Grafana core or other plugins to navigate users to the plugin", "description": "Expose a page link that can be used by Grafana core or other plugins to navigate users to the plugin",
"additionalProperties": false, "additionalProperties": false,
"required": ["type", "title", "target", "path"], "required": ["type", "title", "placement", "path"],
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
@ -491,7 +491,7 @@
"minLength": 3, "minLength": 3,
"maxLength": 22 "maxLength": 22
}, },
"target": { "placement": {
"type": "string", "type": "string",
"pattern": "^(plugins|grafana)/[a-z-/0-9]*$" "pattern": "^(plugins|grafana)/[a-z-/0-9]*$"
}, },

View File

@ -29,7 +29,7 @@ export enum PluginExtensionTypes {
} }
export type PluginsExtensionLinkConfig = { export type PluginsExtensionLinkConfig = {
target: string; placement: string;
type: PluginExtensionTypes.link; type: PluginExtensionTypes.link;
title: string; title: string;
description: string; description: string;

View File

@ -13,7 +13,7 @@ describe('getPluginExtensions', () => {
type: 'link', type: 'link',
title: 'Declare incident', title: 'Declare incident',
description: 'Declaring an incident in the app', description: 'Declaring an incident in the app',
href: `/a/${pluginId}/declare-incident`, path: `/a/${pluginId}/declare-incident`,
key: 1, key: 1,
}, },
], ],
@ -22,26 +22,26 @@ describe('getPluginExtensions', () => {
it('should return a collection of extensions to the plugin', () => { it('should return a collection of extensions to the plugin', () => {
const { extensions, error } = getPluginExtensions({ const { extensions, error } = getPluginExtensions({
target: `plugins/${pluginId}/${linkId}`, placement: `plugins/${pluginId}/${linkId}`,
}); });
expect(extensions[0].href).toBe(`/a/${pluginId}/declare-incident`); expect(extensions[0].path).toBe(`/a/${pluginId}/declare-incident`);
expect(error).toBeUndefined(); expect(error).toBeUndefined();
}); });
it('should return a description for the requested link', () => { it('should return a description for the requested link', () => {
const { extensions, error } = getPluginExtensions({ const { extensions, error } = getPluginExtensions({
target: `plugins/${pluginId}/${linkId}`, placement: `plugins/${pluginId}/${linkId}`,
}); });
expect(extensions[0].href).toBe(`/a/${pluginId}/declare-incident`); expect(extensions[0].path).toBe(`/a/${pluginId}/declare-incident`);
expect(extensions[0].description).toBe('Declaring an incident in the app'); expect(extensions[0].description).toBe('Declaring an incident in the app');
expect(error).toBeUndefined(); expect(error).toBeUndefined();
}); });
it('should return an empty array when no links can be found', () => { it('should return an empty array when no links can be found', () => {
const { extensions, error } = getPluginExtensions({ const { extensions, error } = getPluginExtensions({
target: `an-unknown-app/${linkId}`, placement: `an-unknown-app/${linkId}`,
}); });
expect(extensions.length).toBe(0); expect(extensions.length).toBe(0);

View File

@ -1,7 +1,7 @@
import { getPluginsExtensionRegistry, PluginsExtension } from './registry'; import { getPluginsExtensionRegistry, PluginsExtension } from './registry';
export type GetPluginExtensionsOptions = { export type GetPluginExtensionsOptions = {
target: string; placement: string;
}; };
export type PluginExtensionsResult = { export type PluginExtensionsResult = {
@ -10,23 +10,23 @@ export type PluginExtensionsResult = {
}; };
export class PluginExtensionsMissingError extends Error { export class PluginExtensionsMissingError extends Error {
readonly target: string; readonly placement: string;
constructor(target: string) { constructor(placement: string) {
super(`Could not find extensions for '${target}'`); super(`Could not find extensions for '${placement}'`);
this.target = target; this.placement = placement;
this.name = PluginExtensionsMissingError.name; this.name = PluginExtensionsMissingError.name;
} }
} }
export function getPluginExtensions({ target }: GetPluginExtensionsOptions): PluginExtensionsResult { export function getPluginExtensions({ placement }: GetPluginExtensionsOptions): PluginExtensionsResult {
const registry = getPluginsExtensionRegistry(); const registry = getPluginsExtensionRegistry();
const extensions = registry[target]; const extensions = registry[placement];
if (!Array.isArray(extensions)) { if (!Array.isArray(extensions)) {
return { return {
extensions: [], extensions: [],
error: new PluginExtensionsMissingError(target), error: new PluginExtensionsMissingError(placement),
}; };
} }

View File

@ -2,7 +2,7 @@ export type PluginsExtensionLink = {
type: 'link'; type: 'link';
title: string; title: string;
description: string; description: string;
href: string; path: string;
key: number; key: number;
}; };

View File

@ -244,7 +244,7 @@ func TestHTTPServer_GetFrontendSettings_apps(t *testing.T) {
return &plugins.FakePluginStore{ return &plugins.FakePluginStore{
PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{ PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{
{ {
Target: "core/home/menu", Placement: "core/home/menu",
Type: plugindef.ExtensionsLinkTypeLink, Type: plugindef.ExtensionsLinkTypeLink,
Title: "Title", Title: "Title",
Description: "Home route of app", Description: "Home route of app",
@ -267,7 +267,7 @@ func TestHTTPServer_GetFrontendSettings_apps(t *testing.T) {
Version: "0.5.0", Version: "0.5.0",
Extensions: []*plugindef.ExtensionsLink{ Extensions: []*plugindef.ExtensionsLink{
{ {
Target: "core/home/menu", Placement: "core/home/menu",
Type: plugindef.ExtensionsLinkTypeLink, Type: plugindef.ExtensionsLinkTypeLink,
Title: "Title", Title: "Title",
Description: "Home route of app", Description: "Home route of app",
@ -284,7 +284,7 @@ func TestHTTPServer_GetFrontendSettings_apps(t *testing.T) {
return &plugins.FakePluginStore{ return &plugins.FakePluginStore{
PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{ PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{
{ {
Target: "core/home/menu", Placement: "core/home/menu",
Type: plugindef.ExtensionsLinkTypeLink, Type: plugindef.ExtensionsLinkTypeLink,
Title: "Title", Title: "Title",
Description: "Home route of app", Description: "Home route of app",

View File

@ -502,14 +502,14 @@ func TestLoader_Load(t *testing.T) {
}, },
Extensions: []*plugindef.ExtensionsLink{ Extensions: []*plugindef.ExtensionsLink{
{ {
Target: "plugins/grafana-slo-app/slo-breach", Placement: "plugins/grafana-slo-app/slo-breach",
Title: "Declare incident", Title: "Declare incident",
Type: plugindef.ExtensionsLinkTypeLink, Type: plugindef.ExtensionsLinkTypeLink,
Description: "Declares a new incident", Description: "Declares a new incident",
Path: "/incidents/declare", Path: "/incidents/declare",
}, },
{ {
Target: "plugins/grafana-slo-app/slo-breach", Placement: "plugins/grafana-slo-app/slo-breach",
Title: "Declare incident", Title: "Declare incident",
Type: plugindef.ExtensionsLinkTypeLink, Type: plugindef.ExtensionsLinkTypeLink,
Description: "Declares a new incident (path without backslash)", Description: "Declares a new incident (path without backslash)",

View File

@ -36,14 +36,14 @@
], ],
"extensions": [ "extensions": [
{ {
"target": "plugins/grafana-slo-app/slo-breach", "placement": "plugins/grafana-slo-app/slo-breach",
"type": "link", "type": "link",
"title": "Declare incident", "title": "Declare incident",
"description": "Declares a new incident", "description": "Declares a new incident",
"path": "/incidents/declare" "path": "/incidents/declare"
}, },
{ {
"target": "plugins/grafana-slo-app/slo-breach", "placement": "plugins/grafana-slo-app/slo-breach",
"type": "link", "type": "link",
"title": "Declare incident", "title": "Declare incident",
"description": "Declares a new incident (path without backslash)", "description": "Declares a new incident (path without backslash)",

View File

@ -124,7 +124,7 @@ seqs: [
#ExtensionsLink: { #ExtensionsLink: {
// Target where the link will be rendered // Target where the link will be rendered
target: =~"^(plugins|grafana)\/[a-z-/0-9]*$" placement: =~"^(plugins|grafana)\/[a-z-/0-9]*$"
// Type of extension // Type of extension
type: "link" type: "link"
// Title that will be displayed for the rendered link // Title that will be displayed for the rendered link

View File

@ -162,7 +162,7 @@ type ExtensionsLink struct {
Path string `json:"path"` Path string `json:"path"`
// Target where the link will be rendered // Target where the link will be rendered
Target string `json:"target"` Placement string `json:"placement"`
// Title that will be displayed for the rendered link // Title that will be displayed for the rendered link
Title string `json:"title"` Title string `json:"title"`

View File

@ -7,7 +7,7 @@ describe('Plugin registry', () => {
const registry = createPluginExtensionsRegistry({ const registry = createPluginExtensionsRegistry({
'belugacdn-app': createConfig([ 'belugacdn-app': createConfig([
{ {
target: 'plugins/belugacdn-app/menu', placement: 'plugins/belugacdn-app/menu',
title: 'The title', title: 'The title',
type: PluginExtensionTypes.link, type: PluginExtensionTypes.link,
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
@ -16,7 +16,7 @@ describe('Plugin registry', () => {
]), ]),
'strava-app': createConfig([ 'strava-app': createConfig([
{ {
target: 'plugins/strava-app/menu', placement: 'plugins/strava-app/menu',
title: 'The title', title: 'The title',
type: PluginExtensionTypes.link, type: PluginExtensionTypes.link,
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
@ -25,14 +25,14 @@ describe('Plugin registry', () => {
]), ]),
'duplicate-links-app': createConfig([ 'duplicate-links-app': createConfig([
{ {
target: 'plugins/duplicate-links-app/menu', placement: 'plugins/duplicate-links-app/menu',
title: 'The title', title: 'The title',
type: PluginExtensionTypes.link, type: PluginExtensionTypes.link,
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
path: '/incidents/declare', path: '/incidents/declare',
}, },
{ {
target: 'plugins/duplicate-links-app/menu', placement: 'plugins/duplicate-links-app/menu',
title: 'The title', title: 'The title',
type: PluginExtensionTypes.link, type: PluginExtensionTypes.link,
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
@ -49,7 +49,7 @@ describe('Plugin registry', () => {
title: 'The title', title: 'The title',
type: 'link', type: 'link',
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
href: '/a/belugacdn-app/incidents/declare', path: '/a/belugacdn-app/incidents/declare',
key: 539074708, key: 539074708,
}); });
}); });
@ -68,7 +68,7 @@ describe('Plugin registry', () => {
title: 'The title', title: 'The title',
type: 'link', type: 'link',
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
href: '/a/belugacdn-app/incidents/declare', path: '/a/belugacdn-app/incidents/declare',
key: 539074708, key: 539074708,
}); });
@ -76,7 +76,7 @@ describe('Plugin registry', () => {
title: 'The title', title: 'The title',
type: 'link', type: 'link',
description: 'Incidents are occurring!', description: 'Incidents are occurring!',
href: '/a/strava-app/incidents/declare', path: '/a/strava-app/incidents/declare',
key: -1637066384, key: -1637066384,
}); });
}); });

View File

@ -17,15 +17,15 @@ export function createPluginExtensionsRegistry(apps: Record<string, AppPluginCon
} }
for (const extension of extensions) { for (const extension of extensions) {
const target = extension.target; const placement = extension.placement;
const item = createRegistryItem(pluginId, extension); const item = createRegistryItem(pluginId, extension);
if (!Array.isArray(registry[target])) { if (!Array.isArray(registry[placement])) {
registry[target] = [item]; registry[placement] = [item];
continue; continue;
} }
registry[target].push(item); registry[placement].push(item);
continue; continue;
} }
} }
@ -38,14 +38,14 @@ export function createPluginExtensionsRegistry(apps: Record<string, AppPluginCon
} }
function createRegistryItem(pluginId: string, extension: PluginsExtensionLinkConfig): PluginsExtensionLink { function createRegistryItem(pluginId: string, extension: PluginsExtensionLinkConfig): PluginsExtensionLink {
const href = `/a/${pluginId}${extension.path}`; const path = `/a/${pluginId}${extension.path}`;
return Object.freeze({ return Object.freeze({
type: PluginExtensionTypes.link, type: PluginExtensionTypes.link,
title: extension.title, title: extension.title,
description: extension.description, description: extension.description,
href: href, path: path,
key: hashKey(`${extension.title}${href}`), key: hashKey(`${extension.title}${path}`),
}); });
} }

View File

@ -62,7 +62,7 @@ export const TestStuffPage = () => {
<Page navModel={{ node: node, main: node }}> <Page navModel={{ node: node, main: node }}>
<Page.Contents> <Page.Contents>
<HorizontalGroup> <HorizontalGroup>
<LinkToBasicApp target="grafana/sandbox/testing" /> <LinkToBasicApp placement="grafana/sandbox/testing" />
</HorizontalGroup> </HorizontalGroup>
{data && ( {data && (
<AutoSizer style={{ width: '100%', height: '600px' }}> <AutoSizer style={{ width: '100%', height: '600px' }}>
@ -148,8 +148,8 @@ export function getDefaultState(): State {
}; };
} }
function LinkToBasicApp({ target }: { target: string }) { function LinkToBasicApp({ placement }: { placement: string }) {
const { extensions, error } = getPluginExtensions({ target }); const { extensions, error } = getPluginExtensions({ placement });
if (error) { if (error) {
return null; return null;
@ -159,7 +159,7 @@ function LinkToBasicApp({ target }: { target: string }) {
<div> <div>
{extensions.map((extension) => { {extensions.map((extension) => {
return ( return (
<LinkButton href={extension.href} title={extension.description} key={extension.key}> <LinkButton href={extension.path} title={extension.description} key={extension.key}>
{extension.title} {extension.title}
</LinkButton> </LinkButton>
); );