mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(): plugin list panel
This commit is contained in:
parent
583c0f09a8
commit
d70ef90bdd
@ -252,6 +252,9 @@ func Register(r *macaron.Macaron) {
|
|||||||
// rendering
|
// rendering
|
||||||
r.Get("/render/*", reqSignedIn, RenderToPng)
|
r.Get("/render/*", reqSignedIn, RenderToPng)
|
||||||
|
|
||||||
|
// grafana.net proxy
|
||||||
|
r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)
|
||||||
|
|
||||||
// Gravatar service.
|
// Gravatar service.
|
||||||
avt := avatar.CacheServer()
|
avt := avatar.CacheServer()
|
||||||
r.Get("/avatar/:hash", avt.ServeHTTP)
|
r.Get("/avatar/:hash", avt.ServeHTTP)
|
||||||
|
46
pkg/api/gnetproxy.go
Normal file
46
pkg/api/gnetproxy.go
Normal file
@ -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")
|
||||||
|
}
|
@ -14,6 +14,7 @@ func GetPluginList(c *middleware.Context) Response {
|
|||||||
typeFilter := c.Query("type")
|
typeFilter := c.Query("type")
|
||||||
enabledFilter := c.Query("enabled")
|
enabledFilter := c.Query("enabled")
|
||||||
embeddedFilter := c.Query("embedded")
|
embeddedFilter := c.Query("embedded")
|
||||||
|
coreFilter := c.Query("core")
|
||||||
|
|
||||||
pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId)
|
pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId)
|
||||||
|
|
||||||
@ -28,6 +29,11 @@ func GetPluginList(c *middleware.Context) Response {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter out core plugins
|
||||||
|
if coreFilter == "0" && pluginDef.IsCorePlugin {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// filter on type
|
// filter on type
|
||||||
if typeFilter != "" && typeFilter != pluginDef.Type {
|
if typeFilter != "" && typeFilter != pluginDef.Type {
|
||||||
continue
|
continue
|
||||||
|
@ -14,7 +14,7 @@ type FrontendPluginBase struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fp *FrontendPluginBase) initFrontendPlugin() {
|
func (fp *FrontendPluginBase) initFrontendPlugin() {
|
||||||
if isInternalPlugin(fp.PluginDir) {
|
if isExternalPlugin(fp.PluginDir) {
|
||||||
StaticRoutes = append(StaticRoutes, &PluginStaticRoute{
|
StaticRoutes = append(StaticRoutes, &PluginStaticRoute{
|
||||||
Directory: fp.PluginDir,
|
Directory: fp.PluginDir,
|
||||||
PluginId: fp.Id,
|
PluginId: fp.Id,
|
||||||
@ -48,17 +48,18 @@ func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) {
|
|||||||
|
|
||||||
func (fp *FrontendPluginBase) handleModuleDefaults() {
|
func (fp *FrontendPluginBase) handleModuleDefaults() {
|
||||||
|
|
||||||
if isInternalPlugin(fp.PluginDir) {
|
if isExternalPlugin(fp.PluginDir) {
|
||||||
fp.Module = path.Join("plugins", fp.Id, "module")
|
fp.Module = path.Join("plugins", fp.Id, "module")
|
||||||
fp.BaseUrl = path.Join("public/plugins", fp.Id)
|
fp.BaseUrl = path.Join("public/plugins", fp.Id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp.IsCorePlugin = true
|
||||||
fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module")
|
fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module")
|
||||||
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id)
|
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)
|
return !strings.Contains(pluginDir, setting.StaticRootPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ type PluginBase struct {
|
|||||||
IncludedInAppId string `json:"-"`
|
IncludedInAppId string `json:"-"`
|
||||||
PluginDir string `json:"-"`
|
PluginDir string `json:"-"`
|
||||||
DefaultNavUrl string `json:"-"`
|
DefaultNavUrl string `json:"-"`
|
||||||
|
IsCorePlugin bool `json:"-"`
|
||||||
|
|
||||||
// cache for readme file contents
|
// cache for readme file contents
|
||||||
Readme []byte `json:"-"`
|
Readme []byte `json:"-"`
|
||||||
|
2
public/app/plugins/panel/pluginlist/README.md
Normal file
2
public/app/plugins/panel/pluginlist/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Plugin List Panel - Native Plugin
|
||||||
|
|
40
public/app/plugins/panel/pluginlist/editor.html
Normal file
40
public/app/plugins/panel/pluginlist/editor.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<div class="gf-form-group">
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Mode</span>
|
||||||
|
<div class="gf-form-select-wrapper max-width-10">
|
||||||
|
<select class="gf-form-input" ng-model="ctrl.panel.mode" ng-options="f for f in ctrl.modes" ng-change="ctrl.refresh()"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.mode === 'recently viewed'">
|
||||||
|
<span class="gf-form-label">
|
||||||
|
<i class="grafana-tip fa fa-question-circle ng-scope" bs-tooltip="'WARNING: This list will be cleared when clearing browser cache'" data-original-title="" title=""></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline" ng-if="ctrl.panel.mode === 'search'">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Search options</span>
|
||||||
|
<span class="gf-form-label">Query</span>
|
||||||
|
|
||||||
|
<input type="text" class="gf-form-input" placeholder="title query"
|
||||||
|
ng-model="ctrl.panel.query" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label">Tags</span>
|
||||||
|
|
||||||
|
<bootstrap-tagsinput ng-model="ctrl.panel.tags" tagclass="label label-tag" placeholder="add tags" on-tags-updated="ctrl.refresh()">
|
||||||
|
</bootstrap-tagsinput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-10">Limit number to</span>
|
||||||
|
<input class="gf-form-input" type="number" ng-model="ctrl.panel.limit" ng-model-onblur ng-change="ctrl.refresh()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
119
public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg
Normal file
119
public/app/plugins/panel/pluginlist/img/icn-dashlist-panel.svg
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="100px" height="100px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,11.219h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,11.219z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,2.113l2.054-2.054C0.966,0.139,0.089,1.016,0.008,2.113z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,2.998 0,5.533 5.484,0.05 2.948,0.05 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,0.05 0,6.411 0,8.946 8.896,0.05 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,2.277c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V2.277z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,0.169L0.119,9.704c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,0.812,10.247,0.37,9.654,0.169z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,5.479 5.429,11.219 7.964,11.219 11.169,8.014 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,11.031H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.831,1.83-1.831h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.831v7.37C89.977,10.212,89.157,11.031,88.146,11.031z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,23.902h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,23.902z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,14.796l2.054-2.054C0.966,12.822,0.089,13.699,0.008,14.796z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,15.681 0,18.216 5.484,12.733 2.948,12.733 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,12.733 0,19.094 0,21.629 8.896,12.733 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,14.96c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V14.96z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,12.852l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,13.495,10.247,13.053,9.654,12.852z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,18.162 5.429,23.902 7.964,23.902 11.169,20.697 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,23.714H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.83,1.83-1.83h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.83v7.37C89.977,22.895,89.157,23.714,88.146,23.714z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,36.585h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,36.585z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,27.479l2.054-2.054C0.966,25.505,0.089,26.382,0.008,27.479z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,28.364 0,30.899 5.484,25.416 2.948,25.416 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,25.416 0,31.777 0,34.312 8.896,25.416 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,27.643c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V27.643z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,25.535L0.119,35.07c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,26.178,10.247,25.736,9.654,25.535z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,30.845 5.429,36.585 7.964,36.585 11.169,33.38 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,36.397H14.866c-1.011,0-1.83-0.82-1.83-1.831v-7.37c0-1.011,0.82-1.83,1.83-1.83h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.83v7.37C89.977,35.578,89.157,36.397,88.146,36.397z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,49.268h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,49.268z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,40.162l2.054-2.054C0.966,38.188,0.089,39.065,0.008,40.162z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,41.047 0,43.582 5.484,38.099 2.948,38.099 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,38.099 0,44.46 0,46.995 8.896,38.099 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,40.326c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V40.326z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,38.218l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,38.861,10.247,38.419,9.654,38.218z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,43.528 5.429,49.268 7.964,49.268 11.169,46.063 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,49.08H14.866c-1.011,0-1.83-0.82-1.83-1.831v-7.37c0-1.011,0.82-1.831,1.83-1.831h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.831v7.37C89.977,48.261,89.157,49.08,88.146,49.08z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,61.951h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,61.951z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,52.845l2.054-2.054C0.966,50.871,0.089,51.748,0.008,52.845z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,53.73 0,56.265 5.484,50.782 2.948,50.782 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,50.782 0,57.143 0,59.678 8.896,50.782 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,53.009c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V53.009z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,50.901l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,51.544,10.247,51.102,9.654,50.901z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,56.211 5.429,61.951 7.964,61.951 11.169,58.746 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,61.763H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.831,1.83-1.831h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.831v7.37C89.977,60.944,89.157,61.763,88.146,61.763z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,74.634h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,74.634z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,65.528l2.054-2.054C0.966,63.554,0.089,64.431,0.008,65.528z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,66.413 0,68.948 5.484,63.465 2.948,63.465 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,63.465 0,69.826 0,72.361 8.896,63.465 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,65.692c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V65.692z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,63.584l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,64.227,10.247,63.785,9.654,63.584z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,68.894 5.429,74.634 7.964,74.634 11.169,71.429 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,74.446H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.831,1.83-1.831h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.831v7.37C89.977,73.627,89.157,74.446,88.146,74.446z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,87.317h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,87.317z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,78.211l2.054-2.054C0.966,76.237,0.089,77.114,0.008,78.211z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,79.096 0,81.631 5.484,76.148 2.948,76.148 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,76.148 0,82.509 0,85.044 8.896,76.148 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,78.375c0-0.068-0.004-0.134-0.01-0.2l-9.132,9.132c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V78.375z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,76.267l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,76.91,10.247,76.468,9.654,76.267z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,81.577 5.429,87.317 7.964,87.317 11.169,84.112 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,87.129H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.831,1.83-1.831h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.831v7.37C89.977,86.31,89.157,87.129,88.146,87.129z"/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#666666;" d="M8.842,100h0.1c1.228,0,2.227-0.999,2.227-2.227v-0.1L8.842,100z"/>
|
||||||
|
<path style="fill:#666666;" d="M0.008,90.894l2.054-2.054C0.966,88.92,0.089,89.797,0.008,90.894z"/>
|
||||||
|
<polygon style="fill:#666666;" points="0,91.779 0,94.314 5.484,88.831 2.948,88.831 "/>
|
||||||
|
<polygon style="fill:#666666;" points="6.361,88.831 0,95.192 0,97.727 8.896,88.831 "/>
|
||||||
|
<path style="fill:#666666;" d="M11.169,91.058c0-0.068-0.004-0.134-0.01-0.2L2.027,99.99c0.066,0.006,0.133,0.01,0.2,0.01h2.325
|
||||||
|
l6.617-6.617V91.058z"/>
|
||||||
|
<path style="fill:#666666;" d="M9.654,88.95l-9.536,9.536c0.201,0.592,0.643,1.073,1.211,1.324l9.649-9.649
|
||||||
|
C10.728,89.593,10.247,89.151,9.654,88.95z"/>
|
||||||
|
<polygon style="fill:#666666;" points="11.169,94.26 5.429,100 7.964,100 11.169,96.795 "/>
|
||||||
|
</g>
|
||||||
|
<path style="fill:#898989;" d="M88.146,99.812H14.866c-1.011,0-1.83-0.82-1.83-1.83v-7.37c0-1.011,0.82-1.83,1.83-1.83h73.281
|
||||||
|
c1.011,0,1.83,0.82,1.83,1.83v7.37C89.977,98.993,89.157,99.812,88.146,99.812z"/>
|
||||||
|
<circle style="fill:#F7941E;" cx="96.125" cy="5.637" r="3.875"/>
|
||||||
|
<circle style="fill:#898989;" cx="96.125" cy="18.37" r="3.875"/>
|
||||||
|
<circle style="fill:#898989;" cx="96.125" cy="31.104" r="3.875"/>
|
||||||
|
<circle style="fill:#F7941E;" cx="96.125" cy="43.837" r="3.875"/>
|
||||||
|
<circle style="fill:#F7941E;" cx="96.125" cy="56.57" r="3.875"/>
|
||||||
|
<circle style="fill:#898989;" cx="96.125" cy="69.304" r="3.875"/>
|
||||||
|
<circle style="fill:#F7941E;" cx="96.125" cy="82.037" r="3.875"/>
|
||||||
|
<circle style="fill:#898989;" cx="96.125" cy="94.77" r="3.875"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.8 KiB |
17
public/app/plugins/panel/pluginlist/module.html
Normal file
17
public/app/plugins/panel/pluginlist/module.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<div class="dashlist">
|
||||||
|
<div class="dashlist-item" ng-repeat="plugin in ctrl.pluginList">
|
||||||
|
<a class="dashlist-link dashlist-link-{{plugin.state}}" href="plugins/{{plugin.id}}/edit">
|
||||||
|
<span class="dashlist-title">
|
||||||
|
{{plugin.name}}
|
||||||
|
</span>
|
||||||
|
<span class="dashlist-update" ng-show="plugin.hasUpdate">
|
||||||
|
<i class="fa fa-exclamation"></i>
|
||||||
|
Update available
|
||||||
|
</span>
|
||||||
|
<span class="dashlist-update" ng-show="!plugin.enabled">
|
||||||
|
<i class="fa fa-exclamation"></i>
|
||||||
|
Enable now
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
66
public/app/plugins/panel/pluginlist/module.ts
Normal file
66
public/app/plugins/panel/pluginlist/module.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
///<reference path="../../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
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}
|
16
public/app/plugins/panel/pluginlist/plugin.json
Normal file
16
public/app/plugins/panel/pluginlist/plugin.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user