mirror of
https://github.com/grafana/grafana.git
synced 2026-09-05 04:40:13 -05: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:
co-authored by
Levente Balogh
Jack Westbrook
parent
8a94688114
commit
1cfd3f81fb
@@ -126,6 +126,7 @@ type FrontendSettingsDTO struct {
|
||||
Datasources map[string]plugins.DataSourceDTO `json:"datasources"`
|
||||
MinRefreshInterval string `json:"minRefreshInterval"`
|
||||
Panels map[string]plugins.PanelDTO `json:"panels"`
|
||||
Apps map[string]*plugins.AppDTO `json:"apps"`
|
||||
AppUrl string `json:"appUrl"`
|
||||
AppSubUrl string `json:"appSubUrl"`
|
||||
AllowOrgCreate bool `json:"allowOrgCreate"`
|
||||
@@ -158,21 +159,20 @@ type FrontendSettingsDTO struct {
|
||||
RudderstackSdkUrl string `json:"rudderstackSdkUrl"`
|
||||
RudderstackConfigUrl string `json:"rudderstackConfigUrl"`
|
||||
|
||||
FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"`
|
||||
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"`
|
||||
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"`
|
||||
DisableLoginForm bool `json:"disableLoginForm"`
|
||||
DisableUserSignUp bool `json:"disableUserSignUp"`
|
||||
LoginHint string `json:"loginHint"`
|
||||
PasswordHint string `json:"passwordHint"`
|
||||
ExternalUserMngInfo string `json:"externalUserMngInfo"`
|
||||
ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"`
|
||||
ExternalUserMngLinkName string `json:"externalUserMngLinkName"`
|
||||
ViewersCanEdit bool `json:"viewersCanEdit"`
|
||||
AngularSupportEnabled bool `json:"angularSupportEnabled"`
|
||||
EditorsCanAdmin bool `json:"editorsCanAdmin"`
|
||||
DisableSanitizeHtml bool `json:"disableSanitizeHtml"`
|
||||
PluginsToPreload []*plugins.PreloadPlugin `json:"pluginsToPreload"`
|
||||
FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"`
|
||||
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"`
|
||||
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"`
|
||||
DisableLoginForm bool `json:"disableLoginForm"`
|
||||
DisableUserSignUp bool `json:"disableUserSignUp"`
|
||||
LoginHint string `json:"loginHint"`
|
||||
PasswordHint string `json:"passwordHint"`
|
||||
ExternalUserMngInfo string `json:"externalUserMngInfo"`
|
||||
ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"`
|
||||
ExternalUserMngLinkName string `json:"externalUserMngLinkName"`
|
||||
ViewersCanEdit bool `json:"viewersCanEdit"`
|
||||
AngularSupportEnabled bool `json:"angularSupportEnabled"`
|
||||
EditorsCanAdmin bool `json:"editorsCanAdmin"`
|
||||
DisableSanitizeHtml bool `json:"disableSanitizeHtml"`
|
||||
|
||||
Auth FrontendSettingsAuthDTO `json:"auth"`
|
||||
|
||||
|
||||
+70
-41
@@ -31,22 +31,20 @@ func (hs *HTTPServer) GetFrontendSettings(c *contextmodel.ReqContext) {
|
||||
|
||||
// getFrontendSettings returns a json object with all the settings needed for front end initialisation.
|
||||
func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.FrontendSettingsDTO, error) {
|
||||
enabledPlugins, err := hs.enabledPlugins(c.Req.Context(), c.OrgID)
|
||||
availablePlugins, err := hs.availablePlugins(c.Req.Context(), c.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pluginsToPreload := make([]*plugins.PreloadPlugin, 0)
|
||||
for _, app := range enabledPlugins[plugins.App] {
|
||||
if app.Preload {
|
||||
pluginsToPreload = append(pluginsToPreload, &plugins.PreloadPlugin{
|
||||
Path: app.Module,
|
||||
Version: app.Info.Version,
|
||||
})
|
||||
}
|
||||
apps := make(map[string]*plugins.AppDTO, 0)
|
||||
for _, ap := range availablePlugins[plugins.App] {
|
||||
apps[ap.Plugin.ID] = newAppDTO(
|
||||
ap.Plugin,
|
||||
ap.Settings,
|
||||
)
|
||||
}
|
||||
|
||||
dataSources, err := hs.getFSDataSources(c, enabledPlugins)
|
||||
dataSources, err := hs.getFSDataSources(c, availablePlugins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -59,7 +57,8 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
}
|
||||
|
||||
panels := make(map[string]plugins.PanelDTO)
|
||||
for _, panel := range enabledPlugins[plugins.Panel] {
|
||||
for _, ap := range availablePlugins[plugins.Panel] {
|
||||
panel := ap.Plugin
|
||||
if panel.State == plugins.AlphaRelease && !hs.Cfg.PluginsEnableAlpha {
|
||||
continue
|
||||
}
|
||||
@@ -102,6 +101,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
Datasources: dataSources,
|
||||
MinRefreshInterval: setting.MinRefreshInterval,
|
||||
Panels: panels,
|
||||
Apps: apps,
|
||||
AppUrl: hs.Cfg.AppURL,
|
||||
AppSubUrl: hs.Cfg.AppSubURL,
|
||||
AllowOrgCreate: (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
|
||||
@@ -143,7 +143,6 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
AngularSupportEnabled: hs.Cfg.AngularSupportEnabled,
|
||||
EditorsCanAdmin: hs.Cfg.EditorsCanAdmin,
|
||||
DisableSanitizeHtml: hs.Cfg.DisableSanitizeHtml,
|
||||
PluginsToPreload: pluginsToPreload,
|
||||
DateFormats: hs.Cfg.DateFormats,
|
||||
|
||||
Auth: dtos.FrontendSettingsAuthDTO{
|
||||
@@ -259,7 +258,7 @@ func isSupportBundlesEnabled(hs *HTTPServer) bool {
|
||||
hs.Features.IsEnabled(featuremgmt.FlagSupportBundles)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getFSDataSources(c *contextmodel.ReqContext, enabledPlugins EnabledPlugins) (map[string]plugins.DataSourceDTO, error) {
|
||||
func (hs *HTTPServer) getFSDataSources(c *contextmodel.ReqContext, availablePlugins AvailablePlugins) (map[string]plugins.DataSourceDTO, error) {
|
||||
orgDataSources := make([]*datasources.DataSource, 0)
|
||||
if c.OrgID != 0 {
|
||||
query := datasources.GetDataSourcesQuery{OrgID: c.OrgID, DataSourceLimit: hs.Cfg.DataSourceLimit}
|
||||
@@ -300,11 +299,12 @@ func (hs *HTTPServer) getFSDataSources(c *contextmodel.ReqContext, enabledPlugin
|
||||
ReadOnly: ds.ReadOnly,
|
||||
}
|
||||
|
||||
plugin, exists := enabledPlugins.Get(plugins.DataSource, ds.Type)
|
||||
ap, exists := availablePlugins.Get(plugins.DataSource, ds.Type)
|
||||
if !exists {
|
||||
c.Logger.Error("Could not find plugin definition for data source", "datasource_type", ds.Type)
|
||||
continue
|
||||
}
|
||||
plugin := ap.Plugin
|
||||
dsDTO.Preload = plugin.Preload
|
||||
dsDTO.Module = plugin.Module
|
||||
dsDTO.PluginMeta = &plugins.PluginMetaDTO{
|
||||
@@ -397,6 +397,21 @@ func (hs *HTTPServer) getFSDataSources(c *contextmodel.ReqContext, enabledPlugin
|
||||
return dataSources, nil
|
||||
}
|
||||
|
||||
func newAppDTO(plugin plugins.PluginDTO, settings pluginsettings.InfoDTO) *plugins.AppDTO {
|
||||
app := &plugins.AppDTO{
|
||||
ID: plugin.ID,
|
||||
Version: plugin.Info.Version,
|
||||
Path: plugin.Module,
|
||||
Preload: plugin.Preload,
|
||||
}
|
||||
|
||||
if settings.Enabled {
|
||||
app.Extensions = plugin.Extensions
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func getPanelSort(id string) int {
|
||||
sort := 100
|
||||
switch id {
|
||||
@@ -438,52 +453,66 @@ func getPanelSort(id string) int {
|
||||
return sort
|
||||
}
|
||||
|
||||
// EnabledPlugins represents a mapping from plugin types (panel, data source, etc.) to plugin IDs to plugins
|
||||
// For example ["panel"] -> ["piechart"] -> {pie chart plugin DTO}
|
||||
type EnabledPlugins map[plugins.Type]map[string]plugins.PluginDTO
|
||||
|
||||
func (ep EnabledPlugins) Get(pluginType plugins.Type, pluginID string) (plugins.PluginDTO, bool) {
|
||||
if _, exists := ep[pluginType][pluginID]; exists {
|
||||
return ep[pluginType][pluginID], true
|
||||
}
|
||||
|
||||
return plugins.PluginDTO{}, false
|
||||
type availablePluginDTO struct {
|
||||
Plugin plugins.PluginDTO
|
||||
Settings pluginsettings.InfoDTO
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) enabledPlugins(ctx context.Context, orgID int64) (EnabledPlugins, error) {
|
||||
ep := make(EnabledPlugins)
|
||||
// AvailablePlugins represents a mapping from plugin types (panel, data source, etc.) to plugin IDs to plugins
|
||||
// For example ["panel"] -> ["piechart"] -> {pie chart plugin DTO}
|
||||
type AvailablePlugins map[plugins.Type]map[string]*availablePluginDTO
|
||||
|
||||
func (ap AvailablePlugins) Get(pluginType plugins.Type, pluginID string) (*availablePluginDTO, bool) {
|
||||
if _, exists := ap[pluginType][pluginID]; exists {
|
||||
return ap[pluginType][pluginID], true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) availablePlugins(ctx context.Context, orgID int64) (AvailablePlugins, error) {
|
||||
ap := make(AvailablePlugins)
|
||||
|
||||
pluginSettingMap, err := hs.pluginSettings(ctx, orgID)
|
||||
if err != nil {
|
||||
return ep, err
|
||||
return ap, err
|
||||
}
|
||||
|
||||
apps := make(map[string]plugins.PluginDTO)
|
||||
apps := make(map[string]*availablePluginDTO)
|
||||
for _, app := range hs.pluginStore.Plugins(ctx, plugins.App) {
|
||||
if b, exists := pluginSettingMap[app.ID]; exists {
|
||||
app.Pinned = b.Pinned
|
||||
apps[app.ID] = app
|
||||
if s, exists := pluginSettingMap[app.ID]; exists {
|
||||
app.Pinned = s.Pinned
|
||||
apps[app.ID] = &availablePluginDTO{
|
||||
Plugin: app,
|
||||
Settings: *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
ep[plugins.App] = apps
|
||||
ap[plugins.App] = apps
|
||||
|
||||
dataSources := make(map[string]plugins.PluginDTO)
|
||||
dataSources := make(map[string]*availablePluginDTO)
|
||||
for _, ds := range hs.pluginStore.Plugins(ctx, plugins.DataSource) {
|
||||
if _, exists := pluginSettingMap[ds.ID]; exists {
|
||||
dataSources[ds.ID] = ds
|
||||
if s, exists := pluginSettingMap[ds.ID]; exists {
|
||||
dataSources[ds.ID] = &availablePluginDTO{
|
||||
Plugin: ds,
|
||||
Settings: *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
ep[plugins.DataSource] = dataSources
|
||||
ap[plugins.DataSource] = dataSources
|
||||
|
||||
panels := make(map[string]plugins.PluginDTO)
|
||||
panels := make(map[string]*availablePluginDTO)
|
||||
for _, p := range hs.pluginStore.Plugins(ctx, plugins.Panel) {
|
||||
if _, exists := pluginSettingMap[p.ID]; exists {
|
||||
panels[p.ID] = p
|
||||
if s, exists := pluginSettingMap[p.ID]; exists {
|
||||
panels[p.ID] = &availablePluginDTO{
|
||||
Plugin: p,
|
||||
Settings: *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
ep[plugins.Panel] = panels
|
||||
ap[plugins.Panel] = panels
|
||||
|
||||
return ep, nil
|
||||
return ap, nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) pluginSettings(ctx context.Context, orgID int64) (map[string]*pluginsettings.InfoDTO, error) {
|
||||
|
||||
@@ -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