From d70ef90bddad216435a4fdea4d3f2d14c1ee736f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 8 Apr 2016 16:42:33 -0400 Subject: [PATCH] feat(): plugin list panel --- pkg/api/api.go | 3 + pkg/api/gnetproxy.go | 46 +++++++ pkg/api/plugins.go | 6 + pkg/plugins/frontend_plugin.go | 7 +- pkg/plugins/models.go | 1 + public/app/plugins/panel/pluginlist/README.md | 2 + .../app/plugins/panel/pluginlist/editor.html | 40 ++++++ .../pluginlist/img/icn-dashlist-panel.svg | 119 ++++++++++++++++++ .../app/plugins/panel/pluginlist/module.html | 17 +++ public/app/plugins/panel/pluginlist/module.ts | 66 ++++++++++ .../app/plugins/panel/pluginlist/plugin.json | 16 +++ 11 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 pkg/api/gnetproxy.go create mode 100644 public/app/plugins/panel/pluginlist/README.md create mode 100644 public/app/plugins/panel/pluginlist/editor.html create mode 100644 public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg create mode 100644 public/app/plugins/panel/pluginlist/module.html create mode 100644 public/app/plugins/panel/pluginlist/module.ts create mode 100644 public/app/plugins/panel/pluginlist/plugin.json diff --git a/pkg/api/api.go b/pkg/api/api.go index 85f1e2474c3..62da5c8f084 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -252,6 +252,9 @@ func Register(r *macaron.Macaron) { // rendering r.Get("/render/*", reqSignedIn, RenderToPng) + // grafana.net proxy + r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest) + // Gravatar service. avt := avatar.CacheServer() r.Get("/avatar/:hash", avt.ServeHTTP) diff --git a/pkg/api/gnetproxy.go b/pkg/api/gnetproxy.go new file mode 100644 index 00000000000..6511afd39b7 --- /dev/null +++ b/pkg/api/gnetproxy.go @@ -0,0 +1,46 @@ +package api + +import ( + "crypto/tls" + "net" + "net/http" + "net/http/httputil" + "time" + + "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/util" +) + +var gNetProxyTransport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, +} + +func ReverseProxyGnetReq(proxyPath string) *httputil.ReverseProxy { + director := func(req *http.Request) { + req.URL.Scheme = "https" + req.URL.Host = "grafana.net" + req.Host = "grafana.net" + + req.URL.Path = util.JoinUrlFragments("https://grafana.net/api", proxyPath) + + // clear cookie headers + req.Header.Del("Cookie") + req.Header.Del("Set-Cookie") + } + + return &httputil.ReverseProxy{Director: director} +} + +func ProxyGnetRequest(c *middleware.Context) { + proxyPath := c.Params("*") + proxy := ReverseProxyGnetReq(proxyPath) + proxy.Transport = gNetProxyTransport + proxy.ServeHTTP(c.Resp, c.Req.Request) + c.Resp.Header().Del("Set-Cookie") +} diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 0411c0746ef..3e8f80132d3 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -14,6 +14,7 @@ func GetPluginList(c *middleware.Context) Response { typeFilter := c.Query("type") enabledFilter := c.Query("enabled") embeddedFilter := c.Query("embedded") + coreFilter := c.Query("core") pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId) @@ -28,6 +29,11 @@ func GetPluginList(c *middleware.Context) Response { continue } + // filter out core plugins + if coreFilter == "0" && pluginDef.IsCorePlugin { + continue + } + // filter on type if typeFilter != "" && typeFilter != pluginDef.Type { continue diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go index 55690777b2a..974559001d1 100644 --- a/pkg/plugins/frontend_plugin.go +++ b/pkg/plugins/frontend_plugin.go @@ -14,7 +14,7 @@ type FrontendPluginBase struct { } func (fp *FrontendPluginBase) initFrontendPlugin() { - if isInternalPlugin(fp.PluginDir) { + if isExternalPlugin(fp.PluginDir) { StaticRoutes = append(StaticRoutes, &PluginStaticRoute{ Directory: fp.PluginDir, PluginId: fp.Id, @@ -48,17 +48,18 @@ func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) { func (fp *FrontendPluginBase) handleModuleDefaults() { - if isInternalPlugin(fp.PluginDir) { + if isExternalPlugin(fp.PluginDir) { fp.Module = path.Join("plugins", fp.Id, "module") fp.BaseUrl = path.Join("public/plugins", fp.Id) return } + fp.IsCorePlugin = true fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module") fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id) } -func isInternalPlugin(pluginDir string) bool { +func isExternalPlugin(pluginDir string) bool { return !strings.Contains(pluginDir, setting.StaticRootPath) } diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 30f794285e1..d35a78000b0 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -43,6 +43,7 @@ type PluginBase struct { IncludedInAppId string `json:"-"` PluginDir string `json:"-"` DefaultNavUrl string `json:"-"` + IsCorePlugin bool `json:"-"` // cache for readme file contents Readme []byte `json:"-"` diff --git a/public/app/plugins/panel/pluginlist/README.md b/public/app/plugins/panel/pluginlist/README.md new file mode 100644 index 00000000000..463769dad1f --- /dev/null +++ b/public/app/plugins/panel/pluginlist/README.md @@ -0,0 +1,2 @@ +# Plugin List Panel - Native Plugin + diff --git a/public/app/plugins/panel/pluginlist/editor.html b/public/app/plugins/panel/pluginlist/editor.html new file mode 100644 index 00000000000..c0577578598 --- /dev/null +++ b/public/app/plugins/panel/pluginlist/editor.html @@ -0,0 +1,40 @@ +
+
+
+ Mode +
+ +
+
+
+ + + +
+
+ +
+
+ Search options + Query + + + +
+ +
+ Tags + + + +
+
+ +
+
+ Limit number to + +
+
+
diff --git a/public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg b/public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg new file mode 100644 index 00000000000..8bac231bedf --- /dev/null +++ b/public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/app/plugins/panel/pluginlist/module.html b/public/app/plugins/panel/pluginlist/module.html new file mode 100644 index 00000000000..aaabb1c2c16 --- /dev/null +++ b/public/app/plugins/panel/pluginlist/module.html @@ -0,0 +1,17 @@ +
+ +
diff --git a/public/app/plugins/panel/pluginlist/module.ts b/public/app/plugins/panel/pluginlist/module.ts new file mode 100644 index 00000000000..86108a27961 --- /dev/null +++ b/public/app/plugins/panel/pluginlist/module.ts @@ -0,0 +1,66 @@ +/// + +import _ from 'lodash'; +import config from 'app/core/config'; +import {PanelCtrl} from '../../../features/panel/panel_ctrl'; + +// Set and populate defaults +var panelDefaults = { +}; + +class DashListCtrl extends PanelCtrl { + static templateUrl = 'module.html'; + + pluginList: any[]; + + /** @ngInject */ + constructor($scope, $injector, private backendSrv) { + super($scope, $injector); + _.defaults(this.panel, panelDefaults); + + this.events.on('init-edit-mode', this.onInitEditMode.bind(this)); + this.pluginList = []; + this.update(); + } + + onInitEditMode() { + this.editorTabIndex = 1; + this.addEditorTab('Options', 'public/app/plugins/panel/pluginlist/editor.html'); + } + + update() { + this.backendSrv.get('api/plugins', {embedded: 0, core: 0}).then(plugins => { + this.pluginList = plugins; + + for (let plugin of this.pluginList) { + if (!plugin.enabled) { + plugin.state = 'not-enabled'; + } + } + + }).then(this.checkForUpdates.bind(this)); + } + + checkForUpdates() { + return this.backendSrv.get('api/gnet/plugins/repo').then(data => { + var gNetPlugins = _.reduce(data.plugins, (memo, val) => { + memo[val.id] = val; + return memo; + }, {}); + + for (let plugin of this.pluginList) { + var source = gNetPlugins[plugin.id]; + if (!source) { + continue; + } + + if (plugin.info.version !== source.versions[0].version) { + plugin.hasUpdate = true; + plugin.state = 'has-update'; + } + } + }); + } +} + +export {DashListCtrl, DashListCtrl as PanelCtrl} diff --git a/public/app/plugins/panel/pluginlist/plugin.json b/public/app/plugins/panel/pluginlist/plugin.json new file mode 100644 index 00000000000..be6ae9a5985 --- /dev/null +++ b/public/app/plugins/panel/pluginlist/plugin.json @@ -0,0 +1,16 @@ +{ + "type": "panel", + "name": "Plugin list", + "id": "pluginlist", + + "info": { + "author": { + "name": "Grafana Project", + "url": "http://grafana.org" +}, + "logos": { + "small": "img/icn-dashlist-panel.svg", + "large": "img/icn-dashlist-panel.svg" + } + } +}