Plugins: Don't auto prepend app sub url to plugin asset paths (#81658)

* don't prepend app sub url to paths

* simplify logo path

* fix(plugins): dynamically prepend appSubUrl for System module resolving to work

* fix(sandbox): support dynamic appSuburl prepend when loading plugin module.js

* fix tests

* update test name

* fix tests

* update fe + add some tests

* refactor(plugins): move wrangleurl to utils, rename to resolveModulePath, update usage

* chore: fix a typo

* test(plugins): add missing name to utils test

* reset test flag

---------

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
This commit is contained in:
Will Browne 2024-02-08 12:19:28 +01:00 committed by GitHub
parent 18963dc3ae
commit 99feb928cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 289 additions and 252 deletions

View File

@ -47,12 +47,12 @@ func DefaultService(cfg *config.Cfg) *Service {
func (s *Service) Base(n PluginInfo) (string, error) { func (s *Service) Base(n PluginInfo) (string, error) {
if n.class == plugins.ClassCore { if n.class == plugins.ClassCore {
baseDir := getBaseDir(n.dir) baseDir := getBaseDir(n.dir)
return path.Join("/", s.cfg.GrafanaAppSubURL, "/public/app/plugins", string(n.pluginJSON.Type), baseDir), nil return path.Join("public/app/plugins", string(n.pluginJSON.Type), baseDir), nil
} }
if s.cdn.PluginSupported(n.pluginJSON.ID) { if s.cdn.PluginSupported(n.pluginJSON.ID) {
return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "") return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "")
} }
return path.Join("/", s.cfg.GrafanaAppSubURL, "/public/plugins", n.pluginJSON.ID), nil return path.Join("public/plugins", n.pluginJSON.ID), nil
} }
// Module returns the module.js path for the specified plugin. // Module returns the module.js path for the specified plugin.
@ -70,7 +70,7 @@ func (s *Service) Module(n PluginInfo) (string, error) {
if s.cdn.PluginSupported(n.pluginJSON.ID) { if s.cdn.PluginSupported(n.pluginJSON.ID) {
return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "module.js") return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "module.js")
} }
return path.Join("/", s.cfg.GrafanaAppSubURL, "/public/plugins", n.pluginJSON.ID, "module.js"), nil return path.Join("public/plugins", n.pluginJSON.ID, "module.js"), nil
} }
// RelativeURL returns the relative URL for an arbitrary plugin asset. // RelativeURL returns the relative URL for an arbitrary plugin asset.
@ -101,7 +101,7 @@ func (s *Service) RelativeURL(n PluginInfo, pathStr string) (string, error) {
// DefaultLogoPath returns the default logo path for the specified plugin type. // DefaultLogoPath returns the default logo path for the specified plugin type.
func (s *Service) DefaultLogoPath(pluginType plugins.Type) string { func (s *Service) DefaultLogoPath(pluginType plugins.Type) string {
return path.Join("/", s.cfg.GrafanaAppSubURL, fmt.Sprintf("/public/img/icn-%s.svg", string(pluginType))) return path.Join("public/img", fmt.Sprintf("icn-%s.svg", string(pluginType)))
} }
func getBaseDir(pluginDir string) string { func getBaseDir(pluginDir string) string {

View File

@ -69,11 +69,11 @@ func TestService(t *testing.T) {
base, err = svc.Base(NewPluginInfo(jsonData["two"], plugins.ClassExternal, extPath("two"))) base, err = svc.Base(NewPluginInfo(jsonData["two"], plugins.ClassExternal, extPath("two")))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/public/plugins/two", base) require.Equal(t, "public/plugins/two", base)
base, err = svc.Base(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS)) base, err = svc.Base(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/public/app/plugins/table-old", base) require.Equal(t, "public/app/plugins/table-old", base)
}) })
t.Run("Module", func(t *testing.T) { t.Run("Module", func(t *testing.T) {
@ -86,7 +86,7 @@ func TestService(t *testing.T) {
module, err = svc.Module(NewPluginInfo(jsonData["two"], plugins.ClassExternal, extPath("two"))) module, err = svc.Module(NewPluginInfo(jsonData["two"], plugins.ClassExternal, extPath("two")))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/public/plugins/two/module.js", module) require.Equal(t, "public/plugins/two/module.js", module)
module, err = svc.Module(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS)) module, err = svc.Module(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS))
require.NoError(t, err) require.NoError(t, err)
@ -116,16 +116,16 @@ func TestService(t *testing.T) {
u, err = svc.RelativeURL(NewPluginInfo(pluginsMap["two"].JSONData, plugins.ClassExternal, extPath("two")), "path/to/file.txt") u, err = svc.RelativeURL(NewPluginInfo(pluginsMap["two"].JSONData, plugins.ClassExternal, extPath("two")), "path/to/file.txt")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/public/plugins/two/path/to/file.txt", u) require.Equal(t, "public/plugins/two/path/to/file.txt", u)
u, err = svc.RelativeURL(NewPluginInfo(pluginsMap["two"].JSONData, plugins.ClassExternal, extPath("two")), "default") u, err = svc.RelativeURL(NewPluginInfo(pluginsMap["two"].JSONData, plugins.ClassExternal, extPath("two")), "default")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/public/plugins/two/default", u) require.Equal(t, "public/plugins/two/default", u)
}) })
}) })
} }
t.Run("With App Sub URL", func(t *testing.T) { t.Run("App Sub URL has no effect on the path", func(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
appSubURL string appSubURL string
}{ }{
@ -151,15 +151,15 @@ func TestService(t *testing.T) {
base, err := svc.Base(NewPluginInfo(p, plugins.ClassExternal, fs)) base, err := svc.Base(NewPluginInfo(p, plugins.ClassExternal, fs))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/grafana/public/plugins/test-datasource", base) require.Equal(t, "public/plugins/test-datasource", base)
mod, err := svc.Module(NewPluginInfo(p, plugins.ClassExternal, fs)) mod, err := svc.Module(NewPluginInfo(p, plugins.ClassExternal, fs))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/grafana/public/plugins/test-datasource/module.js", mod) require.Equal(t, "public/plugins/test-datasource/module.js", mod)
base, err = svc.Base(NewPluginInfo(p, plugins.ClassCore, fs)) base, err = svc.Base(NewPluginInfo(p, plugins.ClassCore, fs))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "/grafana/public/app/plugins/test-datasource", base) require.Equal(t, "public/app/plugins/test-datasource", base)
mod, err = svc.Module(NewPluginInfo(p, plugins.ClassCore, fs)) mod, err = svc.Module(NewPluginInfo(p, plugins.ClassCore, fs))
require.NoError(t, err) require.NoError(t, err)

View File

@ -83,8 +83,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Description: "Data source for Amazon AWS monitoring service", Description: "Data source for Amazon AWS monitoring service",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", Small: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Large: "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", Large: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
}, },
}, },
Includes: []*plugins.Includes{ Includes: []*plugins.Includes{
@ -106,9 +106,8 @@ func TestLoader_Load(t *testing.T) {
Backend: true, Backend: true,
QueryOptions: map[string]bool{"minInterval": true}, QueryOptions: map[string]bool{"minInterval": true},
}, },
Module: "core:plugin/cloudwatch", Module: "core:plugin/cloudwatch",
BaseURL: "/public/app/plugins/datasource/cloudwatch", BaseURL: "public/app/plugins/datasource/cloudwatch",
FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")), FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")),
Signature: plugins.SignatureStatusInternal, Signature: plugins.SignatureStatusInternal,
Class: plugins.ClassCore, Class: plugins.ClassCore,
@ -133,8 +132,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Version: "1.0.0", Version: "1.0.0",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -146,8 +145,8 @@ func TestLoader_Load(t *testing.T) {
Backend: true, Backend: true,
State: "alpha", State: "alpha",
}, },
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/")),
Signature: "valid", Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -172,8 +171,8 @@ func TestLoader_Load(t *testing.T) {
URL: "http://test.com", URL: "http://test.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/test-app/img/logo_small.png", Small: "public/plugins/test-app/img/logo_small.png",
Large: "/public/plugins/test-app/img/logo_large.png", Large: "public/plugins/test-app/img/logo_large.png",
}, },
Links: []plugins.InfoLink{ Links: []plugins.InfoLink{
{Name: "Project site", URL: "http://project.com"}, {Name: "Project site", URL: "http://project.com"},
@ -181,8 +180,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Description: "Official Grafana Test App & Dashboard bundle", Description: "Official Grafana Test App & Dashboard bundle",
Screenshots: []plugins.Screenshots{ Screenshots: []plugins.Screenshots{
{Path: "/public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"},
{Path: "/public/plugins/test-app/img/screenshot2.png", Name: "img2"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"},
}, },
Version: "1.0.0", Version: "1.0.0",
Updated: "2015-02-10", Updated: "2015-02-10",
@ -223,8 +222,8 @@ func TestLoader_Load(t *testing.T) {
}, },
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/includes-symlinks")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/includes-symlinks")),
Signature: "valid", Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -251,8 +250,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -264,8 +263,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")),
Signature: "unsigned", Signature: "unsigned",
}, },
@ -298,8 +297,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -311,8 +310,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")),
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
}, },
@ -381,8 +380,8 @@ func TestLoader_Load(t *testing.T) {
{Name: "License & Terms", URL: "http://license.com"}, {Name: "License & Terms", URL: "http://license.com"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-app.svg", Small: "public/img/icn-app.svg",
Large: "/public/img/icn-app.svg", Large: "public/img/icn-app.svg",
}, },
Updated: "2015-02-10", Updated: "2015-02-10",
}, },
@ -401,8 +400,8 @@ func TestLoader_Load(t *testing.T) {
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/test-app-with-includes")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/test-app-with-includes")),
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
}, },
}, },
}, },
@ -427,8 +426,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/grafana/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/grafana/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -440,8 +439,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/grafana/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/grafana/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")),
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
}, },

