mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
b88206d98f
commit
f46f8bdd3a
@ -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]*$"
|
||||||
},
|
},
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
@ -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)",
|
||||||
|
@ -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)",
|
||||||
|
@ -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
|
||||||
|
@ -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"`
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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}`),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user