Files
Will Browne 2c47d246fc Plugins: Introduce LoadingStrategy for frontend loading logic (#92392)
* do it all

* feat(plugins): move loadingStrategy to ds pluginMeta and add to plugin settings endpoint

* support child plugins and update tests

* use relative path for nested plugins

* feat(plugins): support nested plugins in the plugin loader cache by extracting pluginId from path

* feat(grafana-data): add plugin loading strategy to plugin meta and export

* feat(plugins): pass down loadingStrategy to fe plugin loader

* refactor(plugins): make PluginLoadingStrategy an enum

* feat(plugins): add the loading strategy to the fe plugin loader cache

* feat(plugins): load fe plugin js assets as script tags based on be loadingStrategy

* add more tests

* feat(plugins): add loading strategy to plugin preloader

* feat(plugins): make loadingStrategy a maybe and provide fetch fallback

* test(alerting): update config.apps mocks to include loadingStrategy

* fix format

---------

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
2024-09-09 10:38:35 +01:00

82 lines
2.2 KiB
Go

package pluginassets
import (
"context"
"github.com/Masterminds/semver/v3"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/setting"
)
const (
CreatePluginVersionCfgKey = "create_plugin_version"
CreatePluginVersionScriptSupportEnabled = "4.15.0"
)
var (
scriptLoadingMinSupportedVersion = semver.MustParse(CreatePluginVersionScriptSupportEnabled)
)
func ProvideService(cfg *setting.Cfg, cdn *pluginscdn.Service) *Service {
return &Service{
cfg: cfg,
cdn: cdn,
log: log.New("pluginassets"),
}
}
type Service struct {
cfg *setting.Cfg
cdn *pluginscdn.Service
log log.Logger
}
// LoadingStrategy calculates the loading strategy for a plugin.
// If a plugin has plugin setting `create_plugin_version` >= 4.15.0, set loadingStrategy to "script".
// If a plugin is not loaded via the CDN and is not Angular, set loadingStrategy to "script".
// Otherwise, set loadingStrategy to "fetch".
func (s *Service) LoadingStrategy(_ context.Context, p pluginstore.Plugin) plugins.LoadingStrategy {
if pCfg, ok := s.cfg.PluginSettings[p.ID]; ok {
if s.compatibleCreatePluginVersion(pCfg) {
return plugins.LoadingStrategyScript
}
}
// If the plugin has a parent, check the parent's create_plugin_version setting
if p.Parent != nil {
if pCfg, ok := s.cfg.PluginSettings[p.Parent.ID]; ok {
if s.compatibleCreatePluginVersion(pCfg) {
return plugins.LoadingStrategyScript
}
}
}
if !s.cndEnabled(p) && !p.Angular.Detected {
return plugins.LoadingStrategyScript
}
return plugins.LoadingStrategyFetch
}
func (s *Service) compatibleCreatePluginVersion(ps map[string]string) bool {
if cpv, ok := ps[CreatePluginVersionCfgKey]; ok {
createPluginVer, err := semver.NewVersion(cpv)
if err != nil {
s.log.Warn("Failed to parse create plugin version setting as semver", "version", cpv, "error", err)
} else {
if !createPluginVer.LessThan(scriptLoadingMinSupportedVersion) {
return true
}
}
}
return false
}
func (s *Service) cndEnabled(p pluginstore.Plugin) bool {
return s.cdn.PluginSupported(p.ID) || p.Class == plugins.ClassCDN
}