View File

@ -33,7 +33,7 @@ func DefaultDecorateFuncs(cfg *config.Cfg) []DecorateFunc {
return []DecorateFunc{ return []DecorateFunc{
AppDefaultNavURLDecorateFunc, AppDefaultNavURLDecorateFunc,
TemplateDecorateFunc, TemplateDecorateFunc,
AppChildDecorateFunc(cfg), AppChildDecorateFunc(),
SkipHostEnvVarsDecorateFunc(cfg), SkipHostEnvVarsDecorateFunc(cfg),
} }
} }
@ -133,27 +133,28 @@ func setDefaultNavURL(p *plugins.Plugin) {
} }
// AppChildDecorateFunc is a DecorateFunc that configures child plugins of app plugins. // AppChildDecorateFunc is a DecorateFunc that configures child plugins of app plugins.
func AppChildDecorateFunc(cfg *config.Cfg) DecorateFunc { func AppChildDecorateFunc() DecorateFunc {
return func(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) { return func(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if p.Parent != nil && p.Parent.IsApp() { if p.Parent != nil && p.Parent.IsApp() {
configureAppChildPlugin(cfg, p.Parent, p) configureAppChildPlugin(p.Parent, p)
} }
return p, nil return p, nil
} }
} }
func configureAppChildPlugin(cfg *config.Cfg, parent *plugins.Plugin, child *plugins.Plugin) { func configureAppChildPlugin(parent *plugins.Plugin, child *plugins.Plugin) {
if !parent.IsApp() { if !parent.IsApp() {
return return
} }
child.IncludedInAppID = parent.ID child.IncludedInAppID = parent.ID
child.BaseURL = parent.BaseURL child.BaseURL = parent.BaseURL
// TODO move this logic within assetpath package
appSubPath := strings.ReplaceAll(strings.Replace(child.FS.Base(), parent.FS.Base(), "", 1), "\\", "/") appSubPath := strings.ReplaceAll(strings.Replace(child.FS.Base(), parent.FS.Base(), "", 1), "\\", "/")
if parent.IsCorePlugin() { if parent.IsCorePlugin() {
child.Module = path.Join("core:plugin", parent.ID, appSubPath) child.Module = path.Join("core:plugin", parent.ID, appSubPath)
} else { } else {
child.Module = path.Join("/", cfg.GrafanaAppSubURL, "/public/plugins", parent.ID, appSubPath, "module.js") child.Module = path.Join("public/plugins", parent.ID, appSubPath, "module.js")
} }
} }

View File

