mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Support for link extensions (#61663)
* added extensions to plugin.json and exposing it via frontend settings. * added extensions to the plugin.json schema. * changing the extensions in frontend settings to a map instead of an array. * wip * feat(pluginregistry): begin wiring up registry * feat(pluginextensions): prevent duplicate links and clean up * added test case for link extensions. * added tests and implemented the getPluginLink function. * wip * feat(pluginextensions): expose plugin extension registry * fix(pluginextensions): appease the typescript gods post rename * renamed file and will throw error if trying to call setExtensionsRegistry if trying to call it twice. * added reafactorings. * fixed failing test. * minor refactorings to make sure we only include extensions if the app is enabled. * fixed some nits. * Update public/app/features/plugins/extensions/registry.test.ts Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update packages/grafana-runtime/src/services/pluginExtensions/registry.ts Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update packages/grafana-runtime/src/services/pluginExtensions/registry.ts Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/registry.test.ts Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Moved types for extensions from data to runtime. * added a small example on how you could consume link extensions. * renamed after feedback from levi. * updated the plugindef.cue. * using the generated plugin def. * added tests for apps and extensions. * fixed linting issues. * wip * wip * wip * wip * test(extensions): fix up failing tests * feat(extensions): freeze registry extension arrays, include type in registry items * added restrictions in the pugindef cue schema. * wip * added required fields. * added key to uniquely identify each item. * test(pluginextensions): align tests with implementation * chore(schema): refresh reference.md --------- Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
@@ -15,20 +16,19 @@ import (
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/plugindef"
|
||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsettings/service"
|
||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsettings"
|
||||
"github.com/grafana/grafana/pkg/services/rendering"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/services/updatechecker"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.FeatureManager) (*web.Mux, *HTTPServer) {
|
||||
func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.FeatureManager, pstore plugins.Store, psettings pluginSettings.Service) (*web.Mux, *HTTPServer) {
|
||||
t.Helper()
|
||||
db.InitTestDB(t)
|
||||
cfg.IsFeatureToggleEnabled = features.IsEnabled
|
||||
@@ -44,8 +44,15 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.
|
||||
})
|
||||
}
|
||||
|
||||
sqlStore := db.InitTestDB(t)
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
var pluginStore = pstore
|
||||
if pluginStore == nil {
|
||||
pluginStore = &plugins.FakePluginStore{}
|
||||
}
|
||||
|
||||
var pluginsSettings = psettings
|
||||
if pluginsSettings == nil {
|
||||
pluginsSettings = &pluginSettings.FakePluginSettings{}
|
||||
}
|
||||
|
||||
hs := &HTTPServer{
|
||||
Cfg: cfg,
|
||||
@@ -55,12 +62,12 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features *featuremgmt.
|
||||
Cfg: cfg,
|
||||
RendererPluginManager: &fakeRendererManager{},
|
||||
},
|
||||
SQLStore: sqlStore,
|
||||
SQLStore: db.InitTestDB(t),
|
||||
SettingsProvider: setting.ProvideProvider(cfg),
|
||||
pluginStore: &plugins.FakePluginStore{},
|
||||
pluginStore: pluginStore,
|
||||
grafanaUpdateChecker: &updatechecker.GrafanaService{},
|
||||
AccessControl: accesscontrolmock.New().WithDisabled(),
|
||||
PluginSettings: pluginSettings.ProvideService(sqlStore, secretsService),
|
||||
PluginSettings: pluginsSettings,
|
||||
pluginsCDNService: pluginscdn.ProvideService(&config.Cfg{
|
||||
PluginsCDNURLTemplate: cfg.PluginsCDNURLTemplate,
|
||||
PluginSettings: cfg.PluginSettings,
|
||||
@@ -91,7 +98,7 @@ func TestHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testing.T) {
|
||||
cfg.BuildVersion = "7.8.9"
|
||||
cfg.BuildCommit = "01234567"
|
||||
|
||||
m, hs := setupTestEnvironment(t, cfg, featuremgmt.WithFeatures())
|
||||
m, hs := setupTestEnvironment(t, cfg, featuremgmt.WithFeatures(), nil, nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/frontend/settings", nil)
|
||||
|
||||
@@ -182,7 +189,7 @@ func TestHTTPServer_GetFrontendSettings_pluginsCDNBaseURL(t *testing.T) {
|
||||
if test.mutateCfg != nil {
|
||||
test.mutateCfg(cfg)
|
||||
}
|
||||
m, _ := setupTestEnvironment(t, cfg, featuremgmt.WithFeatures())
|
||||
m, _ := setupTestEnvironment(t, cfg, featuremgmt.WithFeatures(), nil, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/frontend/settings", nil)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
@@ -195,3 +202,154 @@ func TestHTTPServer_GetFrontendSettings_pluginsCDNBaseURL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
type settings struct {
|
||||
Apps map[string]*plugins.AppDTO `json:"apps"`
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
pluginStore func() plugins.Store
|
||||
pluginSettings func() pluginSettings.Service
|
||||
expected settings
|
||||
}{
|
||||
{
|
||||
desc: "app without extensions",
|
||||
pluginStore: func() plugins.Store {
|
||||
return &plugins.FakePluginStore{
|
||||
PluginList: newPlugins("test-app", nil),
|
||||
}
|
||||
},
|
||||
pluginSettings: func() pluginSettings.Service {
|
||||
return &pluginSettings.FakePluginSettings{
|
||||
Plugins: newAppSettings("test-app", true),
|
||||
}
|
||||
},
|
||||
expected: settings{
|
||||
Apps: map[string]*plugins.AppDTO{
|
||||
"test-app": {
|
||||
ID: "test-app",
|
||||
Preload: false,
|
||||
Path: "/test-app/module.js",
|
||||
Version: "0.5.0",
|
||||
Extensions: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "enabled app with link extensions",
|
||||
pluginStore: func() plugins.Store {
|
||||
return &plugins.FakePluginStore{
|
||||
PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{
|
||||
{
|
||||
Target: "core/home/menu",
|
||||
Type: plugindef.ExtensionsLinkTypeLink,
|
||||
Title: "Title",
|
||||
Description: "Home route of app",
|
||||
Path: "/home",
|
||||
},
|
||||
}),
|
||||
}
|
||||
},
|
||||
pluginSettings: func() pluginSettings.Service {
|
||||
return &pluginSettings.FakePluginSettings{
|
||||
Plugins: newAppSettings("test-app", true),
|
||||
}
|
||||
},
|
||||
expected: settings{
|
||||
Apps: map[string]*plugins.AppDTO{
|
||||
"test-app": {
|
||||
ID: "test-app",
|
||||
Preload: false,
|
||||
Path: "/test-app/module.js",
|
||||
Version: "0.5.0",
|
||||
Extensions: []*plugindef.ExtensionsLink{
|
||||
{
|
||||
Target: "core/home/menu",
|
||||
Type: plugindef.ExtensionsLinkTypeLink,
|
||||
Title: "Title",
|
||||
Description: "Home route of app",
|
||||
Path: "/home",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "disabled app with link extensions",
|
||||
pluginStore: func() plugins.Store {
|
||||
return &plugins.FakePluginStore{
|
||||
PluginList: newPlugins("test-app", []*plugindef.ExtensionsLink{
|
||||
{
|
||||
Target: "core/home/menu",
|
||||
Type: plugindef.ExtensionsLinkTypeLink,
|
||||
Title: "Title",
|
||||
Description: "Home route of app",
|
||||
Path: "/home",
|
||||
},
|
||||
}),
|
||||
}
|
||||
},
|
||||
pluginSettings: func() pluginSettings.Service {
|
||||
return &pluginSettings.FakePluginSettings{
|
||||
Plugins: newAppSettings("test-app", false),
|
||||
}
|
||||
},
|
||||
expected: settings{
|
||||
Apps: map[string]*plugins.AppDTO{
|
||||
"test-app": {
|
||||
ID: "test-app",
|
||||
Preload: false,
|
||||
Path: "/test-app/module.js",
|
||||
Version: "0.5.0",
|
||||
Extensions: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
m, _ := setupTestEnvironment(t, cfg, featuremgmt.WithFeatures(), test.pluginStore(), test.pluginSettings())
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/frontend/settings", nil)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
m.ServeHTTP(recorder, req)
|
||||
var got settings
|
||||
err := json.Unmarshal(recorder.Body.Bytes(), &got)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, recorder.Code)
|
||||
require.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newAppSettings(id string, enabled bool) map[string]*pluginSettings.DTO {
|
||||
return map[string]*pluginSettings.DTO{
|
||||
id: {
|
||||
ID: 0,
|
||||
OrgID: 1,
|
||||
PluginID: id,
|
||||
Enabled: enabled,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newPlugins(id string, extensions []*plugindef.ExtensionsLink) []plugins.PluginDTO {
|
||||
return []plugins.PluginDTO{
|
||||
{
|
||||
Module: fmt.Sprintf("/%s/module.js", id),
|
||||
JSONData: plugins.JSONData{
|
||||
ID: id,
|
||||
Info: plugins.Info{Version: "0.5.0"},
|
||||
Type: plugins.App,
|
||||
Extensions: extensions,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user