mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 05:32:15 +08:00
feat(apps): lots of more work on apps, changed app_plugin to app_settings in order to to confuse the app plugin model (definition) and app org settings
This commit is contained in:
@ -41,8 +41,8 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Get("/admin/orgs", reqGrafanaAdmin, Index)
|
r.Get("/admin/orgs", reqGrafanaAdmin, Index)
|
||||||
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
|
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
|
||||||
|
|
||||||
r.Get("/org/apps", reqSignedIn, Index)
|
r.Get("/apps", reqSignedIn, Index)
|
||||||
r.Get("/org/apps/edit/*", reqSignedIn, Index)
|
r.Get("/apps/edit/*", reqSignedIn, Index)
|
||||||
|
|
||||||
r.Get("/dashboard/*", reqSignedIn, Index)
|
r.Get("/dashboard/*", reqSignedIn, Index)
|
||||||
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
||||||
@ -119,8 +119,9 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
|
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
|
||||||
|
|
||||||
// apps
|
// apps
|
||||||
r.Get("/apps", wrap(GetAppPlugins))
|
r.Get("/apps", wrap(GetOrgAppsList))
|
||||||
r.Post("/apps", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin))
|
r.Get("/apps/:appId/settings", wrap(GetAppSettingsById))
|
||||||
|
r.Post("/apps/:appId/settings", bind(m.UpdateAppSettingsCmd{}), wrap(UpdateAppSettings))
|
||||||
}, reqOrgAdmin)
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
// create new org
|
// create new org
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
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 GetAppPlugins(c *middleware.Context) Response {
|
|
||||||
query := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
|
||||||
return ApiError(500, "Failed to list Plugin Bundles", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
translateToDto := func(app *plugins.AppPlugin) *dtos.AppPlugin {
|
|
||||||
return &dtos.AppPlugin{
|
|
||||||
Name: app.Name,
|
|
||||||
Type: app.Type,
|
|
||||||
Enabled: app.Enabled,
|
|
||||||
Pinned: app.Pinned,
|
|
||||||
Module: app.Module,
|
|
||||||
Info: &app.Info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
seenApps := make(map[string]bool)
|
|
||||||
result := make([]*dtos.AppPlugin, 0)
|
|
||||||
for _, orgApp := range query.Result {
|
|
||||||
if def, ok := plugins.Apps[orgApp.Type]; ok {
|
|
||||||
pluginDto := translateToDto(def)
|
|
||||||
pluginDto.Enabled = orgApp.Enabled
|
|
||||||
pluginDto.JsonData = orgApp.JsonData
|
|
||||||
result = append(result, pluginDto)
|
|
||||||
seenApps[orgApp.Type] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, app := range plugins.Apps {
|
|
||||||
if _, ok := seenApps[app.Type]; !ok {
|
|
||||||
result = append(result, translateToDto(app))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json(200, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateAppPlugin(c *middleware.Context, cmd m.UpdateAppPluginCmd) Response {
|
|
||||||
cmd.OrgId = c.OrgId
|
|
||||||
|
|
||||||
if _, ok := plugins.Apps[cmd.Type]; !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")
|
|
||||||
}
|
|
59
pkg/api/app_settings.go
Normal file
59
pkg/api/app_settings.go
Normal file
@ -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")
|
||||||
|
}
|
@ -118,12 +118,10 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
|
|||||||
func GetDataSourcePlugins(c *middleware.Context) {
|
func GetDataSourcePlugins(c *middleware.Context) {
|
||||||
dsList := make(map[string]*plugins.DataSourcePlugin)
|
dsList := make(map[string]*plugins.DataSourcePlugin)
|
||||||
|
|
||||||
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
if enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId); err != nil {
|
||||||
err := bus.Dispatch(&orgApps)
|
|
||||||
if err != nil {
|
|
||||||
c.JsonApiErr(500, "Failed to get org apps", err)
|
c.JsonApiErr(500, "Failed to get org apps", err)
|
||||||
}
|
return
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
} else {
|
||||||
|
|
||||||
for key, value := range enabledPlugins.DataSources {
|
for key, value := range enabledPlugins.DataSources {
|
||||||
if !value.BuiltIn {
|
if !value.BuiltIn {
|
||||||
@ -132,4 +130,5 @@ func GetDataSourcePlugins(c *middleware.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(200, dsList)
|
c.JSON(200, dsList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package dtos
|
|
||||||
|
|
||||||
import "github.com/grafana/grafana/pkg/plugins"
|
|
||||||
|
|
||||||
type AppPlugin struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Pinned bool `json:"pinned"`
|
|
||||||
Module string `json:"module"`
|
|
||||||
Info *plugins.PluginInfo `json:"info"`
|
|
||||||
JsonData map[string]interface{} `json:"jsonData"`
|
|
||||||
}
|
|
31
pkg/api/dtos/apps.go
Normal file
31
pkg/api/dtos/apps.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
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"`
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
if data != nil {
|
||||||
|
dto.Enabled = data.Enabled
|
||||||
|
dto.Pinned = data.Pinned
|
||||||
|
dto.Info = &def.Info
|
||||||
|
}
|
||||||
|
|
||||||
|
return dto
|
||||||
|
}
|
@ -29,14 +29,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
|
|||||||
datasources := make(map[string]interface{})
|
datasources := make(map[string]interface{})
|
||||||
var defaultDatasource string
|
var defaultDatasource string
|
||||||
|
|
||||||
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
|
||||||
err := bus.Dispatch(&orgApps)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
|
||||||
|
|
||||||
for _, ds := range orgDataSources {
|
for _, ds := range orgDataSources {
|
||||||
url := ds.Url
|
url := ds.Url
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
@ -69,14 +68,11 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId}
|
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
|
||||||
err = bus.Dispatch(&orgApps)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result)
|
|
||||||
|
|
||||||
for _, plugin := range enabledPlugins.Apps {
|
for _, plugin := range enabledPlugins.Apps {
|
||||||
if plugin.Module != "" {
|
if plugin.Module != "" {
|
||||||
data.PluginModules = append(data.PluginModules, plugin.Module)
|
data.PluginModules = append(data.PluginModules, plugin.Module)
|
||||||
|
@ -2,9 +2,9 @@ package models
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type AppPlugin struct {
|
type AppSettings struct {
|
||||||
Id int64
|
Id int64
|
||||||
Type string
|
AppId string
|
||||||
OrgId int64
|
OrgId int64
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Pinned bool
|
Pinned bool
|
||||||
@ -18,19 +18,18 @@ type AppPlugin struct {
|
|||||||
// COMMANDS
|
// COMMANDS
|
||||||
|
|
||||||
// Also acts as api DTO
|
// Also acts as api DTO
|
||||||
type UpdateAppPluginCmd struct {
|
type UpdateAppSettingsCmd struct {
|
||||||
Type string `json:"type" binding:"Required"`
|
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Pinned bool `json:"pinned"`
|
Pinned bool `json:"pinned"`
|
||||||
JsonData map[string]interface{} `json:"jsonData"`
|
JsonData map[string]interface{} `json:"jsonData"`
|
||||||
|
|
||||||
Id int64 `json:"-"`
|
AppId string `json:"-"`
|
||||||
OrgId int64 `json:"-"`
|
OrgId int64 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// QUERIES
|
// QUERIES
|
||||||
type GetAppPluginsQuery struct {
|
type GetAppSettingsQuery struct {
|
||||||
OrgId int64
|
OrgId int64
|
||||||
Result []*AppPlugin
|
Result []*AppSettings
|
||||||
}
|
}
|
@ -13,7 +13,6 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
@ -180,78 +179,3 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
|
|||||||
|
|
||||||
return loader.Load(jsonParser, currentDir)
|
return loader.Load(jsonParser, currentDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins {
|
|
||||||
enabledPlugins := NewEnabledPlugins()
|
|
||||||
|
|
||||||
orgAppsMap := make(map[string]*models.AppPlugin)
|
|
||||||
for _, orgApp := range orgApps {
|
|
||||||
orgAppsMap[orgApp.Type] = orgApp
|
|
||||||
}
|
|
||||||
seenPanels := make(map[string]bool)
|
|
||||||
seenApi := make(map[string]bool)
|
|
||||||
|
|
||||||
for appType, installedApp := range Apps {
|
|
||||||
var app AppPlugin
|
|
||||||
app = *installedApp
|
|
||||||
|
|
||||||
// check if the app is stored in the DB for this org and if so, use the
|
|
||||||
// state stored there.
|
|
||||||
if b, ok := orgAppsMap[appType]; ok {
|
|
||||||
app.Enabled = b.Enabled
|
|
||||||
app.Pinned = b.Pinned
|
|
||||||
}
|
|
||||||
|
|
||||||
// if app.Enabled {
|
|
||||||
// for _, d := range app.DatasourcePlugins {
|
|
||||||
// if ds, ok := DataSources[d]; ok {
|
|
||||||
// enabledPlugins.DataSourcePlugins[d] = ds
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// for _, p := range app.PanelPlugins {
|
|
||||||
// if panel, ok := Panels[p]; ok {
|
|
||||||
// if _, ok := seenPanels[p]; !ok {
|
|
||||||
// seenPanels[p] = true
|
|
||||||
// enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// for _, a := range app.ApiPlugins {
|
|
||||||
// if api, ok := ApiPlugins[a]; ok {
|
|
||||||
// if _, ok := seenApi[a]; !ok {
|
|
||||||
// seenApi[a] = true
|
|
||||||
// enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, &app)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// add all plugins that are not part of an App.
|
|
||||||
for d, installedDs := range DataSources {
|
|
||||||
if installedDs.App == "" {
|
|
||||||
enabledPlugins.DataSources[d] = installedDs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for p, panel := range Panels {
|
|
||||||
if panel.App == "" {
|
|
||||||
if _, ok := seenPanels[p]; !ok {
|
|
||||||
seenPanels[p] = true
|
|
||||||
enabledPlugins.Panels = append(enabledPlugins.Panels, panel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for a, api := range ApiPlugins {
|
|
||||||
if api.App == "" {
|
|
||||||
if _, ok := seenApi[a]; !ok {
|
|
||||||
seenApi[a] = true
|
|
||||||
enabledPlugins.ApiList = append(enabledPlugins.ApiList, api)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return enabledPlugins
|
|
||||||
}
|
|
||||||
|
96
pkg/plugins/queries.go
Normal file
96
pkg/plugins/queries.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetOrgAppSettings(orgId int64) (map[string]*m.AppSettings, error) {
|
||||||
|
query := m.GetAppSettingsQuery{OrgId: orgId}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgAppsMap := make(map[string]*m.AppSettings)
|
||||||
|
for _, orgApp := range query.Result {
|
||||||
|
orgAppsMap[orgApp.AppId] = orgApp
|
||||||
|
}
|
||||||
|
|
||||||
|
return orgAppsMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEnabledPlugins(orgId int64) (*EnabledPlugins, error) {
|
||||||
|
enabledPlugins := NewEnabledPlugins()
|
||||||
|
orgApps, err := GetOrgAppSettings(orgId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
seenPanels := make(map[string]bool)
|
||||||
|
seenApi := make(map[string]bool)
|
||||||
|
|
||||||
|
for appType, installedApp := range Apps {
|
||||||
|
var app AppPlugin
|
||||||
|
app = *installedApp
|
||||||
|
|
||||||
|
// check if the app is stored in the DB for this org and if so, use the
|
||||||
|
// state stored there.
|
||||||
|
if b, ok := orgApps[appType]; ok {
|
||||||
|
app.Enabled = b.Enabled
|
||||||
|
app.Pinned = b.Pinned
|
||||||
|
}
|
||||||
|
|
||||||
|
// if app.Enabled {
|
||||||
|
// for _, d := range app.DatasourcePlugins {
|
||||||
|
// if ds, ok := DataSources[d]; ok {
|
||||||
|
// enabledPlugins.DataSourcePlugins[d] = ds
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for _, p := range app.PanelPlugins {
|
||||||
|
// if panel, ok := Panels[p]; ok {
|
||||||
|
// if _, ok := seenPanels[p]; !ok {
|
||||||
|
// seenPanels[p] = true
|
||||||
|
// enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for _, a := range app.ApiPlugins {
|
||||||
|
// if api, ok := ApiPlugins[a]; ok {
|
||||||
|
// if _, ok := seenApi[a]; !ok {
|
||||||
|
// seenApi[a] = true
|
||||||
|
// enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, &app)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all plugins that are not part of an App.
|
||||||
|
for d, installedDs := range DataSources {
|
||||||
|
if installedDs.App == "" {
|
||||||
|
enabledPlugins.DataSources[d] = installedDs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for p, panel := range Panels {
|
||||||
|
if panel.App == "" {
|
||||||
|
if _, ok := seenPanels[p]; !ok {
|
||||||
|
seenPanels[p] = true
|
||||||
|
enabledPlugins.Panels = append(enabledPlugins.Panels, panel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for a, api := range ApiPlugins {
|
||||||
|
if api.App == "" {
|
||||||
|
if _, ok := seenApi[a]; !ok {
|
||||||
|
seenApi[a] = true
|
||||||
|
enabledPlugins.ApiList = append(enabledPlugins.ApiList, api)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &enabledPlugins, nil
|
||||||
|
}
|
@ -8,27 +8,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bus.AddHandler("sql", GetAppPlugins)
|
bus.AddHandler("sql", GetAppSettings)
|
||||||
bus.AddHandler("sql", UpdateAppPlugin)
|
bus.AddHandler("sql", UpdateAppSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAppPlugins(query *m.GetAppPluginsQuery) error {
|
func GetAppSettings(query *m.GetAppSettingsQuery) error {
|
||||||
sess := x.Where("org_id=?", query.OrgId)
|
sess := x.Where("org_id=?", query.OrgId)
|
||||||
|
|
||||||
query.Result = make([]*m.AppPlugin, 0)
|
query.Result = make([]*m.AppSettings, 0)
|
||||||
return sess.Find(&query.Result)
|
return sess.Find(&query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error {
|
func UpdateAppSettings(cmd *m.UpdateAppSettingsCmd) error {
|
||||||
return inTransaction2(func(sess *session) error {
|
return inTransaction2(func(sess *session) error {
|
||||||
var app m.AppPlugin
|
var app m.AppSettings
|
||||||
|
|
||||||
exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&app)
|
exists, err := sess.Where("org_id=? and app_id=?", cmd.OrgId, cmd.AppId).Get(&app)
|
||||||
sess.UseBool("enabled")
|
sess.UseBool("enabled")
|
||||||
sess.UseBool("pinned")
|
sess.UseBool("pinned")
|
||||||
if !exists {
|
if !exists {
|
||||||
app = m.AppPlugin{
|
app = m.AppSettings{
|
||||||
Type: cmd.Type,
|
AppId: cmd.AppId,
|
||||||
OrgId: cmd.OrgId,
|
OrgId: cmd.OrgId,
|
||||||
Enabled: cmd.Enabled,
|
Enabled: cmd.Enabled,
|
||||||
Pinned: cmd.Pinned,
|
Pinned: cmd.Pinned,
|
@ -2,14 +2,14 @@ package migrations
|
|||||||
|
|
||||||
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
|
|
||||||
func addAppPluginMigration(mg *Migrator) {
|
func addAppSettingsMigration(mg *Migrator) {
|
||||||
|
|
||||||
var appPluginV2 = Table{
|
appSettingsV1 := Table{
|
||||||
Name: "app_plugin",
|
Name: "app_settings",
|
||||||
Columns: []*Column{
|
Columns: []*Column{
|
||||||
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||||
{Name: "org_id", Type: DB_BigInt, Nullable: true},
|
{Name: "org_id", Type: DB_BigInt, Nullable: true},
|
||||||
{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
|
{Name: "app_id", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||||
{Name: "enabled", Type: DB_Bool, Nullable: false},
|
{Name: "enabled", Type: DB_Bool, Nullable: false},
|
||||||
{Name: "pinned", Type: DB_Bool, Nullable: false},
|
{Name: "pinned", Type: DB_Bool, Nullable: false},
|
||||||
{Name: "json_data", Type: DB_Text, Nullable: true},
|
{Name: "json_data", Type: DB_Text, Nullable: true},
|
||||||
@ -17,12 +17,12 @@ func addAppPluginMigration(mg *Migrator) {
|
|||||||
{Name: "updated", Type: DB_DateTime, Nullable: false},
|
{Name: "updated", Type: DB_DateTime, Nullable: false},
|
||||||
},
|
},
|
||||||
Indices: []*Index{
|
Indices: []*Index{
|
||||||
{Cols: []string{"org_id", "type"}, Type: UniqueIndex},
|
{Cols: []string{"org_id", "app_id"}, Type: UniqueIndex},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
mg.AddMigration("create app_plugin table v2", NewAddTableMigration(appPluginV2))
|
mg.AddMigration("create app_settings table v1", NewAddTableMigration(appSettingsV1))
|
||||||
|
|
||||||
//------- indexes ------------------
|
//------- indexes ------------------
|
||||||
addTableIndicesMigrations(mg, "v2", appPluginV2)
|
addTableIndicesMigrations(mg, "v3", appSettingsV1)
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ func AddMigrations(mg *Migrator) {
|
|||||||
addApiKeyMigrations(mg)
|
addApiKeyMigrations(mg)
|
||||||
addDashboardSnapshotMigrations(mg)
|
addDashboardSnapshotMigrations(mg)
|
||||||
addQuotaMigration(mg)
|
addQuotaMigration(mg)
|
||||||
addAppPluginMigration(mg)
|
addAppSettingsMigration(mg)
|
||||||
addSessionMigration(mg)
|
addSessionMigration(mg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ define([
|
|||||||
controllerAs: 'ctrl',
|
controllerAs: 'ctrl',
|
||||||
resolve: loadAppsBundle,
|
resolve: loadAppsBundle,
|
||||||
})
|
})
|
||||||
.when('/apps/edit/:type', {
|
.when('/apps/edit/:appId', {
|
||||||
templateUrl: 'app/features/apps/partials/edit.html',
|
templateUrl: 'app/features/apps/partials/edit.html',
|
||||||
controller: 'AppEditCtrl',
|
controller: 'AppEditCtrl',
|
||||||
controllerAs: 'ctrl',
|
controllerAs: 'ctrl',
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
import './edit_ctrl';
|
import './edit_ctrl';
|
||||||
import './list_ctrl';
|
import './list_ctrl';
|
||||||
import './app_srv';
|
|
||||||
|
@ -15,9 +15,6 @@ export class AppSrv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get(type) {
|
get(type) {
|
||||||
if (this.apps[type]) {
|
|
||||||
return this.$q.when(this.apps[type]);
|
|
||||||
}
|
|
||||||
return this.getAll().then(() => {
|
return this.getAll().then(() => {
|
||||||
return this.apps[type];
|
return this.apps[type];
|
||||||
});
|
});
|
||||||
@ -38,7 +35,7 @@ export class AppSrv {
|
|||||||
|
|
||||||
update(app) {
|
update(app) {
|
||||||
return this.backendSrv.post('api/org/apps', app).then(resp => {
|
return this.backendSrv.post('api/org/apps', app).then(resp => {
|
||||||
this.apps[app.type] = app;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,20 +8,36 @@ export class AppEditCtrl {
|
|||||||
appModel: any;
|
appModel: any;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private appSrv: any, private $routeParams: any) {}
|
constructor(private backendSrv: any, private $routeParams: any) {}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.appModel = {};
|
this.appModel = {};
|
||||||
this.appSrv.get(this.$routeParams.type).then(result => {
|
this.backendSrv.get(`/api/org/apps/${this.$routeParams.appId}/settings`).then(result => {
|
||||||
this.appModel = _.clone(result);
|
this.appModel = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update(options) {
|
||||||
this.appSrv.update(this.appModel).then(function() {
|
var updateCmd = _.extend({
|
||||||
window.location.href = config.appSubUrl + "org/apps";
|
appId: this.appModel.appId,
|
||||||
|
orgId: this.appModel.orgId,
|
||||||
|
enabled: this.appModel.enabled,
|
||||||
|
pinned: this.appModel.pinned,
|
||||||
|
jsonData: this.appModel.jsonData,
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
this.backendSrv.post(`/api/org/apps/${this.$routeParams.appId}/settings`, updateCmd).then(function() {
|
||||||
|
window.location.href = window.location.href;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleEnabled() {
|
||||||
|
this.update({enabled: this.appModel.enabled});
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePinned() {
|
||||||
|
this.update({pinned: this.appModel.pinned});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.module('grafana.controllers').controller('AppEditCtrl', AppEditCtrl);
|
angular.module('grafana.controllers').controller('AppEditCtrl', AppEditCtrl);
|
||||||
|
@ -7,11 +7,11 @@ export class AppListCtrl {
|
|||||||
apps: any[];
|
apps: any[];
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private appSrv: any) {}
|
constructor(private backendSrv: any) {}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.appSrv.getAll().then(result => {
|
this.backendSrv.get('api/org/apps').then(apps => {
|
||||||
this.apps = result;
|
this.apps = apps;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<topnav title="Apps" icon="fa fa-fw fa-cubes" subnav="true">
|
<topnav title="Apps" icon="fa fa-fw fa-cubes" subnav="true">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
<li ><a href="org/apps">Overview</a></li>
|
<li ><a href="apps">Overview</a></li>
|
||||||
<li class="active" ><a href="org/apps/edit/{{ctrl.current.type}}">Edit</a></li>
|
<li class="active" ><a href="apps/edit/{{ctrl.current.type}}">Edit</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</topnav>
|
</topnav>
|
||||||
|
|
||||||
@ -25,10 +25,12 @@
|
|||||||
<em>
|
<em>
|
||||||
{{ctrl.appModel.info.description}}
|
{{ctrl.appModel.info.description}}
|
||||||
</em>
|
</em>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<div class="form-inline">
|
<div class="form-inline">
|
||||||
<editor-checkbox text="Enabled" model="ctrl.appModel.enabled" change="enabledChanged()"></editor-checkbox>
|
<editor-checkbox text="Enabled" model="ctrl.appModel.enabled" change="ctrl.toggleEnabled()"></editor-checkbox>
|
||||||
<editor-checkbox text="Pinned" model="ctrl.appModel.pinned" change="enabledChanged()"></editor-checkbox>
|
|
||||||
|
<editor-checkbox text="Pinned" model="ctrl.appModel.pinned" change="ctrl.togglePinned()"></editor-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-config-loader></app-config-loader>
|
<app-config-loader></app-config-loader>
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
<ul class="filter-list">
|
<ul class="filter-list">
|
||||||
<li ng-repeat="app in ctrl.apps">
|
<li ng-repeat="app in ctrl.apps">
|
||||||
<ul class="filter-list-card">
|
<ul class="filter-list-card">
|
||||||
|
<li class="filter-list-card-image">
|
||||||
|
<img src="{{app.info.logos.small}}">
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div class="filter-list-card-controls">
|
<div class="filter-list-card-controls">
|
||||||
<div class="filter-list-card-config">
|
<div class="filter-list-card-config">
|
||||||
<a href="apps/edit/{{app.type}}">
|
<a href="apps/edit/{{app.appId}}">
|
||||||
<i class="fa fa-cog"></i>
|
<i class="fa fa-cog"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,6 +52,12 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-list-card-image {
|
||||||
|
width: 50px;
|
||||||
|
padding: 5px 50px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.filter-list-card-status {
|
.filter-list-card-status {
|
||||||
color: #777;
|
color: #777;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -33,6 +33,9 @@ module.exports = function(config, grunt) {
|
|||||||
grunt.config(option, result);
|
grunt.config(option, result);
|
||||||
grunt.task.run('typescript:build');
|
grunt.task.run('typescript:build');
|
||||||
grunt.task.run('tslint');
|
grunt.task.run('tslint');
|
||||||
|
// copy ts file also used by source maps
|
||||||
|
newPath = filepath.replace(/^public/, 'public_gen');
|
||||||
|
grunt.file.copy(filepath, newPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user