@ -108,25 +108,17 @@ func Test_configureAppChildPlugin(t *testing.T) {
}, },
Class: plugins.ClassCore, Class: plugins.ClassCore,
FS: fakes.NewFakePluginFiles("c:\\grafana\\public\\app\\plugins\\app\\testdata-app"), FS: fakes.NewFakePluginFiles("c:\\grafana\\public\\app\\plugins\\app\\testdata-app"),
BaseURL: "/public/app/plugins/app/testdata-app", BaseURL: "public/app/plugins/app/testdata-app",
} }
configureAppChildPlugin(&config.Cfg{}, parent, child) configureAppChildPlugin(parent, child)
require.Equal(t, "core:plugin/testdata-app/datasources/datasource", child.Module) require.Equal(t, "core:plugin/testdata-app/datasources/datasource", child.Module)
require.Equal(t, "testdata-app", child.IncludedInAppID) require.Equal(t, "testdata-app", child.IncludedInAppID)
require.Equal(t, "/public/app/plugins/app/testdata-app", child.BaseURL) require.Equal(t, "public/app/plugins/app/testdata-app", child.BaseURL)
t.Run("App sub URL has no effect on Core plugins", func(t *testing.T) {
configureAppChildPlugin(&config.Cfg{GrafanaAppSubURL: "/grafana"}, parent, child)
require.Equal(t, "core:plugin/testdata-app/datasources/datasource", child.Module)
require.Equal(t, "testdata-app", child.IncludedInAppID)
require.Equal(t, "/public/app/plugins/app/testdata-app", child.BaseURL)
})
}) })
t.Run("When setting paths based on external plugin with app sub URL", func(t *testing.T) { t.Run("When setting paths based on external plugin", func(t *testing.T) {
child := &plugins.Plugin{ child := &plugins.Plugin{
FS: fakes.NewFakePluginFiles("/plugins/parent-app/child-panel"), FS: fakes.NewFakePluginFiles("/plugins/parent-app/child-panel"),
} }
@ -137,14 +129,14 @@ func Test_configureAppChildPlugin(t *testing.T) {
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
FS: fakes.NewFakePluginFiles("/plugins/parent-app"), FS: fakes.NewFakePluginFiles("/plugins/parent-app"),
BaseURL: "/grafana/plugins/parent-app", BaseURL: "plugins/parent-app",
} }
configureAppChildPlugin(&config.Cfg{GrafanaAppSubURL: "/grafana"}, parent, child) configureAppChildPlugin(parent, child)
require.Equal(t, "/grafana/public/plugins/testdata-app/child-panel/module.js", child.Module) require.Equal(t, "public/plugins/testdata-app/child-panel/module.js", child.Module)
require.Equal(t, "testdata-app", child.IncludedInAppID) require.Equal(t, "testdata-app", child.IncludedInAppID)
require.Equal(t, "/grafana/plugins/parent-app", child.BaseURL) require.Equal(t, "plugins/parent-app", child.BaseURL)
}) })
} }

View File

