Merge branch 'apps'
This commit is contained in:
+9
-2
@@ -41,8 +41,8 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/admin/orgs", reqGrafanaAdmin, Index)
|
||||
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
|
||||
|
||||
r.Get("/plugins", reqSignedIn, Index)
|
||||
r.Get("/plugins/edit/*", reqSignedIn, Index)
|
||||
r.Get("/apps", reqSignedIn, Index)
|
||||
r.Get("/apps/edit/*", reqSignedIn, Index)
|
||||
|
||||
r.Get("/dashboard/*", reqSignedIn, Index)
|
||||
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
||||
@@ -120,6 +120,11 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/invites", wrap(GetPendingOrgInvites))
|
||||
r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
|
||||
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
|
||||
|
||||
// apps
|
||||
r.Get("/apps", wrap(GetOrgAppsList))
|
||||
r.Get("/apps/:appId/settings", wrap(GetAppSettingsById))
|
||||
r.Post("/apps/:appId/settings", bind(m.UpdateAppSettingsCmd{}), wrap(UpdateAppSettings))
|
||||
}, reqOrgAdmin)
|
||||
|
||||
// create new org
|
||||
@@ -205,5 +210,7 @@ func Register(r *macaron.Macaron) {
|
||||
// rendering
|
||||
r.Get("/render/*", reqSignedIn, RenderToPng)
|
||||
|
||||
InitApiPluginRoutes(r)
|
||||
|
||||
r.NotFound(NotFoundHandler)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func InitApiPluginRoutes(r *macaron.Macaron) {
|
||||
for _, plugin := range plugins.ApiPlugins {
|
||||
log.Info("Plugin: Adding proxy routes for api plugin")
|
||||
for _, route := range plugin.Routes {
|
||||
url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path)
|
||||
handlers := make([]macaron.Handler, 0)
|
||||
if route.ReqSignedIn {
|
||||
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}))
|
||||
}
|
||||
if route.ReqGrafanaAdmin {
|
||||
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true}))
|
||||
}
|
||||
if route.ReqSignedIn && route.ReqRole != "" {
|
||||
if route.ReqRole == m.ROLE_ADMIN {
|
||||
handlers = append(handlers, middleware.RoleAuth(m.ROLE_ADMIN))
|
||||
} else if route.ReqRole == m.ROLE_EDITOR {
|
||||
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
|
||||
}
|
||||
}
|
||||
handlers = append(handlers, ApiPlugin(route.Url))
|
||||
r.Route(url, route.Method, handlers...)
|
||||
log.Info("Plugin: Adding route %s", url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ApiPlugin(routeUrl string) macaron.Handler {
|
||||
return func(c *middleware.Context) {
|
||||
path := c.Params("*")
|
||||
|
||||
//Create a HTTP header with the context in it.
|
||||
ctx, err := json.Marshal(c.SignedInUser)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "failed to marshal context to json.", err)
|
||||
return
|
||||
}
|
||||
targetUrl, _ := url.Parse(routeUrl)
|
||||
proxy := NewApiPluginProxy(string(ctx), path, targetUrl)
|
||||
proxy.Transport = dataProxyTransport
|
||||
proxy.ServeHTTP(c.RW(), c.Req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func NewApiPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
|
||||
director := func(req *http.Request) {
|
||||
req.URL.Scheme = targetUrl.Scheme
|
||||
req.URL.Host = targetUrl.Host
|
||||
req.Host = targetUrl.Host
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
req.Header.Del("Set-Cookie")
|
||||
req.Header.Add("Grafana-Context", ctx)
|
||||
}
|
||||
|
||||
return &httputil.ReverseProxy{Director: director}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
func GetOrgAppsList(c *middleware.Context) Response {
|
||||
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
|
||||
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to list of apps", err)
|
||||
}
|
||||
|
||||
result := make([]*dtos.AppSettings, 0)
|
||||
for _, app := range plugins.Apps {
|
||||
orgApp := orgApps[app.Id]
|
||||
result = append(result, dtos.NewAppSettingsDto(app, orgApp))
|
||||
}
|
||||
|
||||
return Json(200, result)
|
||||
}
|
||||
|
||||
func GetAppSettingsById(c *middleware.Context) Response {
|
||||
appId := c.Params(":appId")
|
||||
|
||||
if pluginDef, exists := plugins.Apps[appId]; !exists {
|
||||
return ApiError(404, "PluginId not found, no installed plugin with that id", nil)
|
||||
} else {
|
||||
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to get org app settings ", nil)
|
||||
}
|
||||
orgApp := orgApps[appId]
|
||||
|
||||
return Json(200, dtos.NewAppSettingsDto(pluginDef, orgApp))
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateAppSettings(c *middleware.Context, cmd m.UpdateAppSettingsCmd) Response {
|
||||
appId := c.Params(":appId")
|
||||
|
||||
cmd.OrgId = c.OrgId
|
||||
cmd.AppId = appId
|
||||
|
||||
if _, ok := plugins.Apps[cmd.AppId]; !ok {
|
||||
return ApiError(404, "App type not installed.", nil)
|
||||
}
|
||||
|
||||
err := bus.Dispatch(&cmd)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to update App Plugin", err)
|
||||
}
|
||||
|
||||
return ApiSuccess("App updated")
|
||||
}
|
||||
+13
-6
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
//"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -115,13 +116,19 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
|
||||
}
|
||||
|
||||
func GetDataSourcePlugins(c *middleware.Context) {
|
||||
dsList := make(map[string]interface{})
|
||||
dsList := make(map[string]*plugins.DataSourcePlugin)
|
||||
|
||||
for key, value := range plugins.DataSources {
|
||||
if !value.BuiltIn {
|
||||
dsList[key] = value
|
||||
if enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId); err != nil {
|
||||
c.JsonApiErr(500, "Failed to get org apps", err)
|
||||
return
|
||||
} else {
|
||||
|
||||
for key, value := range enabledPlugins.DataSources {
|
||||
if !value.BuiltIn {
|
||||
dsList[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, dsList)
|
||||
c.JSON(200, dsList)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package dtos
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
type AppSettings struct {
|
||||
Name string `json:"name"`
|
||||
AppId string `json:"appId"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Pinned bool `json:"pinned"`
|
||||
Info *plugins.PluginInfo `json:"info"`
|
||||
Pages []*plugins.AppPluginPage `json:"pages"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
}
|
||||
|
||||
func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSettings {
|
||||
dto := &AppSettings{
|
||||
AppId: def.Id,
|
||||
Name: def.Name,
|
||||
Info: &def.Info,
|
||||
Pages: def.Pages,
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
dto.Enabled = data.Enabled
|
||||
dto.Pinned = data.Pinned
|
||||
dto.Info = &def.Info
|
||||
}
|
||||
|
||||
return dto
|
||||
}
|
||||
@@ -8,9 +8,9 @@ type IndexViewData struct {
|
||||
GoogleAnalyticsId string
|
||||
GoogleTagManagerId string
|
||||
|
||||
PluginCss []*PluginCss
|
||||
PluginJs []string
|
||||
MainNavLinks []*NavLink
|
||||
PluginCss []*PluginCss
|
||||
PluginModules []string
|
||||
MainNavLinks []*NavLink
|
||||
}
|
||||
|
||||
type PluginCss struct {
|
||||
@@ -21,5 +21,6 @@ type PluginCss struct {
|
||||
type NavLink struct {
|
||||
Text string `json:"text"`
|
||||
Icon string `json:"icon"`
|
||||
Href string `json:"href"`
|
||||
Img string `json:"img"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package dtos
|
||||
|
||||
type PluginBundle struct {
|
||||
Type string `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Module string `json:"module"`
|
||||
JsonData map[string]interface{} `json:"jsonData"`
|
||||
}
|
||||
@@ -29,6 +29,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
datasources := make(map[string]interface{})
|
||||
var defaultDatasource string
|
||||
|
||||
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ds := range orgDataSources {
|
||||
url := ds.Url
|
||||
|
||||
@@ -42,7 +47,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
"url": url,
|
||||
}
|
||||
|
||||
meta, exists := plugins.DataSources[ds.Type]
|
||||
meta, exists := enabledPlugins.DataSources[ds.Type]
|
||||
if !exists {
|
||||
log.Error(3, "Could not find plugin definition for data source: %v", ds.Type)
|
||||
continue
|
||||
@@ -110,8 +115,8 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
||||
}
|
||||
|
||||
panels := map[string]interface{}{}
|
||||
for _, panel := range plugins.Panels {
|
||||
panels[panel.Type] = map[string]interface{}{
|
||||
for _, panel := range enabledPlugins.Panels {
|
||||
panels[panel.Id] = map[string]interface{}{
|
||||
"module": panel.Module,
|
||||
"name": panel.Name,
|
||||
}
|
||||
|
||||
+32
-2
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@@ -50,7 +51,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: "Dashboards",
|
||||
Icon: "fa fa-fw fa-th-large",
|
||||
Href: "/",
|
||||
Url: "/",
|
||||
})
|
||||
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
@@ -63,8 +64,37 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: "Data Sources",
|
||||
Icon: "fa fa-fw fa-database",
|
||||
Href: "/datasources",
|
||||
Url: "/datasources",
|
||||
})
|
||||
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: "Apps",
|
||||
Icon: "fa fa-fw fa-cubes",
|
||||
Url: "/apps",
|
||||
})
|
||||
}
|
||||
|
||||
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, plugin := range enabledPlugins.Apps {
|
||||
if plugin.Module != "" {
|
||||
data.PluginModules = append(data.PluginModules, plugin.Module)
|
||||
}
|
||||
|
||||
if plugin.Css != nil {
|
||||
data.PluginCss = append(data.PluginCss, &dtos.PluginCss{Light: plugin.Css.Light, Dark: plugin.Css.Dark})
|
||||
}
|
||||
|
||||
if plugin.Pinned {
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: plugin.Name,
|
||||
Url: "/apps/edit/" + plugin.Id,
|
||||
Img: plugin.Info.Logos.Small,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
|
||||
Reference in New Issue
Block a user