@ -83,8 +83,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Description: "Data source for Amazon AWS monitoring service", Description: "Data source for Amazon AWS monitoring service",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", Small: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Large: "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", Large: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
}, },
}, },
Includes: []*plugins.Includes{ Includes: []*plugins.Includes{
@ -106,9 +106,8 @@ func TestLoader_Load(t *testing.T) {
Backend: true, Backend: true,
QueryOptions: map[string]bool{"minInterval": true}, QueryOptions: map[string]bool{"minInterval": true},
}, },
Module: "core:plugin/cloudwatch", Module: "core:plugin/cloudwatch",
BaseURL: "/public/app/plugins/datasource/cloudwatch", BaseURL: "public/app/plugins/datasource/cloudwatch",
FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir(t), "app/plugins/datasource/cloudwatch")), FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir(t), "app/plugins/datasource/cloudwatch")),
Signature: plugins.SignatureStatusInternal, Signature: plugins.SignatureStatusInternal,
Class: plugins.ClassCore, Class: plugins.ClassCore,
@ -133,8 +132,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Version: "1.0.0", Version: "1.0.0",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -146,8 +145,8 @@ func TestLoader_Load(t *testing.T) {
Backend: true, Backend: true,
State: "alpha", State: "alpha",
}, },
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "valid-v2-signature/plugin/")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "valid-v2-signature/plugin/")),
Signature: "valid", Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -172,8 +171,8 @@ func TestLoader_Load(t *testing.T) {
URL: "http://test.com", URL: "http://test.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/test-app/img/logo_small.png", Small: "public/plugins/test-app/img/logo_small.png",
Large: "/public/plugins/test-app/img/logo_large.png", Large: "public/plugins/test-app/img/logo_large.png",
}, },
Links: []plugins.InfoLink{ Links: []plugins.InfoLink{
{Name: "Project site", URL: "http://project.com"}, {Name: "Project site", URL: "http://project.com"},
@ -181,8 +180,8 @@ func TestLoader_Load(t *testing.T) {
}, },
Description: "Official Grafana Test App & Dashboard bundle", Description: "Official Grafana Test App & Dashboard bundle",
Screenshots: []plugins.Screenshots{ Screenshots: []plugins.Screenshots{
{Path: "/public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"},
{Path: "/public/plugins/test-app/img/screenshot2.png", Name: "img2"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"},
}, },
Version: "1.0.0", Version: "1.0.0",
Updated: "2015-02-10", Updated: "2015-02-10",
@ -223,8 +222,8 @@ func TestLoader_Load(t *testing.T) {
}, },
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "includes-symlinks")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "includes-symlinks")),
Signature: "valid", Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -251,8 +250,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -264,8 +263,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")),
Signature: "unsigned", Signature: "unsigned",
}, },
@ -303,8 +302,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -316,8 +315,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")),
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
}, },
@ -409,8 +408,8 @@ func TestLoader_Load(t *testing.T) {
{Name: "License & Terms", URL: "http://license.com"}, {Name: "License & Terms", URL: "http://license.com"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-app.svg", Small: "public/img/icn-app.svg",
Large: "/public/img/icn-app.svg", Large: "public/img/icn-app.svg",
}, },
Updated: "2015-02-10", Updated: "2015-02-10",
}, },
@ -429,8 +428,8 @@ func TestLoader_Load(t *testing.T) {
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "test-app-with-includes")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "test-app-with-includes")),
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
}, },
}, },
}, },
@ -455,8 +454,8 @@ func TestLoader_Load(t *testing.T) {
URL: "https://grafana.com", URL: "https://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/grafana/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/grafana/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
}, },
@ -468,8 +467,8 @@ func TestLoader_Load(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/grafana/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/grafana/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "unsigned-datasource/plugin")),
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
}, },
@ -526,8 +525,8 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
}, },
Version: "1.0.0", Version: "1.0.0",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/grafana-test-datasource/img/ds.svg", Small: "public/plugins/grafana-test-datasource/img/ds.svg",
Large: "/public/plugins/grafana-test-datasource/img/ds.svg", Large: "public/plugins/grafana-test-datasource/img/ds.svg",
}, },
Updated: "2023-08-03", Updated: "2023-08-03",
Screenshots: []plugins.Screenshots{}, Screenshots: []plugins.Screenshots{},
@ -557,8 +556,8 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
FS: mustNewStaticFSForTests(t, pluginPaths[0]), FS: mustNewStaticFSForTests(t, pluginPaths[0]),
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
Module: "/public/plugins/grafana-test-datasource/module.js", Module: "public/plugins/grafana-test-datasource/module.js",
BaseURL: "/public/plugins/grafana-test-datasource", BaseURL: "public/plugins/grafana-test-datasource",
ExternalService: &auth.ExternalService{ ExternalService: &auth.ExternalService{
ClientID: "client-id", ClientID: "client-id",
ClientSecret: "secretz", ClientSecret: "secretz",
@ -628,8 +627,8 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
}, },
Version: "1.0.0", Version: "1.0.0",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/grafana-test-datasource/img/ds.svg", Small: "public/plugins/grafana-test-datasource/img/ds.svg",
Large: "/public/plugins/grafana-test-datasource/img/ds.svg", Large: "public/plugins/grafana-test-datasource/img/ds.svg",
}, },
Updated: "2023-08-03", Updated: "2023-08-03",
Screenshots: []plugins.Screenshots{}, Screenshots: []plugins.Screenshots{},
@ -650,8 +649,8 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
FS: mustNewStaticFSForTests(t, pluginPaths[0]), FS: mustNewStaticFSForTests(t, pluginPaths[0]),
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Signature: plugins.SignatureStatusUnsigned, Signature: plugins.SignatureStatusUnsigned,
Module: "/public/plugins/grafana-test-datasource/module.js", Module: "public/plugins/grafana-test-datasource/module.js",
BaseURL: "/public/plugins/grafana-test-datasource", BaseURL: "public/plugins/grafana-test-datasource",
ExternalService: &auth.ExternalService{ ExternalService: &auth.ExternalService{
ClientID: "client-id", ClientID: "client-id",
ClientSecret: "secretz", ClientSecret: "secretz",
@ -808,8 +807,8 @@ func TestLoader_Load_MultiplePlugins(t *testing.T) {
URL: "https://willbrowne.com", URL: "https://willbrowne.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Test", Description: "Test",
Version: "1.0.0", Version: "1.0.0",
@ -823,8 +822,8 @@ func TestLoader_Load_MultiplePlugins(t *testing.T) {
State: plugins.ReleaseStateAlpha, State: plugins.ReleaseStateAlpha,
}, },
Class: plugins.ClassExternal, Class: plugins.ClassExternal,
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "valid-v2-pvt-signature/plugin")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "valid-v2-pvt-signature/plugin")),
Signature: "valid", Signature: "valid",
SignatureType: plugins.SignatureTypePrivate, SignatureType: plugins.SignatureTypePrivate,
@ -904,8 +903,8 @@ func TestLoader_Load_RBACReady(t *testing.T) {
Version: "1.0.0", Version: "1.0.0",
Links: []plugins.InfoLink{}, Links: []plugins.InfoLink{},
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-app.svg", Small: "public/img/icn-app.svg",
Large: "/public/img/icn-app.svg", Large: "public/img/icn-app.svg",
}, },
Updated: "2015-02-10", Updated: "2015-02-10",
}, },
@ -936,8 +935,8 @@ func TestLoader_Load_RBACReady(t *testing.T) {
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypePrivate, SignatureType: plugins.SignatureTypePrivate,
SignatureOrg: "gabrielmabille", SignatureOrg: "gabrielmabille",
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
}, },
}, },
}, },
@ -981,8 +980,8 @@ func TestLoader_Load_Signature_RootURL(t *testing.T) {
Author: plugins.InfoLink{Name: "Will Browne", URL: "https://willbrowne.com"}, Author: plugins.InfoLink{Name: "Will Browne", URL: "https://willbrowne.com"},
Description: "Test", Description: "Test",
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Version: "1.0.0", Version: "1.0.0",
}, },
@ -996,8 +995,8 @@ func TestLoader_Load_Signature_RootURL(t *testing.T) {
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypePrivate, SignatureType: plugins.SignatureTypePrivate,
SignatureOrg: "Will Browne", SignatureOrg: "Will Browne",
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
}, },
} }
@ -1043,12 +1042,12 @@ func TestLoader_Load_DuplicatePlugins(t *testing.T) {
{Name: "License & Terms", URL: "http://license.com"}, {Name: "License & Terms", URL: "http://license.com"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/test-app/img/logo_small.png", Small: "public/plugins/test-app/img/logo_small.png",
Large: "/public/plugins/test-app/img/logo_large.png", Large: "public/plugins/test-app/img/logo_large.png",
}, },
Screenshots: []plugins.Screenshots{ Screenshots: []plugins.Screenshots{
{Path: "/public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"},
{Path: "/public/plugins/test-app/img/screenshot2.png", Name: "img2"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"},
}, },
Updated: "2015-02-10", Updated: "2015-02-10",
}, },
@ -1072,8 +1071,8 @@ func TestLoader_Load_DuplicatePlugins(t *testing.T) {
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
SignatureOrg: "Grafana Labs", SignatureOrg: "Grafana Labs",
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
}, },
} }
@ -1123,12 +1122,12 @@ func TestLoader_Load_SkipUninitializedPlugins(t *testing.T) {
{Name: "License & Terms", URL: "http://license.com"}, {Name: "License & Terms", URL: "http://license.com"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/test-app/img/logo_small.png", Small: "public/plugins/test-app/img/logo_small.png",
Large: "/public/plugins/test-app/img/logo_large.png", Large: "public/plugins/test-app/img/logo_large.png",
}, },
Screenshots: []plugins.Screenshots{ Screenshots: []plugins.Screenshots{
{Path: "/public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"},
{Path: "/public/plugins/test-app/img/screenshot2.png", Name: "img2"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"},
}, },
Updated: "2015-02-10", Updated: "2015-02-10",
}, },
@ -1152,8 +1151,8 @@ func TestLoader_Load_SkipUninitializedPlugins(t *testing.T) {
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
SignatureOrg: "Grafana Labs", SignatureOrg: "Grafana Labs",
Module: "/public/plugins/test-app/module.js", Module: "public/plugins/test-app/module.js",
BaseURL: "/public/plugins/test-app", BaseURL: "public/plugins/test-app",
}, },
} }
@ -1345,8 +1344,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
URL: "http://grafana.com", URL: "http://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-datasource.svg", Small: "public/img/icn-datasource.svg",
Large: "/public/img/icn-datasource.svg", Large: "public/img/icn-datasource.svg",
}, },
Description: "Parent plugin", Description: "Parent plugin",
Version: "1.0.0", Version: "1.0.0",
@ -1358,8 +1357,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
}, },
Backend: true, Backend: true,
}, },
Module: "/public/plugins/test-datasource/module.js", Module: "public/plugins/test-datasource/module.js",
BaseURL: "/public/plugins/test-datasource", BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "nested-plugins/parent")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "nested-plugins/parent")),
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -1378,8 +1377,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
URL: "http://grafana.com", URL: "http://grafana.com",
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/img/icn-panel.svg", Small: "public/img/icn-panel.svg",
Large: "/public/img/icn-panel.svg", Large: "public/img/icn-panel.svg",
}, },
Description: "Child plugin", Description: "Child plugin",
Version: "1.0.1", Version: "1.0.1",
@ -1390,8 +1389,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
Plugins: []plugins.Dependency{}, Plugins: []plugins.Dependency{},
}, },
}, },
Module: "/public/plugins/test-panel/module.js", Module: "public/plugins/test-panel/module.js",
BaseURL: "/public/plugins/test-panel", BaseURL: "public/plugins/test-panel",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "nested-plugins/parent/nested")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "nested-plugins/parent/nested")),
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
SignatureType: plugins.SignatureTypeGrafana, SignatureType: plugins.SignatureTypeGrafana,
@ -1470,8 +1469,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
{Name: "License", URL: "https://github.com/grafana/grafana-starter-app/blob/master/LICENSE"}, {Name: "License", URL: "https://github.com/grafana/grafana-starter-app/blob/master/LICENSE"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/myorgid-simple-app/img/logo.svg", Small: "public/plugins/myorgid-simple-app/img/logo.svg",
Large: "/public/plugins/myorgid-simple-app/img/logo.svg", Large: "public/plugins/myorgid-simple-app/img/logo.svg",
}, },
Screenshots: []plugins.Screenshots{}, Screenshots: []plugins.Screenshots{},
Description: "Grafana App Plugin Template", Description: "Grafana App Plugin Template",
@ -1526,8 +1525,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
}, },
Backend: false, Backend: false,
}, },
Module: "/public/plugins/myorgid-simple-app/module.js", Module: "public/plugins/myorgid-simple-app/module.js",
BaseURL: "/public/plugins/myorgid-simple-app", BaseURL: "public/plugins/myorgid-simple-app",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "app-with-child/dist")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "app-with-child/dist")),
DefaultNavURL: "/plugins/myorgid-simple-app/page/root-page-react", DefaultNavURL: "/plugins/myorgid-simple-app/page/root-page-react",
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,
@ -1550,8 +1549,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
{Name: "License", URL: "https://github.com/grafana/grafana-starter-panel/blob/master/LICENSE"}, {Name: "License", URL: "https://github.com/grafana/grafana-starter-panel/blob/master/LICENSE"},
}, },
Logos: plugins.Logos{ Logos: plugins.Logos{
Small: "/public/plugins/myorgid-simple-panel/img/logo.svg", Small: "public/plugins/myorgid-simple-panel/img/logo.svg",
Large: "/public/plugins/myorgid-simple-panel/img/logo.svg", Large: "public/plugins/myorgid-simple-panel/img/logo.svg",
}, },
Screenshots: []plugins.Screenshots{}, Screenshots: []plugins.Screenshots{},
Description: "Grafana Panel Plugin Template", Description: "Grafana Panel Plugin Template",
@ -1564,8 +1563,8 @@ func TestLoader_Load_NestedPlugins(t *testing.T) {
Plugins: []plugins.Dependency{}, Plugins: []plugins.Dependency{},
}, },
}, },
Module: "/public/plugins/myorgid-simple-app/child/module.js", Module: "public/plugins/myorgid-simple-app/child/module.js",
BaseURL: "/public/plugins/myorgid-simple-app", BaseURL: "public/plugins/myorgid-simple-app",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "app-with-child/dist/child")), FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "app-with-child/dist/child")),
IncludedInAppID: parent.ID, IncludedInAppID: parent.ID,
Signature: plugins.SignatureStatusValid, Signature: plugins.SignatureStatusValid,

View File

@ -13,8 +13,8 @@
"description": "Shows list of alerts and their current status", "description": "Shows list of alerts and their current status",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/alertlist/img/icn-singlestat-panel.svg", "small": "public/app/plugins/panel/alertlist/img/icn-singlestat-panel.svg",
"large": "/public/app/plugins/panel/alertlist/img/icn-singlestat-panel.svg" "large": "public/app/plugins/panel/alertlist/img/icn-singlestat-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -55,8 +55,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/alertmanager/img/logo.svg", "small": "public/app/plugins/datasource/alertmanager/img/logo.svg",
"large": "/public/app/plugins/datasource/alertmanager/img/logo.svg" "large": "public/app/plugins/datasource/alertmanager/img/logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -92,8 +92,8 @@
"description": "List annotations", "description": "List annotations",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/annolist/img/icn-annolist-panel.svg", "small": "public/app/plugins/panel/annolist/img/icn-annolist-panel.svg",
"large": "/public/app/plugins/panel/annolist/img/icn-annolist-panel.svg" "large": "public/app/plugins/panel/annolist/img/icn-annolist-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -138,22 +138,22 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/azuremonitor/img/logo.jpg", "small": "public/app/plugins/datasource/azuremonitor/img/logo.jpg",
"large": "/public/app/plugins/datasource/azuremonitor/img/logo.jpg" "large": "public/app/plugins/datasource/azuremonitor/img/logo.jpg"
}, },
"build": {}, "build": {},
"screenshots": [ "screenshots": [
{ {
"name": "Azure Contoso Loans", "name": "Azure Contoso Loans",
"path": "/public/app/plugins/datasource/azuremonitor/img/contoso_loans_grafana_dashboard.png" "path": "public/app/plugins/datasource/azuremonitor/img/contoso_loans_grafana_dashboard.png"
}, },
{ {
"name": "Azure Monitor Network", "name": "Azure Monitor Network",
"path": "/public/app/plugins/datasource/azuremonitor/img/azure_monitor_network.png" "path": "public/app/plugins/datasource/azuremonitor/img/azure_monitor_network.png"
}, },
{ {
"name": "Azure Monitor CPU", "name": "Azure Monitor CPU",
"path": "/public/app/plugins/datasource/azuremonitor/img/azure_monitor_cpu.png" "path": "public/app/plugins/datasource/azuremonitor/img/azure_monitor_cpu.png"
} }
], ],
"version": "", "version": "",
@ -188,8 +188,8 @@
"description": "Categorical charts with group support", "description": "Categorical charts with group support",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/barchart/img/barchart.svg", "small": "public/app/plugins/panel/barchart/img/barchart.svg",
"large": "/public/app/plugins/panel/barchart/img/barchart.svg" "large": "public/app/plugins/panel/barchart/img/barchart.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -225,8 +225,8 @@
"description": "Horizontal and vertical gauges", "description": "Horizontal and vertical gauges",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/bargauge/img/icon_bar_gauge.svg", "small": "public/app/plugins/panel/bargauge/img/icon_bar_gauge.svg",
"large": "/public/app/plugins/panel/bargauge/img/icon_bar_gauge.svg" "large": "public/app/plugins/panel/bargauge/img/icon_bar_gauge.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -262,8 +262,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/candlestick/img/candlestick.svg", "small": "public/app/plugins/panel/candlestick/img/candlestick.svg",
"large": "/public/app/plugins/panel/candlestick/img/candlestick.svg" "large": "public/app/plugins/panel/candlestick/img/candlestick.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -299,8 +299,8 @@
"description": "Explicit element placement", "description": "Explicit element placement",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/canvas/img/icn-canvas.svg", "small": "public/app/plugins/panel/canvas/img/icn-canvas.svg",
"large": "/public/app/plugins/panel/canvas/img/icn-canvas.svg" "large": "public/app/plugins/panel/canvas/img/icn-canvas.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -336,8 +336,8 @@
"description": "Data source for Amazon AWS monitoring service", "description": "Data source for Amazon AWS monitoring service",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png", "small": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"large": "/public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png" "large": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -373,8 +373,8 @@
"description": "List of dynamic links to other dashboards", "description": "List of dynamic links to other dashboards",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/dashlist/img/icn-dashlist-panel.svg", "small": "public/app/plugins/panel/dashlist/img/icn-dashlist-panel.svg",
"large": "/public/app/plugins/panel/dashlist/img/icn-dashlist-panel.svg" "large": "public/app/plugins/panel/dashlist/img/icn-dashlist-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -410,8 +410,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/datagrid/img/icn-table-panel.svg", "small": "public/app/plugins/panel/datagrid/img/icn-table-panel.svg",
"large": "/public/app/plugins/panel/datagrid/img/icn-table-panel.svg" "large": "public/app/plugins/panel/datagrid/img/icn-table-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -452,8 +452,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg", "small": "public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg",
"large": "/public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg" "large": "public/app/plugins/datasource/elasticsearch/img/elasticsearch.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -489,8 +489,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/flamegraph/img/icn-flamegraph.svg", "small": "public/app/plugins/panel/flamegraph/img/icn-flamegraph.svg",
"large": "/public/app/plugins/panel/flamegraph/img/icn-flamegraph.svg" "large": "public/app/plugins/panel/flamegraph/img/icn-flamegraph.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -526,8 +526,8 @@
"description": "Standard gauge visualization", "description": "Standard gauge visualization",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/gauge/img/icon_gauge.svg", "small": "public/app/plugins/panel/gauge/img/icon_gauge.svg",
"large": "/public/app/plugins/panel/gauge/img/icon_gauge.svg" "large": "public/app/plugins/panel/gauge/img/icon_gauge.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -563,8 +563,8 @@
"description": "Geomap panel", "description": "Geomap panel",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/geomap/img/icn-geomap.svg", "small": "public/app/plugins/panel/geomap/img/icn-geomap.svg",
"large": "/public/app/plugins/panel/geomap/img/icn-geomap.svg" "large": "public/app/plugins/panel/geomap/img/icn-geomap.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -600,8 +600,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/gettingstarted/img/icn-dashlist-panel.svg", "small": "public/app/plugins/panel/gettingstarted/img/icn-dashlist-panel.svg",
"large": "/public/app/plugins/panel/gettingstarted/img/icn-dashlist-panel.svg" "large": "public/app/plugins/panel/gettingstarted/img/icn-dashlist-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -637,8 +637,8 @@
"description": "Data source for Google's monitoring service (formerly named Stackdriver)", "description": "Data source for Google's monitoring service (formerly named Stackdriver)",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/cloud-monitoring/img/cloud_monitoring_logo.svg", "small": "public/app/plugins/datasource/cloud-monitoring/img/cloud_monitoring_logo.svg",
"large": "/public/app/plugins/datasource/cloud-monitoring/img/cloud_monitoring_logo.svg" "large": "public/app/plugins/datasource/cloud-monitoring/img/cloud_monitoring_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -679,8 +679,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/grafana-pyroscope-datasource/img/grafana_pyroscope_icon.svg", "small": "public/app/plugins/datasource/grafana-pyroscope-datasource/img/grafana_pyroscope_icon.svg",
"large": "/public/app/plugins/datasource/grafana-pyroscope-datasource/img/grafana_pyroscope_icon.svg" "large": "public/app/plugins/datasource/grafana-pyroscope-datasource/img/grafana_pyroscope_icon.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -716,8 +716,8 @@
"description": "The old default graph panel", "description": "The old default graph panel",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/graph/img/icn-graph-panel.svg", "small": "public/app/plugins/panel/graph/img/icn-graph-panel.svg",
"large": "/public/app/plugins/panel/graph/img/icn-graph-panel.svg" "large": "public/app/plugins/panel/graph/img/icn-graph-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -762,8 +762,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/graphite/img/graphite_logo.png", "small": "public/app/plugins/datasource/graphite/img/graphite_logo.png",
"large": "/public/app/plugins/datasource/graphite/img/graphite_logo.png" "large": "public/app/plugins/datasource/graphite/img/graphite_logo.png"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -799,8 +799,8 @@
"description": "Like a histogram over time", "description": "Like a histogram over time",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/heatmap/img/icn-heatmap-panel.svg", "small": "public/app/plugins/panel/heatmap/img/icn-heatmap-panel.svg",
"large": "/public/app/plugins/panel/heatmap/img/icn-heatmap-panel.svg" "large": "public/app/plugins/panel/heatmap/img/icn-heatmap-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -836,8 +836,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/histogram/img/histogram.svg", "small": "public/app/plugins/panel/histogram/img/histogram.svg",
"large": "/public/app/plugins/panel/histogram/img/histogram.svg" "large": "public/app/plugins/panel/histogram/img/histogram.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -873,8 +873,8 @@
"description": "Open source time series database", "description": "Open source time series database",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/influxdb/img/influxdb_logo.svg", "small": "public/app/plugins/datasource/influxdb/img/influxdb_logo.svg",
"large": "/public/app/plugins/datasource/influxdb/img/influxdb_logo.svg" "large": "public/app/plugins/datasource/influxdb/img/influxdb_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -919,8 +919,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/jaeger/img/jaeger_logo.svg", "small": "public/app/plugins/datasource/jaeger/img/jaeger_logo.svg",
"large": "/public/app/plugins/datasource/jaeger/img/jaeger_logo.svg" "large": "public/app/plugins/datasource/jaeger/img/jaeger_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -956,8 +956,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/logs/img/icn-logs-panel.svg", "small": "public/app/plugins/panel/logs/img/icn-logs-panel.svg",
"large": "/public/app/plugins/panel/logs/img/icn-logs-panel.svg" "large": "public/app/plugins/panel/logs/img/icn-logs-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1002,8 +1002,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/loki/img/loki_icon.svg", "small": "public/app/plugins/datasource/loki/img/loki_icon.svg",
"large": "/public/app/plugins/datasource/loki/img/loki_icon.svg" "large": "public/app/plugins/datasource/loki/img/loki_icon.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1039,8 +1039,8 @@
"description": "Data source for Microsoft SQL Server compatible databases", "description": "Data source for Microsoft SQL Server compatible databases",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/mssql/img/sql_server_logo.svg", "small": "public/app/plugins/datasource/mssql/img/sql_server_logo.svg",
"large": "/public/app/plugins/datasource/mssql/img/sql_server_logo.svg" "large": "public/app/plugins/datasource/mssql/img/sql_server_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1076,8 +1076,8 @@
"description": "Data source for MySQL databases", "description": "Data source for MySQL databases",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/mysql/img/mysql_logo.svg", "small": "public/app/plugins/datasource/mysql/img/mysql_logo.svg",
"large": "/public/app/plugins/datasource/mysql/img/mysql_logo.svg" "large": "public/app/plugins/datasource/mysql/img/mysql_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1113,8 +1113,8 @@
"description": "RSS feed reader", "description": "RSS feed reader",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/news/img/news.svg", "small": "public/app/plugins/panel/news/img/news.svg",
"large": "/public/app/plugins/panel/news/img/news.svg" "large": "public/app/plugins/panel/news/img/news.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1150,8 +1150,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/nodeGraph/img/icn-node-graph.svg", "small": "public/app/plugins/panel/nodeGraph/img/icn-node-graph.svg",
"large": "/public/app/plugins/panel/nodeGraph/img/icn-node-graph.svg" "large": "public/app/plugins/panel/nodeGraph/img/icn-node-graph.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1187,8 +1187,8 @@
"description": "Open source time series database", "description": "Open source time series database",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/opentsdb/img/opentsdb_logo.png", "small": "public/app/plugins/datasource/opentsdb/img/opentsdb_logo.png",
"large": "/public/app/plugins/datasource/opentsdb/img/opentsdb_logo.png" "large": "public/app/plugins/datasource/opentsdb/img/opentsdb_logo.png"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1229,8 +1229,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/parca/img/logo-small.svg", "small": "public/app/plugins/datasource/parca/img/logo-small.svg",
"large": "/public/app/plugins/datasource/parca/img/logo-small.svg" "large": "public/app/plugins/datasource/parca/img/logo-small.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1266,8 +1266,8 @@
"description": "The new core pie chart visualization", "description": "The new core pie chart visualization",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/piechart/img/icon_piechart.svg", "small": "public/app/plugins/panel/piechart/img/icon_piechart.svg",
"large": "/public/app/plugins/panel/piechart/img/icon_piechart.svg" "large": "public/app/plugins/panel/piechart/img/icon_piechart.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1303,8 +1303,8 @@
"description": "Data source for PostgreSQL and compatible databases", "description": "Data source for PostgreSQL and compatible databases",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/grafana-postgresql-datasource/img/postgresql_logo.svg", "small": "public/app/plugins/datasource/grafana-postgresql-datasource/img/postgresql_logo.svg",
"large": "/public/app/plugins/datasource/grafana-postgresql-datasource/img/postgresql_logo.svg" "large": "public/app/plugins/datasource/grafana-postgresql-datasource/img/postgresql_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1345,8 +1345,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/prometheus/img/prometheus_logo.svg", "small": "public/app/plugins/datasource/prometheus/img/prometheus_logo.svg",
"large": "/public/app/plugins/datasource/prometheus/img/prometheus_logo.svg" "large": "public/app/plugins/datasource/prometheus/img/prometheus_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1382,8 +1382,8 @@
"description": "Big stat values \u0026 sparklines", "description": "Big stat values \u0026 sparklines",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/stat/img/icn-singlestat-panel.svg", "small": "public/app/plugins/panel/stat/img/icn-singlestat-panel.svg",
"large": "/public/app/plugins/panel/stat/img/icn-singlestat-panel.svg" "large": "public/app/plugins/panel/stat/img/icn-singlestat-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1419,8 +1419,8 @@
"description": "State changes and durations", "description": "State changes and durations",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/state-timeline/img/timeline.svg", "small": "public/app/plugins/panel/state-timeline/img/timeline.svg",
"large": "/public/app/plugins/panel/state-timeline/img/timeline.svg" "large": "public/app/plugins/panel/state-timeline/img/timeline.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1456,8 +1456,8 @@
"description": "Periodic status history", "description": "Periodic status history",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/status-history/img/status.svg", "small": "public/app/plugins/panel/status-history/img/status.svg",
"large": "/public/app/plugins/panel/status-history/img/status.svg" "large": "public/app/plugins/panel/status-history/img/status.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1493,8 +1493,8 @@
"description": "Supports many column styles", "description": "Supports many column styles",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/table/img/icn-table-panel.svg", "small": "public/app/plugins/panel/table/img/icn-table-panel.svg",
"large": "/public/app/plugins/panel/table/img/icn-table-panel.svg" "large": "public/app/plugins/panel/table/img/icn-table-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1530,8 +1530,8 @@
"description": "Table Panel for Grafana", "description": "Table Panel for Grafana",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/table-old/img/icn-table-panel.svg", "small": "public/app/plugins/panel/table-old/img/icn-table-panel.svg",
"large": "/public/app/plugins/panel/table-old/img/icn-table-panel.svg" "large": "public/app/plugins/panel/table-old/img/icn-table-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1572,8 +1572,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/tempo/img/tempo_logo.svg", "small": "public/app/plugins/datasource/tempo/img/tempo_logo.svg",
"large": "/public/app/plugins/datasource/tempo/img/tempo_logo.svg" "large": "public/app/plugins/datasource/tempo/img/tempo_logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1609,8 +1609,8 @@
"description": "Generates test data in different forms", "description": "Generates test data in different forms",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/datasource/grafana-testdata-datasource/img/testdata.svg", "small": "public/app/plugins/datasource/grafana-testdata-datasource/img/testdata.svg",
"large": "/public/app/plugins/datasource/grafana-testdata-datasource/img/testdata.svg" "large": "public/app/plugins/datasource/grafana-testdata-datasource/img/testdata.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1646,8 +1646,8 @@
"description": "Supports markdown and html content", "description": "Supports markdown and html content",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/text/img/icn-text-panel.svg", "small": "public/app/plugins/panel/text/img/icn-text-panel.svg",
"large": "/public/app/plugins/panel/text/img/icn-text-panel.svg" "large": "public/app/plugins/panel/text/img/icn-text-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1683,8 +1683,8 @@
"description": "Time based line, area and bar charts", "description": "Time based line, area and bar charts",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/timeseries/img/icn-timeseries-panel.svg", "small": "public/app/plugins/panel/timeseries/img/icn-timeseries-panel.svg",
"large": "/public/app/plugins/panel/timeseries/img/icn-timeseries-panel.svg" "large": "public/app/plugins/panel/timeseries/img/icn-timeseries-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1720,8 +1720,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/traces/img/traces-panel.svg", "small": "public/app/plugins/panel/traces/img/traces-panel.svg",
"large": "/public/app/plugins/panel/traces/img/traces-panel.svg" "large": "public/app/plugins/panel/traces/img/traces-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1757,8 +1757,8 @@
"description": "Like timeseries, but when x != time", "description": "Like timeseries, but when x != time",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/trend/img/trend.svg", "small": "public/app/plugins/panel/trend/img/trend.svg",
"large": "/public/app/plugins/panel/trend/img/trend.svg" "large": "public/app/plugins/panel/trend/img/trend.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1794,8 +1794,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/welcome/img/icn-dashlist-panel.svg", "small": "public/app/plugins/panel/welcome/img/icn-dashlist-panel.svg",
"large": "/public/app/plugins/panel/welcome/img/icn-dashlist-panel.svg" "large": "public/app/plugins/panel/welcome/img/icn-dashlist-panel.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1831,8 +1831,8 @@
"description": "", "description": "",
"links": null, "links": null,
"logos": { "logos": {
"small": "/public/app/plugins/panel/xychart/img/icn-xychart.svg", "small": "public/app/plugins/panel/xychart/img/icn-xychart.svg",
"large": "/public/app/plugins/panel/xychart/img/icn-xychart.svg" "large": "public/app/plugins/panel/xychart/img/icn-xychart.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1873,8 +1873,8 @@
} }
], ],
"logos": { "logos": {
"small": "/public/app/plugins/datasource/zipkin/img/zipkin-logo.svg", "small": "public/app/plugins/datasource/zipkin/img/zipkin-logo.svg",
"large": "/public/app/plugins/datasource/zipkin/img/zipkin-logo.svg" "large": "public/app/plugins/datasource/zipkin/img/zipkin-logo.svg"
}, },
"build": {}, "build": {},
"screenshots": null, "screenshots": null,
@ -1896,4 +1896,4 @@
"signatureOrg": "", "signatureOrg": "",
"angularDetected": false "angularDetected": false
} }
] ]

View File

@ -0,0 +1,31 @@
import { config } from '@grafana/runtime';
import { resolveModulePath } from './utils';
describe('resolveModulePath', () => {
it.each`
value | expected
${'http://localhost:3000/public/plugins/my-app-plugin/module.js'} | ${'http://localhost:3000/public/plugins/my-app-plugin/module.js'}
${'/public/plugins/my-app-plugin/module.js'} | ${'/public/plugins/my-app-plugin/module.js'}
${'public/plugins/my-app-plugin/module.js'} | ${'/public/plugins/my-app-plugin/module.js'}
`(
"Url correct formatting, when calling the rule with correct formatted value: '$value' then result should be '$expected'",
({ value, expected }) => {
expect(resolveModulePath(value)).toBe(expected);
}
);
it.each`
value | expected
${'http://localhost:3000/public/plugins/my-app-plugin/module.js'} | ${'http://localhost:3000/public/plugins/my-app-plugin/module.js'}
${'/public/plugins/my-app-plugin/module.js'} | ${'/public/plugins/my-app-plugin/module.js'}
${'public/plugins/my-app-plugin/module.js'} | ${'/grafana/public/plugins/my-app-plugin/module.js'}
`(
"Url correct formatting, when calling the rule with correct formatted value: '$value' then result should be '$expected'",
({ value, expected }) => {
config.appSubUrl = '/grafana';
expect(resolveModulePath(value)).toBe(expected);
}
);
});

View File

@ -28,3 +28,15 @@ export function buildImportMap(importMap: Record<string, System.Module>) {
export function isHostedOnCDN(path: string) { export function isHostedOnCDN(path: string) {
return Boolean(config.pluginsCDNBaseURL) && path.startsWith(config.pluginsCDNBaseURL); return Boolean(config.pluginsCDNBaseURL) && path.startsWith(config.pluginsCDNBaseURL);
} }
// This function is used to dynamically prepend the appSubUrl in the frontend.
// This is required because if serve_from_sub_path is false the Image Renderer sets the subpath
// to an empty string and sets appurl to localhost which causes plugins to fail to load.
// https://github.com/grafana/grafana/issues/76180
export function resolveModulePath(path: string) {
if (path.startsWith('http') || path.startsWith('/')) {
return path;
}
return `${config.appSubUrl ?? ''}/${path}`;
}

View File

@ -16,7 +16,7 @@ import { registerPluginInCache } from './loader/cache';
import { sharedDependenciesMap } from './loader/sharedDependencies'; import { sharedDependenciesMap } from './loader/sharedDependencies';
import { decorateSystemJSFetch, decorateSystemJSResolve, decorateSystemJsOnload } from './loader/systemjsHooks'; import { decorateSystemJSFetch, decorateSystemJSResolve, decorateSystemJsOnload } from './loader/systemjsHooks';
import { SystemJSWithLoaderHooks } from './loader/types'; import { SystemJSWithLoaderHooks } from './loader/types';
import { buildImportMap } from './loader/utils'; import { buildImportMap, resolveModulePath } from './loader/utils';
import { importPluginModuleInSandbox } from './sandbox/sandbox_plugin_loader'; import { importPluginModuleInSandbox } from './sandbox/sandbox_plugin_loader';
import { isFrontendSandboxSupported } from './sandbox/utils'; import { isFrontendSandboxSupported } from './sandbox/utils';
@ -67,12 +67,14 @@ export async function importPluginModule({
} }
} }
let modulePath = resolveModulePath(path);
// the sandboxing environment code cannot work in nodejs and requires a real browser // the sandboxing environment code cannot work in nodejs and requires a real browser
if (await isFrontendSandboxSupported({ isAngular, pluginId })) { if (await isFrontendSandboxSupported({ isAngular, pluginId })) {
return importPluginModuleInSandbox({ pluginId }); return importPluginModuleInSandbox({ pluginId });
} }
return SystemJS.import(path); return SystemJS.import(modulePath);
} }
export function importDataSourcePlugin(meta: DataSourcePluginMeta): Promise<GenericDataSourcePlugin> { export function importDataSourcePlugin(meta: DataSourcePluginMeta): Promise<GenericDataSourcePlugin> {

View File

@ -2,7 +2,7 @@ import { PluginMeta, patchArrayVectorProrotypeMethods } from '@grafana/data';
import { transformPluginSourceForCDN } from '../cdn/utils'; import { transformPluginSourceForCDN } from '../cdn/utils';
import { resolveWithCache } from '../loader/cache'; import { resolveWithCache } from '../loader/cache';
import { isHostedOnCDN } from '../loader/utils'; import { isHostedOnCDN, resolveModulePath } from '../loader/utils';
import { SandboxEnvironment } from './types'; import { SandboxEnvironment } from './types';
@ -60,9 +60,10 @@ export async function getPluginCode(meta: PluginMeta): Promise<string> {
}); });
return pluginCode; return pluginCode;
} else { } else {
// local plugin. resolveWithCache will append a query parameter with its version let modulePath = resolveModulePath(meta.module);
// to ensure correct cached version is served // resolveWithCache will append a query parameter with its version
const pluginCodeUrl = resolveWithCache(meta.module); // to ensure correct cached version is served for local plugins
const pluginCodeUrl = resolveWithCache(modulePath);
const response = await fetch(pluginCodeUrl); const response = await fetch(pluginCodeUrl);
let pluginCode = await response.text(); let pluginCode = await response.text();
pluginCode = transformPluginSourceForCDN({ pluginCode = transformPluginSourceForCDN({