From c35b51a26821201200ae0bbecb6d1e983617ddc4 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Thu, 17 Dec 2015 23:53:58 +0800 Subject: [PATCH 01/36] refactor. Rename externalPlugin to apiPlugin Rename bundle to app Move js, css, menuItem and staticRoot to be properties os App Add "app" field to panel, datasource and api plugin models. If populated then the plugin is only enabled if the specific app is enabled for the Org. If app is "", then the plugin is enabled for all orgs and can't be disabled. --- pkg/api/api.go | 6 +- pkg/api/{externalplugin.go => api_plugin.go} | 14 +- pkg/api/app_plugin.go | 65 ++++++++++ pkg/api/datasources.go | 9 +- .../dtos/{plugin_bundle.go => app_plugin.go} | 2 +- pkg/api/frontendsettings.go | 6 +- pkg/api/index.go | 8 +- pkg/api/plugin_bundle.go | 65 ---------- .../{plugin_bundle.go => app_plugin.go} | 8 +- pkg/plugins/models.go | 46 ++++--- pkg/plugins/plugins.go | 122 ++++++++++++------ .../{plugin_bundle.go => app_plugin.go} | 24 ++-- .../{plugin_bundle.go => app_plugin.go} | 10 +- .../sqlstore/migrations/migrations.go | 2 +- public/app/plugins/plugin.json | 9 -- 15 files changed, 215 insertions(+), 181 deletions(-) rename pkg/api/{externalplugin.go => api_plugin.go} (81%) create mode 100644 pkg/api/app_plugin.go rename pkg/api/dtos/{plugin_bundle.go => app_plugin.go} (88%) delete mode 100644 pkg/api/plugin_bundle.go rename pkg/models/{plugin_bundle.go => app_plugin.go} (80%) rename pkg/services/sqlstore/{plugin_bundle.go => app_plugin.go} (55%) rename pkg/services/sqlstore/migrations/{plugin_bundle.go => app_plugin.go} (73%) delete mode 100644 public/app/plugins/plugin.json diff --git a/pkg/api/api.go b/pkg/api/api.go index 0c14f45778f..4092ff8a826 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -157,8 +157,8 @@ func Register(r *macaron.Macaron) { // PluginBundles r.Group("/plugins", func() { - r.Get("/", wrap(GetPluginBundles)) - r.Post("/", bind(m.UpdatePluginBundleCmd{}), wrap(UpdatePluginBundle)) + r.Get("/", wrap(GetAppPlugins)) + r.Post("/", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin)) }, reqOrgAdmin) r.Get("/frontend/settings/", GetFrontendSettings) @@ -196,7 +196,7 @@ func Register(r *macaron.Macaron) { // rendering r.Get("/render/*", reqSignedIn, RenderToPng) - InitExternalPluginRoutes(r) + InitApiPluginRoutes(r) r.NotFound(NotFoundHandler) } diff --git a/pkg/api/externalplugin.go b/pkg/api/api_plugin.go similarity index 81% rename from pkg/api/externalplugin.go rename to pkg/api/api_plugin.go index 331de160ec7..a368e9f1073 100644 --- a/pkg/api/externalplugin.go +++ b/pkg/api/api_plugin.go @@ -14,9 +14,9 @@ import ( "github.com/grafana/grafana/pkg/util" ) -func InitExternalPluginRoutes(r *macaron.Macaron) { - for _, plugin := range plugins.ExternalPlugins { - log.Info("Plugin: Adding proxy routes for backend plugin") +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) @@ -33,14 +33,14 @@ func InitExternalPluginRoutes(r *macaron.Macaron) { handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)) } } - handlers = append(handlers, ExternalPlugin(route.Url)) + handlers = append(handlers, ApiPlugin(route.Url)) r.Route(url, route.Method, handlers...) log.Info("Plugin: Adding route %s", url) } } } -func ExternalPlugin(routeUrl string) macaron.Handler { +func ApiPlugin(routeUrl string) macaron.Handler { return func(c *middleware.Context) { path := c.Params("*") @@ -51,13 +51,13 @@ func ExternalPlugin(routeUrl string) macaron.Handler { return } targetUrl, _ := url.Parse(routeUrl) - proxy := NewExternalPluginProxy(string(ctx), path, targetUrl) + proxy := NewApiPluginProxy(string(ctx), path, targetUrl) proxy.Transport = dataProxyTransport proxy.ServeHTTP(c.RW(), c.Req.Request) } } -func NewExternalPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy { +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 diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go new file mode 100644 index 00000000000..6ef078961d7 --- /dev/null +++ b/pkg/api/app_plugin.go @@ -0,0 +1,65 @@ +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) + } + + installedAppsMap := make(map[string]*dtos.AppPlugin) + for t, a := range plugins.Apps { + installedAppsMap[t] = &dtos.AppPlugin{ + Type: a.Type, + Enabled: a.Enabled, + Module: a.Module, + JsonData: make(map[string]interface{}), + } + } + + seenApps := make(map[string]bool) + + result := make([]*dtos.AppPlugin, 0) + for _, b := range query.Result { + if def, ok := installedAppsMap[b.Type]; ok { + result = append(result, &dtos.AppPlugin{ + Type: b.Type, + Enabled: b.Enabled, + Module: def.Module, + JsonData: b.JsonData, + }) + seenApps[b.Type] = true + } + } + + for t, a := range installedAppsMap { + if _, ok := seenApps[t]; !ok { + result = append(result, a) + } + } + + 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") +} diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index c6081af50ad..9f12330cd5e 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -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" @@ -114,14 +115,14 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) { } func GetDataSourcePlugins(c *middleware.Context) { - dsList := make(map[string]interface{}) + dsList := make(map[string]*plugins.DataSourcePlugin) - orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId} - err := bus.Dispatch(&orgBundles) + orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} + err := bus.Dispatch(&orgApps) if err != nil { c.JsonApiErr(500, "Failed to get org plugin Bundles", err) } - enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result) + enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) for key, value := range enabledPlugins.DataSourcePlugins { if !value.BuiltIn { diff --git a/pkg/api/dtos/plugin_bundle.go b/pkg/api/dtos/app_plugin.go similarity index 88% rename from pkg/api/dtos/plugin_bundle.go rename to pkg/api/dtos/app_plugin.go index f043da39904..1da1b8acd4e 100644 --- a/pkg/api/dtos/plugin_bundle.go +++ b/pkg/api/dtos/app_plugin.go @@ -1,6 +1,6 @@ package dtos -type PluginBundle struct { +type AppPlugin struct { Type string `json:"type"` Enabled bool `json:"enabled"` Module string `json:"module"` diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index a6b27327dfd..409196ed6c5 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -29,12 +29,12 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro datasources := make(map[string]interface{}) var defaultDatasource string - orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId} - err := bus.Dispatch(&orgBundles) + orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} + err := bus.Dispatch(&orgApps) if err != nil { return nil, err } - enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result) + enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) for _, ds := range orgDataSources { url := ds.Url diff --git a/pkg/api/index.go b/pkg/api/index.go index a4f5ac69928..bf79059281e 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -67,14 +67,14 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { }) } - orgBundles := m.GetPluginBundlesQuery{OrgId: c.OrgId} - err = bus.Dispatch(&orgBundles) + orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} + err = bus.Dispatch(&orgApps) if err != nil { return nil, err } - enabledPlugins := plugins.GetEnabledPlugins(orgBundles.Result) + enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) - for _, plugin := range enabledPlugins.ExternalPlugins { + for _, plugin := range enabledPlugins.AppPlugins { for _, js := range plugin.Js { data.PluginJs = append(data.PluginJs, js.Module) } diff --git a/pkg/api/plugin_bundle.go b/pkg/api/plugin_bundle.go deleted file mode 100644 index 9378189af7d..00000000000 --- a/pkg/api/plugin_bundle.go +++ /dev/null @@ -1,65 +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 GetPluginBundles(c *middleware.Context) Response { - query := m.GetPluginBundlesQuery{OrgId: c.OrgId} - - if err := bus.Dispatch(&query); err != nil { - return ApiError(500, "Failed to list Plugin Bundles", err) - } - - installedBundlesMap := make(map[string]*dtos.PluginBundle) - for t, b := range plugins.Bundles { - installedBundlesMap[t] = &dtos.PluginBundle{ - Type: b.Type, - Enabled: b.Enabled, - Module: b.Module, - JsonData: make(map[string]interface{}), - } - } - - seenBundles := make(map[string]bool) - - result := make([]*dtos.PluginBundle, 0) - for _, b := range query.Result { - if def, ok := installedBundlesMap[b.Type]; ok { - result = append(result, &dtos.PluginBundle{ - Type: b.Type, - Enabled: b.Enabled, - Module: def.Module, - JsonData: b.JsonData, - }) - seenBundles[b.Type] = true - } - } - - for t, b := range installedBundlesMap { - if _, ok := seenBundles[t]; !ok { - result = append(result, b) - } - } - - return Json(200, result) -} - -func UpdatePluginBundle(c *middleware.Context, cmd m.UpdatePluginBundleCmd) Response { - cmd.OrgId = c.OrgId - - if _, ok := plugins.Bundles[cmd.Type]; !ok { - return ApiError(404, "Bundle type not installed.", nil) - } - - err := bus.Dispatch(&cmd) - if err != nil { - return ApiError(500, "Failed to update plugin bundle", err) - } - - return ApiSuccess("Plugin updated") -} diff --git a/pkg/models/plugin_bundle.go b/pkg/models/app_plugin.go similarity index 80% rename from pkg/models/plugin_bundle.go rename to pkg/models/app_plugin.go index 5f4e508b9b2..605e69f623c 100644 --- a/pkg/models/plugin_bundle.go +++ b/pkg/models/app_plugin.go @@ -2,7 +2,7 @@ package models import "time" -type PluginBundle struct { +type AppPlugin struct { Id int64 Type string OrgId int64 @@ -17,7 +17,7 @@ type PluginBundle struct { // COMMANDS // Also acts as api DTO -type UpdatePluginBundleCmd struct { +type UpdateAppPluginCmd struct { Type string `json:"type" binding:"Required"` Enabled bool `json:"enabled"` JsonData map[string]interface{} `json:"jsonData"` @@ -28,7 +28,7 @@ type UpdatePluginBundleCmd struct { // --------------------- // QUERIES -type GetPluginBundlesQuery struct { +type GetAppPluginsQuery struct { OrgId int64 - Result []*PluginBundle + Result []*AppPlugin } diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 05b9492f4e5..e0eecd35bfe 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -12,6 +12,7 @@ type DataSourcePlugin struct { Annotations bool `json:"annotations"` Metrics bool `json:"metrics"` BuiltIn bool `json:"builtIn"` + App string `json:"app"` StaticRootConfig *StaticRootConfig `json:"staticRoot"` } @@ -20,6 +21,7 @@ type PanelPlugin struct { Name string `json:"name"` Module string `json:"module"` StaticRootConfig *StaticRootConfig `json:"staticRoot"` + App string `json:"app"` } type StaticRootConfig struct { @@ -27,59 +29,63 @@ type StaticRootConfig struct { Path string `json:"path"` } -type ExternalPluginRoute struct { +type ApiPluginRoute struct { Path string `json:"path"` Method string `json:"method"` ReqSignedIn bool `json:"reqSignedIn"` ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"` ReqRole models.RoleType `json:"reqRole"` Url string `json:"url"` + App string `json:"app"` } -type ExternalPluginJs struct { +type AppPluginJs struct { Module string `json:"module"` } -type ExternalPluginNavLink struct { +type AppPluginNavLink struct { Text string `json:"text"` Icon string `json:"icon"` Href string `json:"href"` ReqRole models.RoleType `json:"reqRole"` } -type ExternalPluginCss struct { +type AppPluginCss struct { Light string `json:"light"` Dark string `json:"dark"` } -type ExternalPlugin struct { - Type string `json:"type"` - Routes []*ExternalPluginRoute `json:"routes"` - Js []*ExternalPluginJs `json:"js"` - Css []*ExternalPluginCss `json:"css"` - MainNavLinks []*ExternalPluginNavLink `json:"mainNavLinks"` - StaticRootConfig *StaticRootConfig `json:"staticRoot"` +type ApiPlugin struct { + Type string `json:"type"` + Routes []*ApiPluginRoute `json:"routes"` + App string `json:"app"` } -type PluginBundle struct { - Type string `json:"type"` - Enabled bool `json:"enabled"` - PanelPlugins []string `json:"panelPlugins"` - DatasourcePlugins []string `json:"datasourcePlugins"` - ExternalPlugins []string `json:"externalPlugins"` - Module string `json:"module"` +type AppPlugin struct { + Type string `json:"type"` + Enabled bool `json:"enabled"` + PanelPlugins []string `json:"panelPlugins"` + DatasourcePlugins []string `json:"datasourcePlugins"` + ApiPlugins []string `json:"apiPlugins"` + Module string `json:"module"` + Js []*AppPluginJs `json:"js"` + Css []*AppPluginCss `json:"css"` + MainNavLinks []*AppPluginNavLink `json:"mainNavLinks"` + StaticRootConfig *StaticRootConfig `json:"staticRoot"` } type EnabledPlugins struct { PanelPlugins []*PanelPlugin DataSourcePlugins map[string]*DataSourcePlugin - ExternalPlugins []*ExternalPlugin + ApiPlugins []*ApiPlugin + AppPlugins []*AppPlugin } func NewEnabledPlugins() EnabledPlugins { return EnabledPlugins{ PanelPlugins: make([]*PanelPlugin, 0), DataSourcePlugins: make(map[string]*DataSourcePlugin), - ExternalPlugins: make([]*ExternalPlugin, 0), + ApiPlugins: make([]*ApiPlugin, 0), + AppPlugins: make([]*AppPlugin, 0), } } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 3e3a9d85152..5363c13c129 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -14,11 +14,11 @@ import ( ) var ( - DataSources map[string]DataSourcePlugin - Panels map[string]PanelPlugin - ExternalPlugins map[string]ExternalPlugin - StaticRoutes []*StaticRootConfig - Bundles map[string]PluginBundle + DataSources map[string]*DataSourcePlugin + Panels map[string]*PanelPlugin + ApiPlugins map[string]*ApiPlugin + StaticRoutes []*StaticRootConfig + Apps map[string]*AppPlugin ) type PluginScanner struct { @@ -27,39 +27,39 @@ type PluginScanner struct { } func Init() error { - DataSources = make(map[string]DataSourcePlugin) - ExternalPlugins = make(map[string]ExternalPlugin) + DataSources = make(map[string]*DataSourcePlugin) + ApiPlugins = make(map[string]*ApiPlugin) StaticRoutes = make([]*StaticRootConfig, 0) - Panels = make(map[string]PanelPlugin) - Bundles = make(map[string]PluginBundle) + Panels = make(map[string]*PanelPlugin) + Apps = make(map[string]*AppPlugin) scan(path.Join(setting.StaticRootPath, "app/plugins")) - checkExternalPluginPaths() + checkPluginPaths() checkDependencies() return nil } func checkDependencies() { - for bundleType, bundle := range Bundles { - for _, reqPanel := range bundle.PanelPlugins { + for appType, app := range Apps { + for _, reqPanel := range app.PanelPlugins { if _, ok := Panels[reqPanel]; !ok { - log.Fatal(4, "Bundle %s requires Panel type %s, but it is not present.", bundleType, reqPanel) + log.Fatal(4, "App %s requires Panel type %s, but it is not present.", appType, reqPanel) } } - for _, reqDataSource := range bundle.DatasourcePlugins { + for _, reqDataSource := range app.DatasourcePlugins { if _, ok := DataSources[reqDataSource]; !ok { - log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqDataSource) + log.Fatal(4, "App %s requires DataSource type %s, but it is not present.", appType, reqDataSource) } } - for _, reqExtPlugin := range bundle.ExternalPlugins { - if _, ok := ExternalPlugins[reqExtPlugin]; !ok { - log.Fatal(4, "Bundle %s requires DataSource type %s, but it is not present.", bundleType, reqExtPlugin) + for _, reqApiPlugin := range app.ApiPlugins { + if _, ok := ApiPlugins[reqApiPlugin]; !ok { + log.Fatal(4, "App %s requires ApiPlugin type %s, but it is not present.", appType, reqApiPlugin) } } } } -func checkExternalPluginPaths() error { +func checkPluginPaths() error { for _, section := range setting.Cfg.Sections() { if strings.HasPrefix(section.Name(), "plugin.") { path := section.Key("path").String() @@ -146,7 +146,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { return errors.New("Did not find type property in plugin.json") } - DataSources[p.Type] = p + DataSources[p.Type] = &p addStaticRoot(p.StaticRootConfig, currentDir) } @@ -161,12 +161,12 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { return errors.New("Did not find type property in plugin.json") } - Panels[p.Type] = p + Panels[p.Type] = &p addStaticRoot(p.StaticRootConfig, currentDir) } - if pluginType == "external" { - p := ExternalPlugin{} + if pluginType == "api" { + p := ApiPlugin{} reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err @@ -174,12 +174,11 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { if p.Type == "" { return errors.New("Did not find type property in plugin.json") } - ExternalPlugins[p.Type] = p - addStaticRoot(p.StaticRootConfig, currentDir) + ApiPlugins[p.Type] = &p } - if pluginType == "bundle" { - p := PluginBundle{} + if pluginType == "app" { + p := AppPlugin{} reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err @@ -187,44 +186,81 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { if p.Type == "" { return errors.New("Did not find type property in plugin.json") } - Bundles[p.Type] = p + Apps[p.Type] = &p + addStaticRoot(p.StaticRootConfig, currentDir) } return nil } -func GetEnabledPlugins(orgBundles []*models.PluginBundle) EnabledPlugins { +func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins { enabledPlugins := NewEnabledPlugins() - orgBundlesMap := make(map[string]*models.PluginBundle) - for _, orgBundle := range orgBundles { - orgBundlesMap[orgBundle.Type] = orgBundle + 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 bundleType, bundle := range Bundles { - enabled := bundle.Enabled - // check if the bundle is stored in the DB. - if b, ok := orgBundlesMap[bundleType]; ok { + for appType, app := range Apps { + // start with enabled set to the default state listed in the json config. + enabled := app.Enabled + + // check if the app is stored in the DB for this org and if so, use the + // enabled state stored there. + if b, ok := orgAppsMap[appType]; ok { enabled = b.Enabled } if enabled { - for _, d := range bundle.DatasourcePlugins { + for _, d := range app.DatasourcePlugins { if ds, ok := DataSources[d]; ok { - enabledPlugins.DataSourcePlugins[d] = &ds + enabledPlugins.DataSourcePlugins[d] = ds } } - for _, p := range bundle.PanelPlugins { + for _, p := range app.PanelPlugins { if panel, ok := Panels[p]; ok { - enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, &panel) + if _, ok := seenPanels[p]; !ok { + seenPanels[p] = true + enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel) + } } } - for _, e := range bundle.ExternalPlugins { - if external, ok := ExternalPlugins[e]; ok { - enabledPlugins.ExternalPlugins = append(enabledPlugins.ExternalPlugins, &external) + 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.DataSourcePlugins[d] = installedDs + } + } + for p, panel := range Panels { + if panel.App == "" { + if _, ok := seenPanels[p]; !ok { + seenPanels[p] = true + enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel) + } } } + for a, api := range ApiPlugins { + if api.App == "" { + if _, ok := seenApi[a]; !ok { + seenApi[a] = true + enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api) + } + } + } + return enabledPlugins } diff --git a/pkg/services/sqlstore/plugin_bundle.go b/pkg/services/sqlstore/app_plugin.go similarity index 55% rename from pkg/services/sqlstore/plugin_bundle.go rename to pkg/services/sqlstore/app_plugin.go index c15c263a100..fca6031cac5 100644 --- a/pkg/services/sqlstore/plugin_bundle.go +++ b/pkg/services/sqlstore/app_plugin.go @@ -8,25 +8,25 @@ import ( ) func init() { - bus.AddHandler("sql", GetPluginBundles) - bus.AddHandler("sql", UpdatePluginBundle) + bus.AddHandler("sql", GetAppPlugins) + bus.AddHandler("sql", UpdateAppPlugin) } -func GetPluginBundles(query *m.GetPluginBundlesQuery) error { +func GetAppPlugins(query *m.GetAppPluginsQuery) error { sess := x.Where("org_id=?", query.OrgId) - query.Result = make([]*m.PluginBundle, 0) + query.Result = make([]*m.AppPlugin, 0) return sess.Find(&query.Result) } -func UpdatePluginBundle(cmd *m.UpdatePluginBundleCmd) error { +func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error { return inTransaction2(func(sess *session) error { - var bundle m.PluginBundle + var app m.AppPlugin - exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&bundle) + exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&app) sess.UseBool("enabled") if !exists { - bundle = m.PluginBundle{ + app = m.AppPlugin{ Type: cmd.Type, OrgId: cmd.OrgId, Enabled: cmd.Enabled, @@ -34,12 +34,12 @@ func UpdatePluginBundle(cmd *m.UpdatePluginBundleCmd) error { Created: time.Now(), Updated: time.Now(), } - _, err = sess.Insert(&bundle) + _, err = sess.Insert(&app) return err } else { - bundle.Enabled = cmd.Enabled - bundle.JsonData = cmd.JsonData - _, err = sess.Id(bundle.Id).Update(&bundle) + app.Enabled = cmd.Enabled + app.JsonData = cmd.JsonData + _, err = sess.Id(app.Id).Update(&app) return err } }) diff --git a/pkg/services/sqlstore/migrations/plugin_bundle.go b/pkg/services/sqlstore/migrations/app_plugin.go similarity index 73% rename from pkg/services/sqlstore/migrations/plugin_bundle.go rename to pkg/services/sqlstore/migrations/app_plugin.go index b56ea74a13e..3fbadcd2a11 100644 --- a/pkg/services/sqlstore/migrations/plugin_bundle.go +++ b/pkg/services/sqlstore/migrations/app_plugin.go @@ -2,10 +2,10 @@ package migrations import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" -func addPluginBundleMigration(mg *Migrator) { +func addAppPluginMigration(mg *Migrator) { - var pluginBundleV1 = Table{ - Name: "plugin_bundle", + var appPluginV1 = Table{ + Name: "app_plugin", Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "org_id", Type: DB_BigInt, Nullable: true}, @@ -19,8 +19,8 @@ func addPluginBundleMigration(mg *Migrator) { {Cols: []string{"org_id", "type"}, Type: UniqueIndex}, }, } - mg.AddMigration("create plugin_bundle table v1", NewAddTableMigration(pluginBundleV1)) + mg.AddMigration("create app_plugin table v1", NewAddTableMigration(appPluginV1)) //------- indexes ------------------ - addTableIndicesMigrations(mg, "v1", pluginBundleV1) + addTableIndicesMigrations(mg, "v1", appPluginV1) } diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 569d26282ed..0194c69b0fd 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -18,7 +18,7 @@ func AddMigrations(mg *Migrator) { addApiKeyMigrations(mg) addDashboardSnapshotMigrations(mg) addQuotaMigration(mg) - addPluginBundleMigration(mg) + addAppPluginMigration(mg) } func addMigrationLogMigrations(mg *Migrator) { diff --git a/public/app/plugins/plugin.json b/public/app/plugins/plugin.json deleted file mode 100644 index d7356c7b8ad..00000000000 --- a/public/app/plugins/plugin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "pluginType": "bundle", - "type": "core", - "module": "", - "enabled": true, - "panelPlugins": ["graph", "singlestat", "text", "dashlist", "table"], - "datasourcePlugins": ["mixed", "grafana", "graphite", "cloudwatch", "elasticsearch", "influxdb", "influxdb_08", "kairosdb", "opentsdb", "prometheus"], - "externalPlugins": [] -} From 42db1378e0997a8ecf357e74e3559acb64165c12 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Thu, 17 Dec 2015 23:59:01 +0800 Subject: [PATCH 02/36] rename app config directive to grafana-app-* --- public/app/features/org/partials/appConfigCore.html | 3 +++ public/app/features/org/partials/pluginConfigCore.html | 3 --- public/app/features/org/plugin_directive.js | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 public/app/features/org/partials/appConfigCore.html delete mode 100644 public/app/features/org/partials/pluginConfigCore.html diff --git a/public/app/features/org/partials/appConfigCore.html b/public/app/features/org/partials/appConfigCore.html new file mode 100644 index 00000000000..8435f39d07b --- /dev/null +++ b/public/app/features/org/partials/appConfigCore.html @@ -0,0 +1,3 @@ +
+{{current.type}} app does not have any additional config. +
diff --git a/public/app/features/org/partials/pluginConfigCore.html b/public/app/features/org/partials/pluginConfigCore.html deleted file mode 100644 index 1b13b46d0e5..00000000000 --- a/public/app/features/org/partials/pluginConfigCore.html +++ /dev/null @@ -1,3 +0,0 @@ -
-{{current.type}} plugin does not have any additional config. -
diff --git a/public/app/features/org/plugin_directive.js b/public/app/features/org/plugin_directive.js index 6fd30730264..845a60aaa3a 100644 --- a/public/app/features/org/plugin_directive.js +++ b/public/app/features/org/plugin_directive.js @@ -10,12 +10,12 @@ function (angular) { return { restrict: 'E', link: function(scope, elem) { - var directive = 'grafana-plugin-core'; + var directive = 'grafana-app-core'; //wait for the parent scope to be applied. scope.$watch("current", function(newVal) { if (newVal) { if (newVal.module) { - directive = 'grafana-plugin-'+newVal.type; + directive = 'grafana-app-'+newVal.type; } scope.require([newVal.module], function () { var panelEl = angular.element(document.createElement(directive)); @@ -28,10 +28,10 @@ function (angular) { }; }); - module.directive('grafanaPluginCore', function() { + module.directive('grafanaAppCore', function() { return { restrict: 'E', - templateUrl: 'app/features/org/partials/pluginConfigCore.html', + templateUrl: 'app/features/org/partials/appConfigCore.html', transclude: true, link: function(scope) { scope.update = function() { From 48cf56b69aec5bc90740483966a84f1f5ea15708 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Fri, 18 Dec 2015 13:46:40 +0800 Subject: [PATCH 03/36] more renaming. also moved apps and datasource menus --- pkg/api/api.go | 14 ++--- pkg/api/index.go | 12 ---- public/app/core/controllers/sidemenu_ctrl.js | 8 +++ public/app/core/routes/all.js | 12 ++-- public/app/features/org/all.js | 8 +-- .../org/{pluginEditCtrl.js => appEditCtrl.js} | 10 ++-- public/app/features/org/app_directive.js | 32 ++++++++++ public/app/features/org/app_srv.js | 58 +++++++++++++++++++ public/app/features/org/appsCtrl.js | 32 ++++++++++ .../features/org/partials/appConfigCore.html | 3 - .../{pluginEdit.html => appEdit.html} | 10 ++-- .../org/partials/{plugins.html => apps.html} | 12 ++-- public/app/features/org/plugin_directive.js | 47 --------------- public/app/features/org/plugin_srv.js | 58 ------------------- public/app/features/org/pluginsCtrl.js | 33 ----------- public/app/plugins/panels/text/module.js | 1 - 16 files changed, 162 insertions(+), 188 deletions(-) rename public/app/features/org/{pluginEditCtrl.js => appEditCtrl.js} (65%) create mode 100644 public/app/features/org/app_directive.js create mode 100644 public/app/features/org/app_srv.js create mode 100644 public/app/features/org/appsCtrl.js delete mode 100644 public/app/features/org/partials/appConfigCore.html rename public/app/features/org/partials/{pluginEdit.html => appEdit.html} (78%) rename public/app/features/org/partials/{plugins.html => apps.html} (70%) delete mode 100644 public/app/features/org/plugin_directive.js delete mode 100644 public/app/features/org/plugin_srv.js delete mode 100644 public/app/features/org/pluginsCtrl.js diff --git a/pkg/api/api.go b/pkg/api/api.go index 4092ff8a826..f4946a19cb6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -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("/org/apps", reqSignedIn, Index) + r.Get("/org/apps/edit/*", reqSignedIn, Index) r.Get("/dashboard/*", reqSignedIn, Index) r.Get("/dashboard-solo/*", reqSignedIn, Index) @@ -116,6 +116,10 @@ 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(GetAppPlugins)) + r.Post("/apps", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin)) }, reqOrgAdmin) // create new org @@ -155,12 +159,6 @@ func Register(r *macaron.Macaron) { r.Get("/plugins", GetDataSourcePlugins) }, reqOrgAdmin) - // PluginBundles - r.Group("/plugins", func() { - r.Get("/", wrap(GetAppPlugins)) - r.Post("/", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin)) - }, reqOrgAdmin) - r.Get("/frontend/settings/", GetFrontendSettings) r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest) diff --git a/pkg/api/index.go b/pkg/api/index.go index bf79059281e..8caa709b0be 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -55,18 +55,6 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Href: "/", }) - if c.OrgRole == m.ROLE_ADMIN { - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: "Data Sources", - Icon: "fa fa-fw fa-database", - Href: "/datasources", - }, &dtos.NavLink{ - Text: "Plugins", - Icon: "fa fa-fw fa-cubes", - Href: "/plugins", - }) - } - orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} err = bus.Dispatch(&orgApps) if err != nil { diff --git a/public/app/core/controllers/sidemenu_ctrl.js b/public/app/core/controllers/sidemenu_ctrl.js index a2885674d34..93e1afd151b 100644 --- a/public/app/core/controllers/sidemenu_ctrl.js +++ b/public/app/core/controllers/sidemenu_ctrl.js @@ -40,6 +40,14 @@ function (angular, _, $, coreModule, config) { text: "API Keys", href: $scope.getUrl("/org/apikeys"), }); + $scope.orgMenu.push({ + text: "Datasources", + href: $scope.getUrl("/datasources"), + }); + $scope.orgMenu.push({ + text: "Apps", + href: $scope.getUrl("/org/apps"), + }); } if ($scope.orgMenu.length > 0) { diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index fd029a27939..5b0939d133b 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -131,14 +131,14 @@ define([ templateUrl: 'app/partials/reset_password.html', controller : 'ResetPasswordCtrl', }) - .when('/plugins', { - templateUrl: 'app/features/org/partials/plugins.html', - controller: 'PluginsCtrl', + .when('/org/apps', { + templateUrl: 'app/features/org/partials/apps.html', + controller: 'AppsCtrl', resolve: loadOrgBundle, }) - .when('/plugins/edit/:type', { - templateUrl: 'app/features/org/partials/pluginEdit.html', - controller: 'PluginEditCtrl', + .when('/org/apps/edit/:type', { + templateUrl: 'app/features/org/partials/appEdit.html', + controller: 'AppEditCtrl', resolve: loadOrgBundle, }) .otherwise({ diff --git a/public/app/features/org/all.js b/public/app/features/org/all.js index be9668e33de..3c9e0a4453c 100644 --- a/public/app/features/org/all.js +++ b/public/app/features/org/all.js @@ -6,8 +6,8 @@ define([ './userInviteCtrl', './orgApiKeysCtrl', './orgDetailsCtrl', - './pluginsCtrl', - './pluginEditCtrl', - './plugin_srv', - './plugin_directive', + './appsCtrl', + './appEditCtrl', + './app_srv', + './app_directive', ], function () {}); diff --git a/public/app/features/org/pluginEditCtrl.js b/public/app/features/org/appEditCtrl.js similarity index 65% rename from public/app/features/org/pluginEditCtrl.js rename to public/app/features/org/appEditCtrl.js index b4ba2c05653..8d4bb80dea9 100644 --- a/public/app/features/org/pluginEditCtrl.js +++ b/public/app/features/org/appEditCtrl.js @@ -8,14 +8,14 @@ function (angular, _, config) { var module = angular.module('grafana.controllers'); - module.controller('PluginEditCtrl', function($scope, pluginSrv, $routeParams) { + module.controller('AppEditCtrl', function($scope, appSrv, $routeParams) { $scope.init = function() { $scope.current = {}; - $scope.getPlugins(); + $scope.getApps(); }; - $scope.getPlugins = function() { - pluginSrv.get($routeParams.type).then(function(result) { + $scope.getApps = function() { + appSrv.get($routeParams.type).then(function(result) { $scope.current = _.clone(result); }); }; @@ -25,7 +25,7 @@ function (angular, _, config) { }; $scope._update = function() { - pluginSrv.update($scope.current).then(function() { + appSrv.update($scope.current).then(function() { window.location.href = config.appSubUrl + "plugins"; }); }; diff --git a/public/app/features/org/app_directive.js b/public/app/features/org/app_directive.js new file mode 100644 index 00000000000..c58464f8075 --- /dev/null +++ b/public/app/features/org/app_directive.js @@ -0,0 +1,32 @@ +define([ + 'angular', +], +function (angular) { + 'use strict'; + + var module = angular.module('grafana.directives'); + + module.directive('appConfigLoader', function($compile) { + return { + restrict: 'E', + link: function(scope, elem) { + var directive = 'grafana-app-default'; + //wait for the parent scope to be applied. + scope.panelAdded = false; + scope.$watch("current", function(newVal) { + if (newVal && !scope.panelAdded) { + if (newVal.module) { + scope.panelAdded = true; + directive = 'grafana-app-'+newVal.type; + scope.require([newVal.module], function () { + var panelEl = angular.element(document.createElement(directive)); + elem.append(panelEl); + $compile(panelEl)(scope); + }); + } + } + }); + } + }; + }); +}); \ No newline at end of file diff --git a/public/app/features/org/app_srv.js b/public/app/features/org/app_srv.js new file mode 100644 index 00000000000..f88f17eaff8 --- /dev/null +++ b/public/app/features/org/app_srv.js @@ -0,0 +1,58 @@ +define([ + 'angular', + 'lodash', +], +function (angular, _) { + 'use strict'; + + var module = angular.module('grafana.services'); + + module.service('appSrv', function($rootScope, $timeout, $q, backendSrv) { + var self = this; + this.init = function() { + console.log("appSrv init"); + this.apps = {}; + }; + + this.get = function(type) { + return $q(function(resolve) { + if (type in self.apps) { + return resolve(self.apps[type]); + } + backendSrv.get('api/org/apps').then(function(results) { + _.forEach(results, function(p) { + self.apps[p.type] = p; + }); + return resolve(self.apps[type]); + }); + }); + }; + + this.getAll = function() { + return $q(function(resolve) { + if (!_.isEmpty(self.apps)) { + return resolve(self.apps); + } + backendSrv.get('api/org/apps').then(function(results) { + _.forEach(results, function(p) { + self.apps[p.type] = p; + }); + return resolve(self.apps); + }); + }); + }; + + this.update = function(app) { + return $q(function(resolve, reject) { + backendSrv.post('api/org/apps', app).then(function(resp) { + self.apps[app.type] = app; + resolve(resp); + }, function(resp) { + reject(resp); + }); + }); + }; + + this.init(); + }); +}); diff --git a/public/app/features/org/appsCtrl.js b/public/app/features/org/appsCtrl.js new file mode 100644 index 00000000000..47e6dfcc5d4 --- /dev/null +++ b/public/app/features/org/appsCtrl.js @@ -0,0 +1,32 @@ +define([ + 'angular', + 'app/core/config', +], +function (angular, config) { + 'use strict'; + + var module = angular.module('grafana.controllers'); + + module.controller('AppsCtrl', function($scope, $location, appSrv) { + + $scope.init = function() { + $scope.apps = {}; + $scope.getApps(); + }; + + $scope.getApps = function() { + appSrv.getAll().then(function(result) { + $scope.apps = result; + }); + }; + + $scope.update = function(app) { + appSrv.update(app).then(function() { + window.location.href = config.appSubUrl + $location.path(); + }); + }; + + $scope.init(); + + }); +}); \ No newline at end of file diff --git a/public/app/features/org/partials/appConfigCore.html b/public/app/features/org/partials/appConfigCore.html deleted file mode 100644 index 8435f39d07b..00000000000 --- a/public/app/features/org/partials/appConfigCore.html +++ /dev/null @@ -1,3 +0,0 @@ -
-{{current.type}} app does not have any additional config. -
diff --git a/public/app/features/org/partials/pluginEdit.html b/public/app/features/org/partials/appEdit.html similarity index 78% rename from public/app/features/org/partials/pluginEdit.html rename to public/app/features/org/partials/appEdit.html index 9276fce277c..1af3af51182 100644 --- a/public/app/features/org/partials/pluginEdit.html +++ b/public/app/features/org/partials/appEdit.html @@ -1,13 +1,13 @@
-

Edit Plugin

+

Edit App

@@ -30,10 +30,10 @@

- +
- Cancel + Cancel

diff --git a/public/app/features/org/partials/plugins.html b/public/app/features/org/partials/apps.html similarity index 70% rename from public/app/features/org/partials/plugins.html rename to public/app/features/org/partials/apps.html index 97949649094..cd662416302 100644 --- a/public/app/features/org/partials/plugins.html +++ b/public/app/features/org/partials/apps.html @@ -1,6 +1,6 @@ @@ -8,23 +8,23 @@

Plugins

-
- No plugins defined +
+ No apps defined
- +
- +
Type
  {{p.type}} - + Edit diff --git a/public/app/features/org/plugin_directive.js b/public/app/features/org/plugin_directive.js deleted file mode 100644 index 845a60aaa3a..00000000000 --- a/public/app/features/org/plugin_directive.js +++ /dev/null @@ -1,47 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.directives'); - - module.directive('pluginConfigLoader', function($compile) { - return { - restrict: 'E', - link: function(scope, elem) { - var directive = 'grafana-app-core'; - //wait for the parent scope to be applied. - scope.$watch("current", function(newVal) { - if (newVal) { - if (newVal.module) { - directive = 'grafana-app-'+newVal.type; - } - scope.require([newVal.module], function () { - var panelEl = angular.element(document.createElement(directive)); - elem.append(panelEl); - $compile(panelEl)(scope); - }); - } - }); - } - }; - }); - - module.directive('grafanaAppCore', function() { - return { - restrict: 'E', - templateUrl: 'app/features/org/partials/appConfigCore.html', - transclude: true, - link: function(scope) { - scope.update = function() { - //Perform custom save events to the plugins own backend if needed. - - // call parent update to commit the change to the plugin object. - // this will cause the page to reload. - scope._update(); - }; - } - }; - }); -}); \ No newline at end of file diff --git a/public/app/features/org/plugin_srv.js b/public/app/features/org/plugin_srv.js deleted file mode 100644 index 863828c7659..00000000000 --- a/public/app/features/org/plugin_srv.js +++ /dev/null @@ -1,58 +0,0 @@ -define([ - 'angular', - 'lodash', -], -function (angular, _) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.service('pluginSrv', function($rootScope, $timeout, $q, backendSrv) { - var self = this; - this.init = function() { - console.log("pluginSrv init"); - this.plugins = {}; - }; - - this.get = function(type) { - return $q(function(resolve) { - if (type in self.plugins) { - return resolve(self.plugins[type]); - } - backendSrv.get('/api/plugins').then(function(results) { - _.forEach(results, function(p) { - self.plugins[p.type] = p; - }); - return resolve(self.plugins[type]); - }); - }); - }; - - this.getAll = function() { - return $q(function(resolve) { - if (!_.isEmpty(self.plugins)) { - return resolve(self.plugins); - } - backendSrv.get('api/plugins').then(function(results) { - _.forEach(results, function(p) { - self.plugins[p.type] = p; - }); - return resolve(self.plugins); - }); - }); - }; - - this.update = function(plugin) { - return $q(function(resolve, reject) { - backendSrv.post('/api/plugins', plugin).then(function(resp) { - self.plugins[plugin.type] = plugin; - resolve(resp); - }, function(resp) { - reject(resp); - }); - }); - }; - - this.init(); - }); -}); diff --git a/public/app/features/org/pluginsCtrl.js b/public/app/features/org/pluginsCtrl.js deleted file mode 100644 index 49dc104a840..00000000000 --- a/public/app/features/org/pluginsCtrl.js +++ /dev/null @@ -1,33 +0,0 @@ -define([ - 'angular', - 'app/core/config', -], -function (angular, config) { - 'use strict'; - - var module = angular.module('grafana.controllers'); - - module.controller('PluginsCtrl', function($scope, $location, pluginSrv) { - - $scope.init = function() { - $scope.plugins = {}; - $scope.getPlugins(); - }; - - $scope.getPlugins = function() { - pluginSrv.getAll().then(function(result) { - console.log(result); - $scope.plugins = result; - }); - }; - - $scope.update = function(plugin) { - pluginSrv.update(plugin).then(function() { - window.location.href = config.appSubUrl + $location.path(); - }); - }; - - $scope.init(); - - }); -}); \ No newline at end of file diff --git a/public/app/plugins/panels/text/module.js b/public/app/plugins/panels/text/module.js index 145b3be9b0c..bb3c5faae03 100644 --- a/public/app/plugins/panels/text/module.js +++ b/public/app/plugins/panels/text/module.js @@ -98,7 +98,6 @@ function (angular, app, _, require, PanelMeta) { console.log('Text panel error: ', e); $scope.content = $sce.trustAsHtml(html); } - if(!$scope.$$phase) { $scope.$digest(); } From 3d15ee6d7430a1c02966d748c7b9509465178be1 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Fri, 18 Dec 2015 15:10:52 +0800 Subject: [PATCH 04/36] allow app menu items to be selectivly pinned to the left nav menu --- pkg/api/app_plugin.go | 18 ++++---- pkg/api/dtos/app_plugin.go | 9 ++-- pkg/api/index.go | 43 ++++++++++--------- pkg/models/app_plugin.go | 18 ++++---- pkg/plugins/models.go | 1 + pkg/plugins/plugins.go | 15 ++++--- pkg/services/sqlstore/app_plugin.go | 15 ++++--- .../sqlstore/migrations/app_plugin.go | 1 + public/app/features/org/appEditCtrl.js | 2 +- public/app/features/org/partials/appEdit.html | 5 +++ 10 files changed, 73 insertions(+), 54 deletions(-) diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go index 6ef078961d7..c39acb4dba4 100644 --- a/pkg/api/app_plugin.go +++ b/pkg/api/app_plugin.go @@ -18,10 +18,11 @@ func GetAppPlugins(c *middleware.Context) Response { installedAppsMap := make(map[string]*dtos.AppPlugin) for t, a := range plugins.Apps { installedAppsMap[t] = &dtos.AppPlugin{ - Type: a.Type, - Enabled: a.Enabled, - Module: a.Module, - JsonData: make(map[string]interface{}), + Type: a.Type, + Enabled: a.Enabled, + PinNavLinks: a.PinNavLinks, + Module: a.Module, + JsonData: make(map[string]interface{}), } } @@ -31,10 +32,11 @@ func GetAppPlugins(c *middleware.Context) Response { for _, b := range query.Result { if def, ok := installedAppsMap[b.Type]; ok { result = append(result, &dtos.AppPlugin{ - Type: b.Type, - Enabled: b.Enabled, - Module: def.Module, - JsonData: b.JsonData, + Type: b.Type, + Enabled: b.Enabled, + PinNavLinks: b.PinNavLinks, + Module: def.Module, + JsonData: b.JsonData, }) seenApps[b.Type] = true } diff --git a/pkg/api/dtos/app_plugin.go b/pkg/api/dtos/app_plugin.go index 1da1b8acd4e..d7eaf8f4140 100644 --- a/pkg/api/dtos/app_plugin.go +++ b/pkg/api/dtos/app_plugin.go @@ -1,8 +1,9 @@ package dtos type AppPlugin struct { - Type string `json:"type"` - Enabled bool `json:"enabled"` - Module string `json:"module"` - JsonData map[string]interface{} `json:"jsonData"` + Type string `json:"type"` + Enabled bool `json:"enabled"` + PinNavLinks bool `json:"pin_nav_links"` + Module string `json:"module"` + JsonData map[string]interface{} `json:"jsonData"` } diff --git a/pkg/api/index.go b/pkg/api/index.go index 8caa709b0be..1346a45a7ac 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -69,28 +69,31 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { for _, css := range plugin.Css { data.PluginCss = append(data.PluginCss, &dtos.PluginCss{Light: css.Light, Dark: css.Dark}) } - for _, item := range plugin.MainNavLinks { - // only show menu items for the specified roles. - var validRoles []m.RoleType - if string(item.ReqRole) == "" || item.ReqRole == m.ROLE_VIEWER { - validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR, m.ROLE_VIEWER} - } else if item.ReqRole == m.ROLE_EDITOR { - validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR} - } else if item.ReqRole == m.ROLE_ADMIN { - validRoles = []m.RoleType{m.ROLE_ADMIN} - } - ok := true - if len(validRoles) > 0 { - ok = false - for _, role := range validRoles { - if role == c.OrgRole { - ok = true - break + + if plugin.PinNavLinks { + for _, item := range plugin.MainNavLinks { + // only show menu items for the specified roles. + var validRoles []m.RoleType + if string(item.ReqRole) == "" || item.ReqRole == m.ROLE_VIEWER { + validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR, m.ROLE_VIEWER} + } else if item.ReqRole == m.ROLE_EDITOR { + validRoles = []m.RoleType{m.ROLE_ADMIN, m.ROLE_EDITOR} + } else if item.ReqRole == m.ROLE_ADMIN { + validRoles = []m.RoleType{m.ROLE_ADMIN} + } + ok := true + if len(validRoles) > 0 { + ok = false + for _, role := range validRoles { + if role == c.OrgRole { + ok = true + break + } } } - } - if ok { - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{Text: item.Text, Href: item.Href, Icon: item.Icon}) + if ok { + data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{Text: item.Text, Href: item.Href, Icon: item.Icon}) + } } } } diff --git a/pkg/models/app_plugin.go b/pkg/models/app_plugin.go index 605e69f623c..fc155035f84 100644 --- a/pkg/models/app_plugin.go +++ b/pkg/models/app_plugin.go @@ -3,11 +3,12 @@ package models import "time" type AppPlugin struct { - Id int64 - Type string - OrgId int64 - Enabled bool - JsonData map[string]interface{} + Id int64 + Type string + OrgId int64 + Enabled bool + PinNavLinks bool + JsonData map[string]interface{} Created time.Time Updated time.Time @@ -18,9 +19,10 @@ type AppPlugin struct { // Also acts as api DTO type UpdateAppPluginCmd struct { - Type string `json:"type" binding:"Required"` - Enabled bool `json:"enabled"` - JsonData map[string]interface{} `json:"jsonData"` + Type string `json:"type" binding:"Required"` + Enabled bool `json:"enabled"` + PinNavLinks bool `json:"pin_nav_links"` + JsonData map[string]interface{} `json:"jsonData"` Id int64 `json:"-"` OrgId int64 `json:"-"` diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index e0eecd35bfe..1e040a37748 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -71,6 +71,7 @@ type AppPlugin struct { Js []*AppPluginJs `json:"js"` Css []*AppPluginCss `json:"css"` MainNavLinks []*AppPluginNavLink `json:"mainNavLinks"` + PinNavLinks bool `json:"pinNavLinks"` StaticRootConfig *StaticRootConfig `json:"staticRoot"` } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 5363c13c129..01feace9d44 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -203,17 +203,18 @@ func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins { seenPanels := make(map[string]bool) seenApi := make(map[string]bool) - for appType, app := range Apps { - // start with enabled set to the default state listed in the json config. - enabled := app.Enabled + 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 - // enabled state stored there. + // state stored there. if b, ok := orgAppsMap[appType]; ok { - enabled = b.Enabled + app.Enabled = b.Enabled + app.PinNavLinks = b.PinNavLinks } - if enabled { + if app.Enabled { for _, d := range app.DatasourcePlugins { if ds, ok := DataSources[d]; ok { enabledPlugins.DataSourcePlugins[d] = ds @@ -235,7 +236,7 @@ func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins { } } } - enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, app) + enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, &app) } } diff --git a/pkg/services/sqlstore/app_plugin.go b/pkg/services/sqlstore/app_plugin.go index fca6031cac5..63fdcac0d8c 100644 --- a/pkg/services/sqlstore/app_plugin.go +++ b/pkg/services/sqlstore/app_plugin.go @@ -25,20 +25,23 @@ func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error { exists, err := sess.Where("org_id=? and type=?", cmd.OrgId, cmd.Type).Get(&app) sess.UseBool("enabled") + sess.UseBool("pin_nav_links") if !exists { app = m.AppPlugin{ - Type: cmd.Type, - OrgId: cmd.OrgId, - Enabled: cmd.Enabled, - JsonData: cmd.JsonData, - Created: time.Now(), - Updated: time.Now(), + Type: cmd.Type, + OrgId: cmd.OrgId, + Enabled: cmd.Enabled, + PinNavLinks: cmd.PinNavLinks, + JsonData: cmd.JsonData, + Created: time.Now(), + Updated: time.Now(), } _, err = sess.Insert(&app) return err } else { app.Enabled = cmd.Enabled app.JsonData = cmd.JsonData + app.PinNavLinks = cmd.PinNavLinks _, err = sess.Id(app.Id).Update(&app) return err } diff --git a/pkg/services/sqlstore/migrations/app_plugin.go b/pkg/services/sqlstore/migrations/app_plugin.go index 3fbadcd2a11..a0208f0eac5 100644 --- a/pkg/services/sqlstore/migrations/app_plugin.go +++ b/pkg/services/sqlstore/migrations/app_plugin.go @@ -11,6 +11,7 @@ func addAppPluginMigration(mg *Migrator) { {Name: "org_id", Type: DB_BigInt, Nullable: true}, {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "enabled", Type: DB_Bool, Nullable: false}, + {Name: "pin_nav_links", Type: DB_Bool, Nullable: false}, {Name: "json_data", Type: DB_Text, Nullable: true}, {Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false}, diff --git a/public/app/features/org/appEditCtrl.js b/public/app/features/org/appEditCtrl.js index 8d4bb80dea9..63f638a72fd 100644 --- a/public/app/features/org/appEditCtrl.js +++ b/public/app/features/org/appEditCtrl.js @@ -26,7 +26,7 @@ function (angular, _, config) { $scope._update = function() { appSrv.update($scope.current).then(function() { - window.location.href = config.appSubUrl + "plugins"; + window.location.href = config.appSubUrl + "org/apps"; }); }; diff --git a/public/app/features/org/partials/appEdit.html b/public/app/features/org/partials/appEdit.html index 1af3af51182..1926751f96a 100644 --- a/public/app/features/org/partials/appEdit.html +++ b/public/app/features/org/partials/appEdit.html @@ -26,6 +26,11 @@ +
  • + Pin To Menu  + + +
  • From e7a0ab76c38aaebe7b4b1691aad9a477e68608d0 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Fri, 18 Dec 2015 22:09:33 +0800 Subject: [PATCH 05/36] change plugin to app in breadcrumb --- public/app/features/org/partials/appEdit.html | 2 +- public/app/features/org/partials/apps.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/features/org/partials/appEdit.html b/public/app/features/org/partials/appEdit.html index 1926751f96a..02236355c92 100644 --- a/public/app/features/org/partials/appEdit.html +++ b/public/app/features/org/partials/appEdit.html @@ -1,4 +1,4 @@ - + -
    -
    -

    Edit App

    - +
    +
    +

    {{ctrl.appModel.type}}

    @@ -34,14 +33,9 @@
    -
    + -
    - - Cancel -
    -
    -
    \ No newline at end of file +
    diff --git a/public/app/features/org/partials/app_list.html b/public/app/features/org/partials/app_list.html index 94044c00cf7..79afd4a03fe 100644 --- a/public/app/features/org/partials/app_list.html +++ b/public/app/features/org/partials/app_list.html @@ -4,33 +4,32 @@ -
    -
    -

    Apps

    +
    +
    +

    Apps

    -
    +
    No apps defined
    - - - - - - - - - - -
    Name
    -   - {{p.type}} - - - - Configure - -
    - +
      +
    • +
        +
      • +
        +
        + + + +
        +
        + Litmus{{app.type}} + + Dashboards: 1 + +
      • +
      +
    • +
    From 41a0995db7f4858a1518df9e68b64d99826208c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 22 Dec 2015 16:32:17 +0100 Subject: [PATCH 10/36] feat(apps): minor progress on app meta data --- pkg/api/app_plugin.go | 39 ++++++++----------- pkg/api/dtos/app_plugin.go | 1 + pkg/plugins/models.go | 19 +++++++++ public/app/features/org/app_edit_ctrl.ts | 5 ++- public/app/features/org/app_srv.ts | 2 +- .../app/features/org/partials/app_list.html | 2 +- .../plugins/datasource/graphite/plugin.json | 3 +- 7 files changed, 43 insertions(+), 28 deletions(-) diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go index 6bc0e5a4933..860334e362e 100644 --- a/pkg/api/app_plugin.go +++ b/pkg/api/app_plugin.go @@ -15,36 +15,31 @@ func GetAppPlugins(c *middleware.Context) Response { return ApiError(500, "Failed to list Plugin Bundles", err) } - installedAppsMap := make(map[string]*dtos.AppPlugin) - for t, a := range plugins.Apps { - installedAppsMap[t] = &dtos.AppPlugin{ - Type: a.Type, - Enabled: a.Enabled, - Pinned: a.Pinned, - Module: a.Module, - JsonData: make(map[string]interface{}), + 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, } } seenApps := make(map[string]bool) - result := make([]*dtos.AppPlugin, 0) - for _, b := range query.Result { - if def, ok := installedAppsMap[b.Type]; ok { - result = append(result, &dtos.AppPlugin{ - Type: b.Type, - Enabled: b.Enabled, - Pinned: b.Pinned, - Module: def.Module, - JsonData: b.JsonData, - }) - seenApps[b.Type] = true + 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 t, a := range installedAppsMap { - if _, ok := seenApps[t]; !ok { - result = append(result, a) + for _, app := range plugins.Apps { + if _, ok := seenApps[app.Type]; !ok { + result = append(result, translateToDto(app)) } } diff --git a/pkg/api/dtos/app_plugin.go b/pkg/api/dtos/app_plugin.go index 741b17ab383..029989008b5 100644 --- a/pkg/api/dtos/app_plugin.go +++ b/pkg/api/dtos/app_plugin.go @@ -1,6 +1,7 @@ package dtos type AppPlugin struct { + Name string `json:"name"` Type string `json:"type"` Enabled bool `json:"enabled"` Pinned bool `json:"pinned"` diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 15e48409144..0db825b56cf 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -4,6 +4,23 @@ import ( "github.com/grafana/grafana/pkg/models" ) +type PluginInfo struct { + Author PluginAuthor `json:"author"` + Description string `json:"description"` + Homepage string `json:"homepage"` + Logos PluginLogos `json:"logos"` +} + +type PluginAuthor struct { + Name string `json:"name"` + Url string `json:"url"` +} + +type PluginLogos struct { + Small string `json:"small"` + Large string `json:"large"` +} + type DataSourcePlugin struct { Type string `json:"type"` Name string `json:"name"` @@ -61,12 +78,14 @@ type ApiPlugin struct { type AppPlugin struct { Type string `json:"type"` + Name string `json:"name"` Enabled bool `json:"enabled"` Pinned bool `json:"pinned"` Module string `json:"module"` Css *AppPluginCss `json:"css"` Page *AppPluginPage `json:"page"` PublicContent *PublicContent `json:"public"` + Info *PluginInfo `json:"info"` } type EnabledPlugins struct { diff --git a/public/app/features/org/app_edit_ctrl.ts b/public/app/features/org/app_edit_ctrl.ts index ad7db2970e2..7c4553ac332 100644 --- a/public/app/features/org/app_edit_ctrl.ts +++ b/public/app/features/org/app_edit_ctrl.ts @@ -1,8 +1,8 @@ /// -import config = require('app/core/config'); +import config from 'app/core/config'; import angular from 'angular'; -import * as _ from 'lodash'; +import _ from 'lodash'; export class AppEditCtrl { appModel: any; @@ -25,3 +25,4 @@ export class AppEditCtrl { } angular.module('grafana.controllers').controller('AppEditCtrl', AppEditCtrl); + diff --git a/public/app/features/org/app_srv.ts b/public/app/features/org/app_srv.ts index 6d712301b90..0f937e601bc 100644 --- a/public/app/features/org/app_srv.ts +++ b/public/app/features/org/app_srv.ts @@ -1,6 +1,6 @@ /// -import config = require('app/core/config'); +import _ from 'lodash'; import angular from 'angular'; export class AppSrv { diff --git a/public/app/features/org/partials/app_list.html b/public/app/features/org/partials/app_list.html index 79afd4a03fe..ea992a46a92 100644 --- a/public/app/features/org/partials/app_list.html +++ b/public/app/features/org/partials/app_list.html @@ -23,7 +23,7 @@
    - Litmus{{app.type}} + {{app.name}} Dashboards: 1 diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index b170cc708f1..0a94404533d 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -1,10 +1,9 @@ { "pluginType": "datasource", "name": "Graphite", - "type": "graphite", - "serviceName": "GraphiteDatasource", + "serviceName": "GraphiteDatasource", "module": "app/plugins/datasource/graphite/datasource", "partials": { From aa32459bc20e8b6345e26fe552fb6a7e1b917fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 22 Dec 2015 17:00:21 +0100 Subject: [PATCH 11/36] feat(apps): mini update to apps config view --- .../app/features/org/partials/app_edit.html | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/public/app/features/org/partials/app_edit.html b/public/app/features/org/partials/app_edit.html index cdd878e47b5..4335a94ead8 100644 --- a/public/app/features/org/partials/app_edit.html +++ b/public/app/features/org/partials/app_edit.html @@ -1,34 +1,22 @@
    -

    {{ctrl.appModel.type}}

    +

    {{ctrl.appModel.name}}

      -
    • - Type -
    • -
    • -
    • - -
    • +
    • +
    • - Default  - - -
    • -
    • - Pin To Menu  - - +
    From f67563e9ee4f1a32d0be6c2f63bfa79c3ff1a402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 8 Jan 2016 12:45:12 +0100 Subject: [PATCH 12/36] feat(apps): moving things around --- pkg/api/index.go | 14 ++++++++ public/app/core/controllers/sidemenu_ctrl.js | 10 +----- public/app/core/routes/all.js | 13 ++++---- public/app/features/apps/all.ts | 3 ++ public/app/features/{org => apps}/app_srv.ts | 0 .../app_edit_ctrl.ts => apps/edit_ctrl.ts} | 0 .../app_list_ctrl.ts => apps/list_ctrl.ts} | 0 .../app_edit.html => apps/partials/edit.html} | 0 .../app_list.html => apps/partials/list.html} | 2 +- public/app/features/org/app_directive.js | 32 ------------------- 10 files changed, 26 insertions(+), 48 deletions(-) create mode 100644 public/app/features/apps/all.ts rename public/app/features/{org => apps}/app_srv.ts (100%) rename public/app/features/{org/app_edit_ctrl.ts => apps/edit_ctrl.ts} (100%) rename public/app/features/{org/app_list_ctrl.ts => apps/list_ctrl.ts} (100%) rename public/app/features/{org/partials/app_edit.html => apps/partials/edit.html} (100%) rename public/app/features/{org/partials/app_list.html => apps/partials/list.html} (95%) delete mode 100644 public/app/features/org/app_directive.js diff --git a/pkg/api/index.go b/pkg/api/index.go index af8dfcb99f1..3a56a7f1205 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -55,6 +55,20 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Url: "/", }) + if c.OrgRole == m.ROLE_ADMIN { + data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ + Text: "Data Sources", + Icon: "fa fa-fw fa-database", + Url: "/datasources", + }) + + data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ + Text: "Apps", + Icon: "fa fa-fw fa-cubes", + Url: "/apps", + }) + } + orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} err = bus.Dispatch(&orgApps) if err != nil { diff --git a/public/app/core/controllers/sidemenu_ctrl.js b/public/app/core/controllers/sidemenu_ctrl.js index bd58edccebc..e53b555466e 100644 --- a/public/app/core/controllers/sidemenu_ctrl.js +++ b/public/app/core/controllers/sidemenu_ctrl.js @@ -19,7 +19,7 @@ function (angular, _, $, coreModule, config) { $scope.mainLinks.push({ text: item.text, icon: item.icon, - href: $scope.getUrl(item.href) + url: $scope.getUrl(item.url) }); }); }; @@ -40,14 +40,6 @@ function (angular, _, $, coreModule, config) { text: "API Keys", href: $scope.getUrl("/org/apikeys"), }); - $scope.orgMenu.push({ - text: "Datasources", - href: $scope.getUrl("/datasources"), - }); - $scope.orgMenu.push({ - text: "Apps", - href: $scope.getUrl("/org/apps"), - }); } if ($scope.orgMenu.length > 0) { diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index 82b9c409f9d..1f18210f8a9 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -10,6 +10,7 @@ define([ $locationProvider.html5Mode(true); var loadOrgBundle = new BundleLoader.BundleLoader('app/features/org/all'); + var loadAppsBundle = new BundleLoader.BundleLoader('app/features/apps/all'); $routeProvider .when('/', { @@ -131,17 +132,17 @@ define([ templateUrl: 'app/partials/reset_password.html', controller : 'ResetPasswordCtrl', }) - .when('/org/apps', { - templateUrl: 'app/features/org/partials/app_list.html', + .when('/apps', { + templateUrl: 'app/features/apps/partials/list.html', controller: 'AppListCtrl', controllerAs: 'ctrl', - resolve: loadOrgBundle, + resolve: loadAppsBundle, }) - .when('/org/apps/edit/:type', { - templateUrl: 'app/features/org/partials/app_edit.html', + .when('/apps/edit/:type', { + templateUrl: 'app/features/apps/partials/edit.html', controller: 'AppEditCtrl', controllerAs: 'ctrl', - resolve: loadOrgBundle, + resolve: loadAppsBundle, }) .when('/global-alerts', { templateUrl: 'app/features/dashboard/partials/globalAlerts.html', diff --git a/public/app/features/apps/all.ts b/public/app/features/apps/all.ts new file mode 100644 index 00000000000..005c0796493 --- /dev/null +++ b/public/app/features/apps/all.ts @@ -0,0 +1,3 @@ +import './edit_ctrl'; +import './list_ctrl'; +import './app_srv'; diff --git a/public/app/features/org/app_srv.ts b/public/app/features/apps/app_srv.ts similarity index 100% rename from public/app/features/org/app_srv.ts rename to public/app/features/apps/app_srv.ts diff --git a/public/app/features/org/app_edit_ctrl.ts b/public/app/features/apps/edit_ctrl.ts similarity index 100% rename from public/app/features/org/app_edit_ctrl.ts rename to public/app/features/apps/edit_ctrl.ts diff --git a/public/app/features/org/app_list_ctrl.ts b/public/app/features/apps/list_ctrl.ts similarity index 100% rename from public/app/features/org/app_list_ctrl.ts rename to public/app/features/apps/list_ctrl.ts diff --git a/public/app/features/org/partials/app_edit.html b/public/app/features/apps/partials/edit.html similarity index 100% rename from public/app/features/org/partials/app_edit.html rename to public/app/features/apps/partials/edit.html diff --git a/public/app/features/org/partials/app_list.html b/public/app/features/apps/partials/list.html similarity index 95% rename from public/app/features/org/partials/app_list.html rename to public/app/features/apps/partials/list.html index ea992a46a92..37897546eed 100644 --- a/public/app/features/org/partials/app_list.html +++ b/public/app/features/apps/partials/list.html @@ -18,7 +18,7 @@
  • diff --git a/public/app/features/org/app_directive.js b/public/app/features/org/app_directive.js deleted file mode 100644 index c58464f8075..00000000000 --- a/public/app/features/org/app_directive.js +++ /dev/null @@ -1,32 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.directives'); - - module.directive('appConfigLoader', function($compile) { - return { - restrict: 'E', - link: function(scope, elem) { - var directive = 'grafana-app-default'; - //wait for the parent scope to be applied. - scope.panelAdded = false; - scope.$watch("current", function(newVal) { - if (newVal && !scope.panelAdded) { - if (newVal.module) { - scope.panelAdded = true; - directive = 'grafana-app-'+newVal.type; - scope.require([newVal.module], function () { - var panelEl = angular.element(document.createElement(directive)); - elem.append(panelEl); - $compile(panelEl)(scope); - }); - } - } - }); - } - }; - }); -}); \ No newline at end of file From 7a8b3c419bf2cd45319a3d5fd5b45f7eae4253cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 8 Jan 2016 20:57:58 +0100 Subject: [PATCH 13/36] feat(apps): lots of progress --- pkg/api/app_plugin.go | 1 + pkg/api/dtos/app_plugin.go | 3 ++ pkg/plugins/models.go | 10 ++--- pkg/plugins/plugins.go | 35 ++++++++++++++- pkg/plugins/plugins_test.go | 13 ++++++ public/app/features/apps/partials/edit.html | 13 +++++- tests/app-plugin-json/plugin.json | 50 +++++++++++++++++++++ 7 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 tests/app-plugin-json/plugin.json diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go index 860334e362e..0ad81827246 100644 --- a/pkg/api/app_plugin.go +++ b/pkg/api/app_plugin.go @@ -22,6 +22,7 @@ func GetAppPlugins(c *middleware.Context) Response { Enabled: app.Enabled, Pinned: app.Pinned, Module: app.Module, + Info: app.Info, } } diff --git a/pkg/api/dtos/app_plugin.go b/pkg/api/dtos/app_plugin.go index 029989008b5..7213c224cf8 100644 --- a/pkg/api/dtos/app_plugin.go +++ b/pkg/api/dtos/app_plugin.go @@ -1,10 +1,13 @@ 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"` } diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 0db825b56cf..7c0bfcafc50 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -5,13 +5,13 @@ import ( ) type PluginInfo struct { - Author PluginAuthor `json:"author"` - Description string `json:"description"` - Homepage string `json:"homepage"` - Logos PluginLogos `json:"logos"` + Author PluginInfoLink `json:"author"` + Description string `json:"description"` + Links []PluginInfoLink `json:"links"` + Logos PluginLogos `json:"logos"` } -type PluginAuthor struct { +type PluginInfoLink struct { Name string `json:"name"` Url string `json:"url"` } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 10c511a966b..a1ae0ff8dd6 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -1,12 +1,15 @@ package plugins import ( + "bytes" "encoding/json" "errors" + "io" "os" "path" "path/filepath" "strings" + "text/template" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" @@ -118,6 +121,28 @@ func addPublicContent(public *PublicContent, currentDir string) { } } +func interpolatePluginJson(reader io.Reader) (io.Reader, error) { + buf := new(bytes.Buffer) + buf.ReadFrom(reader) + jsonStr := buf.String() // + + tmpl, err := template.New("json").Parse(jsonStr) + if err != nil { + return nil, err + } + + data := map[string]interface{}{ + "PluginPublicRoot": "HAHAHA", + } + + var resultBuffer bytes.Buffer + if err := tmpl.ExecuteTemplate(&resultBuffer, "json", data); err != nil { + return nil, err + } + + return bytes.NewReader(resultBuffer.Bytes()), nil +} + func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { currentDir := filepath.Dir(pluginJsonFilePath) reader, err := os.Open(pluginJsonFilePath) @@ -128,7 +153,6 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { defer reader.Close() jsonParser := json.NewDecoder(reader) - pluginJson := make(map[string]interface{}) if err := jsonParser.Decode(&pluginJson); err != nil { return err @@ -139,9 +163,16 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { return errors.New("Did not find pluginType property in plugin.json") } + reader.Seek(0, 0) + + if newReader, err := interpolatePluginJson(reader); err != nil { + return err + } else { + jsonParser = json.NewDecoder(newReader) + } + if pluginType == "datasource" { p := DataSourcePlugin{} - reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err } diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index bbeac4bba81..812b8ad19f2 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -18,5 +18,18 @@ func TestPluginScans(t *testing.T) { So(err, ShouldBeNil) So(len(DataSources), ShouldBeGreaterThan, 1) + So(len(Panels), ShouldBeGreaterThan, 1) }) + + Convey("When reading app plugin definition", t, func() { + setting.Cfg = ini.Empty() + sec, _ := setting.Cfg.NewSection("plugin.app-test") + sec.NewKey("path", "../../tests/app-plugin-json") + err := Init() + + So(err, ShouldBeNil) + So(len(Apps), ShouldBeGreaterThan, 0) + So(Apps["app-test"].Info.Logos.Large, ShouldEqual, "plugins/app-exampl/img/logo_large.png") + }) + } diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index 4335a94ead8..b770914c802 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -6,8 +6,20 @@
    +
    + + + +

    {{ctrl.appModel.name}}

    + + {{ctrl.appModel.info.description}} +
    @@ -24,6 +36,5 @@ -
    diff --git a/tests/app-plugin-json/plugin.json b/tests/app-plugin-json/plugin.json new file mode 100644 index 00000000000..34c60f84f52 --- /dev/null +++ b/tests/app-plugin-json/plugin.json @@ -0,0 +1,50 @@ +{ + "pluginType": "app", + "name": "App Example", + "type": "app-test", + + "plugins": [], + + "css": { + "light": "plugin.dark.css", + "dark": "plugin.light.css" + }, + + "module": "app", + + "pages": [ + {"name": "Example1", "url": "/app-example", "reqRole": "Editor"} + ], + + "public": { + "urlFragment": "app-example", + "path": "./public" + }, + + "info": { + "description": "Example Grafana App", + "author": { + "name": "Raintank Inc.", + "url": "http://raintank.io" + }, + "keywords": ["example"], + "logos": { + "small": "{{.PluginPublicRoot}}/img/logo_small.png", + "large": "{{.PluginPublicRoot}}/logo_large.png" + }, + "links": [ + {"name": "Project site", "url": "http://project.com"}, + {"name": "License & Terms", "url": "http://license.com"} + ], + "version": "1.0.0", + "updated": "2015-02-10" + }, + + "dependencies": { + "grafanaVersion": "2.6.x", + "plugins": [ + {"type": "datasource", "id": "graphite", "name": "Graphite", "version": "1.0.0"}, + {"type": "panel", "id": "graph", "name": "Graph", "version": "1.0.0"} + ] + } +} From 3bb20dbf2e63514369daf3a271b4427cbe622de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 8 Jan 2016 23:15:44 +0100 Subject: [PATCH 14/36] feat(plugins): changed plugin schema, pluginType -> type, type -> id --- pkg/api/app_plugin.go | 2 +- pkg/api/frontendsettings.go | 2 +- pkg/plugins/models.go | 21 ++++---- pkg/plugins/plugins.go | 53 +++++++------------ pkg/plugins/plugins_test.go | 2 +- .../plugins/datasource/cloudwatch/plugin.json | 4 +- .../datasource/elasticsearch/plugin.json | 4 +- .../plugins/datasource/grafana/plugin.json | 5 +- .../plugins/datasource/graphite/plugin.json | 4 +- .../plugins/datasource/influxdb/plugin.json | 4 +- .../app/plugins/datasource/mixed/plugin.json | 5 +- .../plugins/datasource/opentsdb/plugin.json | 5 +- .../plugins/datasource/prometheus/plugin.json | 4 +- .../app/plugins/datasource/sql/datasource.js | 18 ------- .../datasource/sql/partials/config.html | 53 ------------------- .../datasource/sql/partials/query.editor.html | 17 ------ .../app/plugins/datasource/sql/plugin.json_ | 16 ------ .../app/plugins/panels/dashlist/plugin.json | 5 +- public/app/plugins/panels/graph/plugin.json | 5 +- .../app/plugins/panels/singlestat/plugin.json | 5 +- public/app/plugins/panels/table/plugin.json | 5 +- public/app/plugins/panels/text/plugin.json | 5 +- tests/app-plugin-json/plugin.json | 38 +++++++------ 23 files changed, 79 insertions(+), 203 deletions(-) delete mode 100644 public/app/plugins/datasource/sql/datasource.js delete mode 100644 public/app/plugins/datasource/sql/partials/config.html delete mode 100644 public/app/plugins/datasource/sql/partials/query.editor.html delete mode 100644 public/app/plugins/datasource/sql/plugin.json_ diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go index 0ad81827246..bcab5fa4788 100644 --- a/pkg/api/app_plugin.go +++ b/pkg/api/app_plugin.go @@ -22,7 +22,7 @@ func GetAppPlugins(c *middleware.Context) Response { Enabled: app.Enabled, Pinned: app.Pinned, Module: app.Module, - Info: app.Info, + Info: &app.Info, } } diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 9334b030201..486d59608ba 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -119,7 +119,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro panels := map[string]interface{}{} for _, panel := range enabledPlugins.Panels { - panels[panel.Type] = map[string]interface{}{ + panels[panel.Id] = map[string]interface{}{ "module": panel.Module, "name": panel.Name, } diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 7c0bfcafc50..078a63a884f 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -4,6 +4,13 @@ import ( "github.com/grafana/grafana/pkg/models" ) +type PluginCommon struct { + Type string `json:"type"` + Name string `json:"name"` + Id string `json:"id"` + Info PluginInfo `json:"info"` +} + type PluginInfo struct { Author PluginInfoLink `json:"author"` Description string `json:"description"` @@ -22,10 +29,9 @@ type PluginLogos struct { } type DataSourcePlugin struct { - Type string `json:"type"` - Name string `json:"name"` - ServiceName string `json:"serviceName"` + PluginCommon Module string `json:"module"` + ServiceName string `json:"serviceName"` Partials map[string]interface{} `json:"partials"` DefaultMatchFormat string `json:"defaultMatchFormat"` Annotations bool `json:"annotations"` @@ -36,8 +42,7 @@ type DataSourcePlugin struct { } type PanelPlugin struct { - Type string `json:"type"` - Name string `json:"name"` + PluginCommon Module string `json:"module"` PublicContent *PublicContent `json:"public"` App string `json:"app"` @@ -71,21 +76,19 @@ type AppPluginCss struct { } type ApiPlugin struct { - Type string `json:"type"` + PluginCommon Routes []*ApiPluginRoute `json:"routes"` App string `json:"app"` } type AppPlugin struct { - Type string `json:"type"` - Name string `json:"name"` + PluginCommon Enabled bool `json:"enabled"` Pinned bool `json:"pinned"` Module string `json:"module"` Css *AppPluginCss `json:"css"` Page *AppPluginPage `json:"page"` PublicContent *PublicContent `json:"public"` - Info *PluginInfo `json:"info"` } type EnabledPlugins struct { diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index a1ae0ff8dd6..8002e505b01 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -121,7 +121,7 @@ func addPublicContent(public *PublicContent, currentDir string) { } } -func interpolatePluginJson(reader io.Reader) (io.Reader, error) { +func interpolatePluginJson(reader io.Reader, pluginCommon *PluginCommon) (io.Reader, error) { buf := new(bytes.Buffer) buf.ReadFrom(reader) jsonStr := buf.String() // @@ -132,7 +132,7 @@ func interpolatePluginJson(reader io.Reader) (io.Reader, error) { } data := map[string]interface{}{ - "PluginPublicRoot": "HAHAHA", + "PluginPublicRoot": "public/plugins/" + pluginCommon.Id, } var resultBuffer bytes.Buffer @@ -153,76 +153,59 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { defer reader.Close() jsonParser := json.NewDecoder(reader) - pluginJson := make(map[string]interface{}) - if err := jsonParser.Decode(&pluginJson); err != nil { + pluginCommon := PluginCommon{} + if err := jsonParser.Decode(&pluginCommon); err != nil { return err } - pluginType, exists := pluginJson["pluginType"] - if !exists { - return errors.New("Did not find pluginType property in plugin.json") + if pluginCommon.Id == "" || pluginCommon.Type == "" { + return errors.New("Did not find type and id property in plugin.json") } reader.Seek(0, 0) - if newReader, err := interpolatePluginJson(reader); err != nil { + if newReader, err := interpolatePluginJson(reader, &pluginCommon); err != nil { return err } else { jsonParser = json.NewDecoder(newReader) } - if pluginType == "datasource" { + switch pluginCommon.Type { + case "datasource": p := DataSourcePlugin{} if err := jsonParser.Decode(&p); err != nil { return err } - if p.Type == "" { - return errors.New("Did not find type property in plugin.json") - } - - DataSources[p.Type] = &p + DataSources[p.Id] = &p addPublicContent(p.PublicContent, currentDir) - } - if pluginType == "panel" { + case "panel": p := PanelPlugin{} reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err } - if p.Type == "" { - return errors.New("Did not find type property in plugin.json") - } - - Panels[p.Type] = &p + Panels[p.Id] = &p addPublicContent(p.PublicContent, currentDir) - } - - if pluginType == "api" { + case "api": p := ApiPlugin{} reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err } - if p.Type == "" { - return errors.New("Did not find type property in plugin.json") - } - ApiPlugins[p.Type] = &p - } - - if pluginType == "app" { + ApiPlugins[p.Id] = &p + case "app": p := AppPlugin{} reader.Seek(0, 0) if err := jsonParser.Decode(&p); err != nil { return err } - if p.Type == "" { - return errors.New("Did not find type property in plugin.json") - } - Apps[p.Type] = &p + Apps[p.Id] = &p addPublicContent(p.PublicContent, currentDir) + default: + return errors.New("Unkown plugin type " + pluginCommon.Type) } return nil diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index 812b8ad19f2..92982d8abe4 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -29,7 +29,7 @@ func TestPluginScans(t *testing.T) { So(err, ShouldBeNil) So(len(Apps), ShouldBeGreaterThan, 0) - So(Apps["app-test"].Info.Logos.Large, ShouldEqual, "plugins/app-exampl/img/logo_large.png") + So(Apps["app-test"].Info.Logos.Large, ShouldEqual, "public/plugins/app-test/logo_large.png") }) } diff --git a/public/app/plugins/datasource/cloudwatch/plugin.json b/public/app/plugins/datasource/cloudwatch/plugin.json index f1cf0e5512c..5e54db64f52 100644 --- a/public/app/plugins/datasource/cloudwatch/plugin.json +++ b/public/app/plugins/datasource/cloudwatch/plugin.json @@ -1,8 +1,8 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "CloudWatch", + "id": "cloudwatch", - "type": "cloudwatch", "serviceName": "CloudWatchDatasource", "module": "app/plugins/datasource/cloudwatch/datasource", diff --git a/public/app/plugins/datasource/elasticsearch/plugin.json b/public/app/plugins/datasource/elasticsearch/plugin.json index a0350bd8c6c..c06f9e7ba99 100644 --- a/public/app/plugins/datasource/elasticsearch/plugin.json +++ b/public/app/plugins/datasource/elasticsearch/plugin.json @@ -1,8 +1,8 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "Elasticsearch", + "id": "elasticsearch", - "type": "elasticsearch", "serviceName": "ElasticDatasource", "module": "app/plugins/datasource/elasticsearch/datasource", diff --git a/public/app/plugins/datasource/grafana/plugin.json b/public/app/plugins/datasource/grafana/plugin.json index 8d4ba70e471..5b74f9ea613 100644 --- a/public/app/plugins/datasource/grafana/plugin.json +++ b/public/app/plugins/datasource/grafana/plugin.json @@ -1,9 +1,10 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "Grafana", + "id": "grafana", + "builtIn": true, - "type": "grafana", "serviceName": "GrafanaDatasource", "module": "app/plugins/datasource/grafana/datasource", diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index 0a94404533d..9a7360ba50a 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -1,7 +1,7 @@ { - "pluginType": "datasource", "name": "Graphite", - "type": "graphite", + "type": "datasource", + "id": "graphite", "serviceName": "GraphiteDatasource", "module": "app/plugins/datasource/graphite/datasource", diff --git a/public/app/plugins/datasource/influxdb/plugin.json b/public/app/plugins/datasource/influxdb/plugin.json index d586d679367..3a9aea175cb 100644 --- a/public/app/plugins/datasource/influxdb/plugin.json +++ b/public/app/plugins/datasource/influxdb/plugin.json @@ -1,8 +1,8 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "InfluxDB 0.9.x", + "id": "influxdb", - "type": "influxdb", "serviceName": "InfluxDatasource", "module": "app/plugins/datasource/influxdb/datasource", diff --git a/public/app/plugins/datasource/mixed/plugin.json b/public/app/plugins/datasource/mixed/plugin.json index 85be108d995..fb9bb340a04 100644 --- a/public/app/plugins/datasource/mixed/plugin.json +++ b/public/app/plugins/datasource/mixed/plugin.json @@ -1,10 +1,11 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "Mixed datasource", + "id": "mixed", + "builtIn": true, "mixed": true, - "type": "mixed", "serviceName": "MixedDatasource", "module": "app/plugins/datasource/mixed/datasource", diff --git a/public/app/plugins/datasource/opentsdb/plugin.json b/public/app/plugins/datasource/opentsdb/plugin.json index 311dcf0da9a..a72e09a1ab0 100644 --- a/public/app/plugins/datasource/opentsdb/plugin.json +++ b/public/app/plugins/datasource/opentsdb/plugin.json @@ -1,10 +1,9 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "OpenTSDB", + "id": "opentsdb", - "type": "opentsdb", "serviceName": "OpenTSDBDatasource", - "module": "app/plugins/datasource/opentsdb/datasource", "partials": { diff --git a/public/app/plugins/datasource/prometheus/plugin.json b/public/app/plugins/datasource/prometheus/plugin.json index 5c97866101d..2580db9e5c9 100644 --- a/public/app/plugins/datasource/prometheus/plugin.json +++ b/public/app/plugins/datasource/prometheus/plugin.json @@ -1,8 +1,8 @@ { - "pluginType": "datasource", + "type": "datasource", "name": "Prometheus", + "id": "prometheus", - "type": "prometheus", "serviceName": "PrometheusDatasource", "module": "app/plugins/datasource/prometheus/datasource", diff --git a/public/app/plugins/datasource/sql/datasource.js b/public/app/plugins/datasource/sql/datasource.js deleted file mode 100644 index ae6e62286ba..00000000000 --- a/public/app/plugins/datasource/sql/datasource.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.factory('SqlDatasource', function() { - - function SqlDatasource() { - } - - return SqlDatasource; - - }); - -}); diff --git a/public/app/plugins/datasource/sql/partials/config.html b/public/app/plugins/datasource/sql/partials/config.html deleted file mode 100644 index e6b7749a2f7..00000000000 --- a/public/app/plugins/datasource/sql/partials/config.html +++ /dev/null @@ -1,53 +0,0 @@ -

    SQL Options

    - -
    -
      -
    • - DB Type -
    • -
    • - -
    • -
    • - Host -
    • -
    • - -
    • -
    • - SSL  - - -
    • -
    -
    -
    -
    -
      -
    • - Database -
    • -
    • - -
    • -
    -
    -
    -
    -
      -
    • - User -
    • -
    • - -
    • -
    • - Password -
    • -
    • - -
    • -
    -
    -
    - diff --git a/public/app/plugins/datasource/sql/partials/query.editor.html b/public/app/plugins/datasource/sql/partials/query.editor.html deleted file mode 100644 index 0d6d21d0ad2..00000000000 --- a/public/app/plugins/datasource/sql/partials/query.editor.html +++ /dev/null @@ -1,17 +0,0 @@ - -
    -
    -
    -
    Test graph
    - -

    - This is just a test data source that generates random walk series. If this is your only data source - open the left side menu and navigate to the data sources admin screen and add your data sources. You can change - data source using the button to the left of the Add query button. -

    -
    -
    - -
    -
    - diff --git a/public/app/plugins/datasource/sql/plugin.json_ b/public/app/plugins/datasource/sql/plugin.json_ deleted file mode 100644 index 8d3f6effae7..00000000000 --- a/public/app/plugins/datasource/sql/plugin.json_ +++ /dev/null @@ -1,16 +0,0 @@ -{ - "pluginType": "datasource", - "name": "Generic SQL (prototype)", - - "type": "generic_sql", - "serviceName": "SqlDatasource", - - "module": "app/plugins/datasource/sql/datasource", - - "partials": { - "config": "app/plugins/datasource/sql/partials/config.html", - "query": "app/plugins/datasource/sql/partials/query.editor.html" - }, - - "metrics": true -} diff --git a/public/app/plugins/panels/dashlist/plugin.json b/public/app/plugins/panels/dashlist/plugin.json index af9b9d8bbc8..e1fcb2f9221 100644 --- a/public/app/plugins/panels/dashlist/plugin.json +++ b/public/app/plugins/panels/dashlist/plugin.json @@ -1,8 +1,7 @@ { - "pluginType": "panel", - + "type": "panel", "name": "Dashboard list", - "type": "dashlist", + "id": "dashlist", "module": "app/plugins/panels/dashlist/module" } diff --git a/public/app/plugins/panels/graph/plugin.json b/public/app/plugins/panels/graph/plugin.json index 8b683c9d750..7e4dc3093bb 100644 --- a/public/app/plugins/panels/graph/plugin.json +++ b/public/app/plugins/panels/graph/plugin.json @@ -1,8 +1,7 @@ { - "pluginType": "panel", - + "type": "panel", "name": "Graph", - "type": "graph", + "id": "graph", "module": "app/plugins/panels/graph/module" } diff --git a/public/app/plugins/panels/singlestat/plugin.json b/public/app/plugins/panels/singlestat/plugin.json index dfb38d615c7..5bc8e536510 100644 --- a/public/app/plugins/panels/singlestat/plugin.json +++ b/public/app/plugins/panels/singlestat/plugin.json @@ -1,8 +1,7 @@ { - "pluginType": "panel", - + "type": "panel", "name": "Singlestat", - "type": "singlestat", + "id": "singlestat", "module": "app/plugins/panels/singlestat/module" } diff --git a/public/app/plugins/panels/table/plugin.json b/public/app/plugins/panels/table/plugin.json index cdcfb7081dc..4fdb393b3db 100644 --- a/public/app/plugins/panels/table/plugin.json +++ b/public/app/plugins/panels/table/plugin.json @@ -1,8 +1,7 @@ { - "pluginType": "panel", - + "type": "panel", "name": "Table", - "type": "table", + "id": "table", "module": "app/plugins/panels/table/module" } diff --git a/public/app/plugins/panels/text/plugin.json b/public/app/plugins/panels/text/plugin.json index 4a6c039104b..33c49b2f8a4 100644 --- a/public/app/plugins/panels/text/plugin.json +++ b/public/app/plugins/panels/text/plugin.json @@ -1,8 +1,7 @@ { - "pluginType": "panel", - + "type": "panel", "name": "Text", - "type": "text", + "id": "text", "module": "app/plugins/panels/text/module" } diff --git a/tests/app-plugin-json/plugin.json b/tests/app-plugin-json/plugin.json index 34c60f84f52..5f48132f4db 100644 --- a/tests/app-plugin-json/plugin.json +++ b/tests/app-plugin-json/plugin.json @@ -1,25 +1,7 @@ { - "pluginType": "app", "name": "App Example", - "type": "app-test", - - "plugins": [], - - "css": { - "light": "plugin.dark.css", - "dark": "plugin.light.css" - }, - - "module": "app", - - "pages": [ - {"name": "Example1", "url": "/app-example", "reqRole": "Editor"} - ], - - "public": { - "urlFragment": "app-example", - "path": "./public" - }, + "id": "app-test", + "type": "app", "info": { "description": "Example Grafana App", @@ -40,6 +22,22 @@ "updated": "2015-02-10" }, + "css": { + "light": "plugin.dark.css", + "dark": "plugin.light.css" + }, + + "module": "app", + + "pages": [ + {"name": "Example1", "url": "/app-example", "reqRole": "Editor"} + ], + + "public": { + "urlFragment": "app-example", + "path": "./public" + }, + "dependencies": { "grafanaVersion": "2.6.x", "plugins": [ From 9943b9a2266d6a2ef46a3731b4d0cfadda30b237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 08:12:27 +0100 Subject: [PATCH 15/36] feat(plugin): more work on plugin schema --- pkg/cmd/web.go | 6 +++--- pkg/plugins/models.go | 36 +++++++++++++++---------------- pkg/plugins/plugins.go | 32 +++++++++++++++++++-------- pkg/plugins/plugins_test.go | 2 +- tests/app-plugin-json/plugin.json | 36 ++++++++++++++----------------- 5 files changed, 60 insertions(+), 52 deletions(-) diff --git a/pkg/cmd/web.go b/pkg/cmd/web.go index 3c433728ba6..ff7f8a053bc 100644 --- a/pkg/cmd/web.go +++ b/pkg/cmd/web.go @@ -30,9 +30,9 @@ func newMacaron() *macaron.Macaron { } for _, route := range plugins.StaticRoutes { - pluginRoute := path.Join("/public/plugins/", route.UrlFragment) - log.Info("Plugin: Adding static route %s -> %s", pluginRoute, route.Dir) - mapStatic(m, route.Dir, "", pluginRoute) + pluginRoute := path.Join("/public/plugins/", route.PluginId) + log.Info("Plugin: Adding static route %s -> %s", pluginRoute, route.Directory) + mapStatic(m, route.Directory, "", pluginRoute) } mapStatic(m, setting.StaticRootPath, "", "public") diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 078a63a884f..e60ff558df2 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -5,10 +5,11 @@ import ( ) type PluginCommon struct { - Type string `json:"type"` - Name string `json:"name"` - Id string `json:"id"` - Info PluginInfo `json:"info"` + Type string `json:"type"` + Name string `json:"name"` + Id string `json:"id"` + StaticRoot string `json:"staticRoot"` + Info PluginInfo `json:"info"` } type PluginInfo struct { @@ -38,19 +39,17 @@ type DataSourcePlugin struct { Metrics bool `json:"metrics"` BuiltIn bool `json:"builtIn"` App string `json:"app"` - PublicContent *PublicContent `json:"public"` +} + +type PluginStaticRoute struct { + Directory string + PluginId string } type PanelPlugin struct { PluginCommon - Module string `json:"module"` - PublicContent *PublicContent `json:"public"` - App string `json:"app"` -} - -type PublicContent struct { - UrlFragment string `json:"urlFragment"` - Dir string `json:"dir"` + Module string `json:"module"` + App string `json:"app"` } type ApiPluginRoute struct { @@ -83,12 +82,11 @@ type ApiPlugin struct { type AppPlugin struct { PluginCommon - Enabled bool `json:"enabled"` - Pinned bool `json:"pinned"` - Module string `json:"module"` - Css *AppPluginCss `json:"css"` - Page *AppPluginPage `json:"page"` - PublicContent *PublicContent `json:"public"` + Enabled bool `json:"enabled"` + Pinned bool `json:"pinned"` + Module string `json:"module"` + Css *AppPluginCss `json:"css"` + Page *AppPluginPage `json:"page"` } type EnabledPlugins struct { diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 8002e505b01..59b0b0db866 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "io" + "net/url" "os" "path" "path/filepath" @@ -21,7 +22,7 @@ var ( DataSources map[string]*DataSourcePlugin Panels map[string]*PanelPlugin ApiPlugins map[string]*ApiPlugin - StaticRoutes []*PublicContent + StaticRoutes []*PluginStaticRoute Apps map[string]*AppPlugin ) @@ -33,7 +34,7 @@ type PluginScanner struct { func Init() error { DataSources = make(map[string]*DataSourcePlugin) ApiPlugins = make(map[string]*ApiPlugin) - StaticRoutes = make([]*PublicContent, 0) + StaticRoutes = make([]*PluginStaticRoute, 0) Panels = make(map[string]*PanelPlugin) Apps = make(map[string]*AppPlugin) @@ -114,11 +115,24 @@ func (scanner *PluginScanner) walker(currentPath string, f os.FileInfo, err erro return nil } -func addPublicContent(public *PublicContent, currentDir string) { - if public != nil { - public.Dir = path.Join(currentDir, public.Dir) - StaticRoutes = append(StaticRoutes, public) +func evalRelativePluginUrlPath(pathStr string, pluginId string) string { + u, _ := url.Parse(pathStr) + if u.IsAbs() { + return pathStr } + return path.Join("public/plugins", pluginId, pathStr) +} + +func addPublicContent(plugin *PluginCommon, currentDir string) { + if plugin.StaticRoot != "" { + StaticRoutes = append(StaticRoutes, &PluginStaticRoute{ + Directory: path.Join(currentDir, plugin.StaticRoot), + PluginId: plugin.Id, + }) + } + + plugin.Info.Logos.Small = evalRelativePluginUrlPath(plugin.Info.Logos.Small, plugin.Id) + plugin.Info.Logos.Large = evalRelativePluginUrlPath(plugin.Info.Logos.Large, plugin.Id) } func interpolatePluginJson(reader io.Reader, pluginCommon *PluginCommon) (io.Reader, error) { @@ -178,7 +192,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { } DataSources[p.Id] = &p - addPublicContent(p.PublicContent, currentDir) + addPublicContent(&p.PluginCommon, currentDir) case "panel": p := PanelPlugin{} @@ -188,7 +202,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { } Panels[p.Id] = &p - addPublicContent(p.PublicContent, currentDir) + addPublicContent(&p.PluginCommon, currentDir) case "api": p := ApiPlugin{} reader.Seek(0, 0) @@ -203,7 +217,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { return err } Apps[p.Id] = &p - addPublicContent(p.PublicContent, currentDir) + addPublicContent(&p.PluginCommon, currentDir) default: return errors.New("Unkown plugin type " + pluginCommon.Type) } diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index 92982d8abe4..dc95d0e2b40 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -29,7 +29,7 @@ func TestPluginScans(t *testing.T) { So(err, ShouldBeNil) So(len(Apps), ShouldBeGreaterThan, 0) - So(Apps["app-test"].Info.Logos.Large, ShouldEqual, "public/plugins/app-test/logo_large.png") + So(Apps["app-example"].Info.Logos.Large, ShouldEqual, "public/plugins/app-example/img/logo_large.png") }) } diff --git a/tests/app-plugin-json/plugin.json b/tests/app-plugin-json/plugin.json index 5f48132f4db..986f28c7e99 100644 --- a/tests/app-plugin-json/plugin.json +++ b/tests/app-plugin-json/plugin.json @@ -1,7 +1,19 @@ { - "name": "App Example", - "id": "app-test", "type": "app", + "name": "App Example", + "id": "app-example", + + "staticRoot":" ./public", + "module": "app", + + "pages": [ + {"name": "Example1", "url": "/app-example", "reqRole": "Editor"} + ], + + "css": { + "light": "css/plugin.dark.css", + "dark": "css/plugin.light.css" + }, "info": { "description": "Example Grafana App", @@ -11,8 +23,8 @@ }, "keywords": ["example"], "logos": { - "small": "{{.PluginPublicRoot}}/img/logo_small.png", - "large": "{{.PluginPublicRoot}}/logo_large.png" + "small": "img/logo_small.png", + "large": "img/logo_large.png" }, "links": [ {"name": "Project site", "url": "http://project.com"}, @@ -22,22 +34,6 @@ "updated": "2015-02-10" }, - "css": { - "light": "plugin.dark.css", - "dark": "plugin.light.css" - }, - - "module": "app", - - "pages": [ - {"name": "Example1", "url": "/app-example", "reqRole": "Editor"} - ], - - "public": { - "urlFragment": "app-example", - "path": "./public" - }, - "dependencies": { "grafanaVersion": "2.6.x", "plugins": [ From d932653c7f87ea2263dde1e1a92e9a3f7bb556a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 11:07:34 +0100 Subject: [PATCH 16/36] feat(apps): minor progress on apps edit view --- public/app/core/directives/misc.js | 5 ++-- public/app/features/apps/partials/edit.html | 30 +++++++++----------- public/app/features/panel/panel_directive.js | 2 +- public/less/apps.less | 26 +++++++++++++++++ public/less/gfbox.less | 5 ++++ public/less/grafana.less | 1 + public/less/type.less | 5 ++++ 7 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 public/less/apps.less diff --git a/public/app/core/directives/misc.js b/public/app/core/directives/misc.js index 97361ed02d3..b3d6de2585d 100644 --- a/public/app/core/directives/misc.js +++ b/public/app/core/directives/misc.js @@ -62,12 +62,13 @@ function (angular, coreModule, kbn) { var label = ''; - var template = '' + ' '; - template = label + template; + template = template + label; elem.replaceWith($compile(angular.element(template))(scope)); } }; diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index b770914c802..3dd8e24d593 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -7,34 +7,30 @@
    -
    + +

    {{ctrl.appModel.name}}

    {{ctrl.appModel.info.description}} -
    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    +
    + + +
    -
    diff --git a/public/app/features/panel/panel_directive.js b/public/app/features/panel/panel_directive.js index c75c67ce825..ef36d3a1a2a 100644 --- a/public/app/features/panel/panel_directive.js +++ b/public/app/features/panel/panel_directive.js @@ -90,7 +90,7 @@ function (angular, $, config) { scope.target.refId = 'A'; } - var panelEl = angular.element(document.createElement('metric-query-editor-' + ds.meta.type)); + var panelEl = angular.element(document.createElement('metric-query-editor-' + ds.meta.id)); elem.append(panelEl); $compile(panelEl)(editorScope); }); diff --git a/public/less/apps.less b/public/less/apps.less new file mode 100644 index 00000000000..b53b0272290 --- /dev/null +++ b/public/less/apps.less @@ -0,0 +1,26 @@ +.apps-side-box { + float: left; +} + +.apps-side-box-logo { + padding: 15px; + background: @grafanaPanelBackground; + width: 120px; + text-align: center; + img { + max-width: 100px; + } + margin-bottom: 10px; +} + +.app-side-box-links { + list-style: none; + margin: 0; + + li { + background: @grafanaPanelBackground; + margin-top: 4px; + padding-left: 10px; + line-height: 25px; + } +} diff --git a/public/less/gfbox.less b/public/less/gfbox.less index 46967d143c5..55330d26513 100644 --- a/public/less/gfbox.less +++ b/public/less/gfbox.less @@ -84,6 +84,11 @@ max-width: 1000px; } +.page-wide-margined { + margin-left: 170px; + max-width: 1000px; +} + .admin-page { max-width: 800px; margin-left: 10px; diff --git a/public/less/grafana.less b/public/less/grafana.less index dcd6b4b734d..6e31e628c82 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -21,6 +21,7 @@ @import "tabs.less"; @import "timepicker.less"; @import "alerting.less"; +@import "apps.less"; @import "filter-controls.less"; @import "filter-list.less"; @import "filter-table.less"; diff --git a/public/less/type.less b/public/less/type.less index 0aeec228d6a..1e958c4b097 100644 --- a/public/less/type.less +++ b/public/less/type.less @@ -245,3 +245,8 @@ address { font-style: normal; line-height: @baseLineHeight; } + +a.external-link { + color: @blue; + text-decoration: underline; +} From c5635f9c89d3505b5836626bc002427e37169e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 13:21:16 +0100 Subject: [PATCH 17/36] feat(plugins): changed what datasources should return, they should now return the datasource constructor --- pkg/plugins/models.go | 1 + public/app/core/controllers/all.js | 6 -- public/app/core/services/datasource_srv.js | 17 ++++- .../datasource/elasticsearch/datasource.d.ts | 3 + .../datasource/elasticsearch/datasource.js | 76 +++++++++---------- .../elasticsearch/specs/datasource_specs.ts | 32 ++++---- .../plugins/datasource/graphite/datasource.js | 3 + .../plugins/datasource/mixed/datasource.js | 35 --------- .../plugins/datasource/mixed/datasource.ts | 37 +++++++++ public/test/lib/common.ts | 3 + 10 files changed, 112 insertions(+), 101 deletions(-) create mode 100644 public/app/plugins/datasource/elasticsearch/datasource.d.ts delete mode 100644 public/app/plugins/datasource/mixed/datasource.js create mode 100644 public/app/plugins/datasource/mixed/datasource.ts diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index e60ff558df2..4516bbd5491 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -38,6 +38,7 @@ type DataSourcePlugin struct { Annotations bool `json:"annotations"` Metrics bool `json:"metrics"` BuiltIn bool `json:"builtIn"` + Mixed bool `json:"mixed"` App string `json:"app"` } diff --git a/public/app/core/controllers/all.js b/public/app/core/controllers/all.js index 0d39cf57d69..d22010cffdc 100644 --- a/public/app/core/controllers/all.js +++ b/public/app/core/controllers/all.js @@ -1,9 +1,3 @@ -// import grafanaCtrl from './grafana_ctrl'; -// -// import * as asd from './sidemenu_ctrl'; -// -// export {grafanaCtrl}; - define([ './grafana_ctrl', './search_ctrl', diff --git a/public/app/core/services/datasource_srv.js b/public/app/core/services/datasource_srv.js index 3811daad168..054504ec602 100644 --- a/public/app/core/services/datasource_srv.js +++ b/public/app/core/services/datasource_srv.js @@ -58,12 +58,21 @@ function (angular, _, coreModule, config) { } var deferred = $q.defer(); - var pluginDef = dsConfig.meta; - System.import(pluginDef.module).then(function() { - var AngularService = $injector.get(pluginDef.serviceName); - var instance = new AngularService(dsConfig, pluginDef); + System.import(pluginDef.module).then(function(plugin) { + // check if its in cache now + if (self.datasources[name]) { + deferred.resolve(self.datasources[name]); + return; + } + + // plugin module needs to export a constructor function named Datasource + if (!plugin.Datasource) { + return; + } + + var instance = $injector.instantiate(plugin.Datasource, {instanceSettings: dsConfig}); instance.meta = pluginDef; instance.name = name; self.datasources[name] = instance; diff --git a/public/app/plugins/datasource/elasticsearch/datasource.d.ts b/public/app/plugins/datasource/elasticsearch/datasource.d.ts new file mode 100644 index 00000000000..4de8bcda15d --- /dev/null +++ b/public/app/plugins/datasource/elasticsearch/datasource.d.ts @@ -0,0 +1,3 @@ +declare var Datasource: any; +export {Datasource}; + diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 72eaa4fcfd6..2a43e45aba8 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -12,28 +12,22 @@ define([ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticResponse) { 'use strict'; - var module = angular.module('grafana.services'); + function ElasticDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) { + this.basicAuth = instanceSettings.basicAuth; + this.withCredentials = instanceSettings.withCredentials; + this.url = instanceSettings.url; + this.name = instanceSettings.name; + this.index = instanceSettings.index; + this.timeField = instanceSettings.jsonData.timeField; + this.esVersion = instanceSettings.jsonData.esVersion; + this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval); + this.interval = instanceSettings.jsonData.timeInterval; + this.queryBuilder = new ElasticQueryBuilder({ + timeField: this.timeField, + esVersion: this.esVersion, + }); - module.factory('ElasticDatasource', function($q, backendSrv, templateSrv, timeSrv) { - - function ElasticDatasource(datasource) { - this.type = 'elasticsearch'; - this.basicAuth = datasource.basicAuth; - this.withCredentials = datasource.withCredentials; - this.url = datasource.url; - this.name = datasource.name; - this.index = datasource.index; - this.timeField = datasource.jsonData.timeField; - this.esVersion = datasource.jsonData.esVersion; - this.indexPattern = new IndexPattern(datasource.index, datasource.jsonData.interval); - this.interval = datasource.jsonData.timeInterval; - this.queryBuilder = new ElasticQueryBuilder({ - timeField: this.timeField, - esVersion: this.esVersion, - }); - } - - ElasticDatasource.prototype._request = function(method, url, data) { + this._request = function(method, url, data) { var options = { url: this.url + "/" + url, method: method, @@ -52,21 +46,21 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes return backendSrv.datasourceRequest(options); }; - ElasticDatasource.prototype._get = function(url) { + this._get = function(url) { return this._request('GET', this.indexPattern.getIndexForToday() + url) - .then(function(results) { - return results.data; - }); + .then(function(results) { + return results.data; + }); }; - ElasticDatasource.prototype._post = function(url, data) { + this._post = function(url, data) { return this._request('POST', url, data) - .then(function(results) { - return results.data; - }); + .then(function(results) { + return results.data; + }); }; - ElasticDatasource.prototype.annotationQuery = function(options) { + this.annotationQuery = function(options) { var annotation = options.annotation; var timeField = annotation.timeField || '@timestamp'; var queryString = annotation.query || '*'; @@ -147,7 +141,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }); }; - ElasticDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { return this._get('/_stats').then(function() { return { status: "success", message: "Data source is working", title: "Success" }; }, function(err) { @@ -159,13 +153,13 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }); }; - ElasticDatasource.prototype.getQueryHeader = function(searchType, timeFrom, timeTo) { + this.getQueryHeader = function(searchType, timeFrom, timeTo) { var header = {search_type: searchType, "ignore_unavailable": true}; header.index = this.indexPattern.getIndexList(timeFrom, timeTo); return angular.toJson(header); }; - ElasticDatasource.prototype.query = function(options) { + this.query = function(options) { var payload = ""; var target; var sentTargets = []; @@ -203,7 +197,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }); }; - ElasticDatasource.prototype.getFields = function(query) { + this.getFields = function(query) { return this._get('/_mapping').then(function(res) { var fields = {}; var typeMap = { @@ -240,7 +234,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }); }; - ElasticDatasource.prototype.getTerms = function(queryDef) { + this.getTerms = function(queryDef) { var range = timeSrv.timeRange(); var header = this.getQueryHeader('count', range.from, range.to); var esQuery = angular.toJson(this.queryBuilder.getTermsQuery(queryDef)); @@ -258,7 +252,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }); }; - ElasticDatasource.prototype.metricFindQuery = function(query) { + this.metricFindQuery = function(query) { query = templateSrv.replace(query); query = angular.fromJson(query); if (!query) { @@ -273,14 +267,14 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes } }; - ElasticDatasource.prototype.getDashboard = function(id) { + this.getDashboard = function(id) { return this._get('/dashboard/' + id) .then(function(result) { return angular.fromJson(result._source.dashboard); }); }; - ElasticDatasource.prototype.searchDashboards = function() { + this.searchDashboards = function() { var query = { query: { query_string: { query: '*' } }, size: 10000, @@ -308,7 +302,9 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes return displayHits; }); }; + } - return ElasticDatasource; - }); + return { + Datasource: ElasticDatasource, + }; }); diff --git a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts index f34d52b42df..88700838cc0 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts @@ -1,28 +1,32 @@ -import "../datasource"; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import moment from 'moment'; import angular from 'angular'; import helpers from 'test/specs/helpers'; +import {Datasource} from "../datasource"; describe('ElasticDatasource', function() { var ctx = new helpers.ServiceTestContext(); + var instanceSettings: any = {jsonData: {}}; beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); beforeEach(ctx.providePhase(['templateSrv', 'backendSrv'])); - beforeEach(ctx.createService('ElasticDatasource')); - beforeEach(function() { - ctx.ds = new ctx.service({jsonData: {}}); - }); + beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + ctx.$q = $q; + ctx.$httpBackend = $httpBackend; + ctx.$rootScope = $rootScope; + ctx.$injector = $injector; + })); + + function createDatasource(instanceSettings) { + instanceSettings.jsonData = instanceSettings.jsonData || {}; + ctx.ds = ctx.$injector.instantiate(Datasource, {instanceSettings: instanceSettings}); + } describe('When testing datasource with index pattern', function() { beforeEach(function() { - ctx.ds = new ctx.service({ - url: 'http://es.com', - index: '[asd-]YYYY.MM.DD', - jsonData: { interval: 'Daily' } - }); + createDatasource({url: 'http://es.com', index: '[asd-]YYYY.MM.DD', jsonData: {interval: 'Daily'}}); }); it('should translate index pattern to current day', function() { @@ -44,11 +48,7 @@ describe('ElasticDatasource', function() { var requestOptions, parts, header; beforeEach(function() { - ctx.ds = new ctx.service({ - url: 'http://es.com', - index: '[asd-]YYYY.MM.DD', - jsonData: { interval: 'Daily' } - }); + createDatasource({url: 'http://es.com', index: '[asd-]YYYY.MM.DD', jsonData: {interval: 'Daily'}}); ctx.backendSrv.datasourceRequest = function(options) { requestOptions = options; @@ -83,7 +83,7 @@ describe('ElasticDatasource', function() { var requestOptions, parts, header; beforeEach(function() { - ctx.ds = new ctx.service({url: 'http://es.com', index: 'test', jsonData: {}}); + createDatasource({url: 'http://es.com', index: 'test'}); ctx.backendSrv.datasourceRequest = function(options) { requestOptions = options; diff --git a/public/app/plugins/datasource/graphite/datasource.js b/public/app/plugins/datasource/graphite/datasource.js index 49aa589db45..3548fcb9571 100644 --- a/public/app/plugins/datasource/graphite/datasource.js +++ b/public/app/plugins/datasource/graphite/datasource.js @@ -301,4 +301,7 @@ function (angular, _, $, config, dateMath) { }); + return { + serviceName: "GraphiteDatasource" + }; }); diff --git a/public/app/plugins/datasource/mixed/datasource.js b/public/app/plugins/datasource/mixed/datasource.js deleted file mode 100644 index a74e872276b..00000000000 --- a/public/app/plugins/datasource/mixed/datasource.js +++ /dev/null @@ -1,35 +0,0 @@ -define([ - 'angular', - 'lodash', -], -function (angular, _) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.factory('MixedDatasource', function($q, backendSrv, datasourceSrv) { - - function MixedDatasource() { - } - - MixedDatasource.prototype.query = function(options) { - var sets = _.groupBy(options.targets, 'datasource'); - var promises = _.map(sets, function(targets) { - return datasourceSrv.get(targets[0].datasource).then(function(ds) { - var opt = angular.copy(options); - opt.targets = targets; - return ds.query(opt); - }); - }); - - return $q.all(promises).then(function(results) { - return { data: _.flatten(_.pluck(results, 'data')) }; - }); - - }; - - return MixedDatasource; - - }); - -}); diff --git a/public/app/plugins/datasource/mixed/datasource.ts b/public/app/plugins/datasource/mixed/datasource.ts new file mode 100644 index 00000000000..874773e7f45 --- /dev/null +++ b/public/app/plugins/datasource/mixed/datasource.ts @@ -0,0 +1,37 @@ +/// + +import angular from 'angular'; +import _ from 'lodash'; + +class MixedDatasource { + + constructor(private $q, private datasourceSrv) { + } + + query(options) { + var sets = _.groupBy(options.targets, 'datasource'); + var promises = _.map(sets, targets => { + var dsName = targets[0].datasource; + if (dsName === '-- Mixed --') { + return this.$q([]); + } + + return this.datasourceSrv.get(dsName).then(function(ds) { + var opt = angular.copy(options); + opt.targets = targets; + return ds.query(opt); + }); + }); + + return this.$q.all(promises).then(function(results) { + return { data: _.flatten(_.pluck(results, 'data')) }; + }); + } +} + +export {MixedDatasource, MixedDatasource as Datasource} + +// var module = angular.module('grafana.services'); +// module.factory('MixedDatasource', MixedDatasource); +// + diff --git a/public/test/lib/common.ts b/public/test/lib/common.ts index 523a97c2c03..c7e8147c9c9 100644 --- a/public/test/lib/common.ts +++ b/public/test/lib/common.ts @@ -2,6 +2,7 @@ var _global = (window); var beforeEach = _global.beforeEach; +var before = _global.before; var describe = _global.describe; var it = _global.it; var sinon = _global.sinon; @@ -9,10 +10,12 @@ var expect = _global.expect; var angularMocks = { module: _global.module, + inject: _global.inject, }; export { beforeEach, + before, describe, it, sinon, From f813b4c58f0a4300e9de8029f4e82b35593908c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 13:30:02 +0100 Subject: [PATCH 18/36] feat(plugins): converted graphite plugin to new format --- .../datasource/elasticsearch/datasource.js | 1 + .../datasource/graphite/datasource.d.ts | 3 + .../plugins/datasource/graphite/datasource.js | 110 ++++++++---------- .../graphite/specs/datasource_specs.ts | 13 ++- 4 files changed, 64 insertions(+), 63 deletions(-) create mode 100644 public/app/plugins/datasource/graphite/datasource.d.ts diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 2a43e45aba8..e8760a93cc8 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -12,6 +12,7 @@ define([ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticResponse) { 'use strict'; + /** @ngInject */ function ElasticDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) { this.basicAuth = instanceSettings.basicAuth; this.withCredentials = instanceSettings.withCredentials; diff --git a/public/app/plugins/datasource/graphite/datasource.d.ts b/public/app/plugins/datasource/graphite/datasource.d.ts new file mode 100644 index 00000000000..4de8bcda15d --- /dev/null +++ b/public/app/plugins/datasource/graphite/datasource.d.ts @@ -0,0 +1,3 @@ +declare var Datasource: any; +export {Datasource}; + diff --git a/public/app/plugins/datasource/graphite/datasource.js b/public/app/plugins/datasource/graphite/datasource.js index 3548fcb9571..1baac516790 100644 --- a/public/app/plugins/datasource/graphite/datasource.js +++ b/public/app/plugins/datasource/graphite/datasource.js @@ -12,20 +12,16 @@ define([ function (angular, _, $, config, dateMath) { 'use strict'; - var module = angular.module('grafana.services'); + /** @ngInject */ + function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.basicAuth = instanceSettings.basicAuth; + this.url = instanceSettings.url; + this.name = instanceSettings.name; + this.cacheTimeout = instanceSettings.cacheTimeout; + this.withCredentials = instanceSettings.withCredentials; + this.render_method = instanceSettings.render_method || 'POST'; - module.factory('GraphiteDatasource', function($q, backendSrv, templateSrv) { - - function GraphiteDatasource(datasource) { - this.basicAuth = datasource.basicAuth; - this.url = datasource.url; - this.name = datasource.name; - this.cacheTimeout = datasource.cacheTimeout; - this.withCredentials = datasource.withCredentials; - this.render_method = datasource.render_method || 'POST'; - } - - GraphiteDatasource.prototype.query = function(options) { + this.query = function(options) { try { var graphOptions = { from: this.translateTime(options.rangeRaw.from, false), @@ -62,7 +58,7 @@ function (angular, _, $, config, dateMath) { } }; - GraphiteDatasource.prototype.convertDataPointsToMs = function(result) { + this.convertDataPointsToMs = function(result) { if (!result || !result.data) { return []; } for (var i = 0; i < result.data.length; i++) { var series = result.data[i]; @@ -73,7 +69,7 @@ function (angular, _, $, config, dateMath) { return result; }; - GraphiteDatasource.prototype.annotationQuery = function(options) { + this.annotationQuery = function(options) { // Graphite metric as annotation if (options.annotation.target) { var target = templateSrv.replace(options.annotation.target); @@ -85,50 +81,49 @@ function (angular, _, $, config, dateMath) { }; return this.query(graphiteQuery) - .then(function(result) { - var list = []; + .then(function(result) { + var list = []; - for (var i = 0; i < result.data.length; i++) { - var target = result.data[i]; + for (var i = 0; i < result.data.length; i++) { + var target = result.data[i]; - for (var y = 0; y < target.datapoints.length; y++) { - var datapoint = target.datapoints[y]; - if (!datapoint[0]) { continue; } + for (var y = 0; y < target.datapoints.length; y++) { + var datapoint = target.datapoints[y]; + if (!datapoint[0]) { continue; } - list.push({ - annotation: options.annotation, - time: datapoint[1], - title: target.target - }); - } + list.push({ + annotation: options.annotation, + time: datapoint[1], + title: target.target + }); } + } - return list; - }); + return list; + }); } // Graphite event as annotation else { var tags = templateSrv.replace(options.annotation.tags); - return this.events({range: options.rangeRaw, tags: tags}) - .then(function(results) { - var list = []; - for (var i = 0; i < results.data.length; i++) { - var e = results.data[i]; + return this.events({range: options.rangeRaw, tags: tags}).then(function(results) { + var list = []; + for (var i = 0; i < results.data.length; i++) { + var e = results.data[i]; - list.push({ - annotation: options.annotation, - time: e.when * 1000, - title: e.what, - tags: e.tags, - text: e.data - }); - } - return list; - }); + list.push({ + annotation: options.annotation, + time: e.when * 1000, + title: e.what, + tags: e.tags, + text: e.data + }); + } + return list; + }); } }; - GraphiteDatasource.prototype.events = function(options) { + this.events = function(options) { try { var tags = ''; if (options.tags) { @@ -146,7 +141,7 @@ function (angular, _, $, config, dateMath) { } }; - GraphiteDatasource.prototype.translateTime = function(date, roundUp) { + this.translateTime = function(date, roundUp) { if (_.isString(date)) { if (date === 'now') { return 'now'; @@ -178,7 +173,7 @@ function (angular, _, $, config, dateMath) { return date.unix(); }; - GraphiteDatasource.prototype.metricFindQuery = function(query) { + this.metricFindQuery = function(query) { var interpolated; try { interpolated = encodeURIComponent(templateSrv.replace(query)); @@ -198,24 +193,24 @@ function (angular, _, $, config, dateMath) { }); }; - GraphiteDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { return this.metricFindQuery('*').then(function () { return { status: "success", message: "Data source is working", title: "Success" }; }); }; - GraphiteDatasource.prototype.listDashboards = function(query) { + this.listDashboards = function(query) { return this.doGraphiteRequest({ method: 'GET', url: '/dashboard/find/', params: {query: query || ''} }) .then(function(results) { return results.data.dashboards; }); }; - GraphiteDatasource.prototype.loadDashboard = function(dashName) { + this.loadDashboard = function(dashName) { return this.doGraphiteRequest({method: 'GET', url: '/dashboard/load/' + encodeURIComponent(dashName) }); }; - GraphiteDatasource.prototype.doGraphiteRequest = function(options) { + this.doGraphiteRequest = function(options) { if (this.basicAuth || this.withCredentials) { options.withCredentials = true; } @@ -230,9 +225,9 @@ function (angular, _, $, config, dateMath) { return backendSrv.datasourceRequest(options); }; - GraphiteDatasource.prototype._seriesRefLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + this._seriesRefLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - GraphiteDatasource.prototype.buildGraphiteParams = function(options, scopedVars) { + this.buildGraphiteParams = function(options, scopedVars) { var graphite_options = ['from', 'until', 'rawData', 'format', 'maxDataPoints', 'cacheTimeout']; var clean_options = [], targets = {}; var target, targetValue, i; @@ -296,12 +291,9 @@ function (angular, _, $, config, dateMath) { return clean_options; }; - - return GraphiteDatasource; - - }); + } return { - serviceName: "GraphiteDatasource" + Datasource: GraphiteDatasource }; }); diff --git a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts index 2342b2a17fe..52ec58cf5bc 100644 --- a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts @@ -1,19 +1,24 @@ -import "../datasource"; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import helpers from 'test/specs/helpers'; +import {Datasource} from "../datasource"; describe('graphiteDatasource', function() { var ctx = new helpers.ServiceTestContext(); + var instanceSettings: any = {url:['']}; beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); - beforeEach(ctx.providePhase(['backendSrv'])); - beforeEach(ctx.createService('GraphiteDatasource')); + beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + ctx.$q = $q; + ctx.$httpBackend = $httpBackend; + ctx.$rootScope = $rootScope; + ctx.$injector = $injector; + })); beforeEach(function() { - ctx.ds = new ctx.service({ url: [''] }); + ctx.ds = ctx.$injector.instantiate(Datasource, {instanceSettings: instanceSettings}); }); describe('When querying influxdb with one target using query editor target spec', function() { From cf98a16db09fe87b6ada6a41be02e8c8f9c446d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 18:07:42 +0100 Subject: [PATCH 19/36] feat(plugins): made data source custom edit view into a directive instead of html path config in plugin.json --- public/app/core/services/datasource_srv.js | 1 + public/app/features/org/datasourceEditCtrl.js | 21 +------ .../features/org/partials/datasourceEdit.html | 2 +- public/app/features/panel/panel_directive.js | 56 +++++++---------- .../datasource/elasticsearch/datasource.d.ts | 2 +- .../datasource/elasticsearch/datasource.js | 5 +- .../datasource/elasticsearch/directives.js | 4 ++ .../datasource/elasticsearch/edit_view.ts | 38 ++++++++++++ .../datasource/elasticsearch/module.js | 60 +++++++++++++++++++ .../partials/{config.html => edit_view.html} | 4 +- .../datasource/elasticsearch/plugin.json | 9 +-- .../elasticsearch/specs/datasource_specs.ts | 2 +- .../plugins/datasource/graphite/plugin.json | 1 - .../graphite/specs/datasource_specs.ts | 2 +- 14 files changed, 134 insertions(+), 73 deletions(-) create mode 100644 public/app/plugins/datasource/elasticsearch/edit_view.ts create mode 100644 public/app/plugins/datasource/elasticsearch/module.js rename public/app/plugins/datasource/elasticsearch/partials/{config.html => edit_view.html} (96%) diff --git a/public/app/core/services/datasource_srv.js b/public/app/core/services/datasource_srv.js index 054504ec602..1f2b492ee93 100644 --- a/public/app/core/services/datasource_srv.js +++ b/public/app/core/services/datasource_srv.js @@ -60,6 +60,7 @@ function (angular, _, coreModule, config) { var deferred = $q.defer(); var pluginDef = dsConfig.meta; + console.log(pluginDef); System.import(pluginDef.module).then(function(plugin) { // check if its in cache now if (self.datasources[name]) { diff --git a/public/app/features/org/datasourceEditCtrl.js b/public/app/features/org/datasourceEditCtrl.js index b7f141f480e..5eadd9a07b1 100644 --- a/public/app/features/org/datasourceEditCtrl.js +++ b/public/app/features/org/datasourceEditCtrl.js @@ -15,20 +15,6 @@ function (angular, _, config) { var defaults = {name: '', type: 'graphite', url: '', access: 'proxy', jsonData: {}}; - $scope.indexPatternTypes = [ - {name: 'No pattern', value: undefined}, - {name: 'Hourly', value: 'Hourly', example: '[logstash-]YYYY.MM.DD.HH'}, - {name: 'Daily', value: 'Daily', example: '[logstash-]YYYY.MM.DD'}, - {name: 'Weekly', value: 'Weekly', example: '[logstash-]GGGG.WW'}, - {name: 'Monthly', value: 'Monthly', example: '[logstash-]YYYY.MM'}, - {name: 'Yearly', value: 'Yearly', example: '[logstash-]YYYY'}, - ]; - - $scope.esVersions = [ - {name: '1.x', value: 1}, - {name: '2.x', value: 2}, - ]; - $scope.init = function() { $scope.isNew = true; $scope.datasources = []; @@ -59,7 +45,7 @@ function (angular, _, config) { backendSrv.get('/api/datasources/' + id).then(function(ds) { $scope.isNew = false; $scope.current = ds; - $scope.typeChanged(); + return $scope.typeChanged(); }); }; @@ -127,11 +113,6 @@ function (angular, _, config) { } }; - $scope.indexPatternTypeChanged = function() { - var def = _.findWhere($scope.indexPatternTypes, {value: $scope.current.jsonData.interval}); - $scope.current.database = def.example || 'es-index-name'; - }; - $scope.init(); }); diff --git a/public/app/features/org/partials/datasourceEdit.html b/public/app/features/org/partials/datasourceEdit.html index 6ea33e5a43c..fda9acde58a 100644 --- a/public/app/features/org/partials/datasourceEdit.html +++ b/public/app/features/org/partials/datasourceEdit.html @@ -42,7 +42,7 @@
    -
    +
    Testing....
    diff --git a/public/app/features/panel/panel_directive.js b/public/app/features/panel/panel_directive.js index ef36d3a1a2a..504c5843004 100644 --- a/public/app/features/panel/panel_directive.js +++ b/public/app/features/panel/panel_directive.js @@ -43,28 +43,30 @@ function (angular, $, config) { }; }); - module.service('dynamicDirectiveSrv', function($compile, $parse, datasourceSrv) { - var self = this; + module.directive('datasourceCustomSettingsView', function($compile) { + return { + restrict: 'E', + scope: { + dsMeta: "=", + current: "=", + }, + link: function(scope, elem) { + scope.$watch("dsMeta.module", function() { + if (!scope.dsMeta) { + return; + } - this.addDirective = function(options, type, editorScope) { - var panelEl = angular.element(document.createElement(options.name + '-' + type)); - options.parentElem.append(panelEl); - $compile(panelEl)(editorScope); - }; - - this.define = function(options) { - var editorScope; - options.scope.$watch(options.datasourceProperty, function(newVal) { - if (editorScope) { - editorScope.$destroy(); - options.parentElem.empty(); - } - - editorScope = options.scope.$new(); - datasourceSrv.get(newVal).then(function(ds) { - self.addDirective(options, ds.meta.type, editorScope); + System.import(scope.dsMeta.module).then(function(module) { + console.log('datasourceCustomSettingsView', module); + var panelEl = angular.element(document.createElement('datasource-custom-settings-view-' + scope.dsMeta.id)); + elem.append(panelEl); + $compile(panelEl)(scope); + }).catch(function(err) { + console.log('Failed to load plugin:', err); + scope.appEvent('alert-error', ['Plugin Load Error', 'Failed to load plugin ' + scope.dsMeta.id + ', ' + err]); + }); }); - }); + } }; }); @@ -99,20 +101,6 @@ function (angular, $, config) { }; }); - module.directive('datasourceEditorView', function(dynamicDirectiveSrv) { - return { - restrict: 'E', - link: function(scope, elem, attrs) { - dynamicDirectiveSrv.define({ - datasourceProperty: attrs.datasource, - name: attrs.name, - scope: scope, - parentElem: elem, - }); - } - }; - }); - module.directive('panelResizer', function($rootScope) { return { restrict: 'E', diff --git a/public/app/plugins/datasource/elasticsearch/datasource.d.ts b/public/app/plugins/datasource/elasticsearch/datasource.d.ts index 4de8bcda15d..a50d7ca49cc 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.d.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.d.ts @@ -1,3 +1,3 @@ declare var Datasource: any; -export {Datasource}; +export default Datasource; diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index e8760a93cc8..da31c6b50bb 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -7,7 +7,6 @@ define([ './index_pattern', './elastic_response', './query_ctrl', - './directives' ], function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticResponse) { 'use strict'; @@ -305,7 +304,5 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes }; } - return { - Datasource: ElasticDatasource, - }; + return ElasticDatasource; }); diff --git a/public/app/plugins/datasource/elasticsearch/directives.js b/public/app/plugins/datasource/elasticsearch/directives.js index a7ad8f6dfbf..9246ca90039 100644 --- a/public/app/plugins/datasource/elasticsearch/directives.js +++ b/public/app/plugins/datasource/elasticsearch/directives.js @@ -20,6 +20,10 @@ function (angular) { return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'}; }); + module.directive('datasourceCustomSettingsViewElasticsearch', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/config.html'}; + }); + module.directive('elasticMetricAgg', function() { return { templateUrl: 'app/plugins/datasource/elasticsearch/partials/metric_agg.html', diff --git a/public/app/plugins/datasource/elasticsearch/edit_view.ts b/public/app/plugins/datasource/elasticsearch/edit_view.ts new file mode 100644 index 00000000000..8315a389953 --- /dev/null +++ b/public/app/plugins/datasource/elasticsearch/edit_view.ts @@ -0,0 +1,38 @@ +/// + +import angular from 'angular'; +import _ from 'lodash'; + +export class EditViewCtrl { + + constructor($scope) { + $scope.indexPatternTypes = [ + {name: 'No pattern', value: undefined}, + {name: 'Hourly', value: 'Hourly', example: '[logstash-]YYYY.MM.DD.HH'}, + {name: 'Daily', value: 'Daily', example: '[logstash-]YYYY.MM.DD'}, + {name: 'Weekly', value: 'Weekly', example: '[logstash-]GGGG.WW'}, + {name: 'Monthly', value: 'Monthly', example: '[logstash-]YYYY.MM'}, + {name: 'Yearly', value: 'Yearly', example: '[logstash-]YYYY'}, + ]; + + $scope.esVersions = [ + {name: '1.x', value: 1}, + {name: '2.x', value: 2}, + ]; + + $scope.indexPatternTypeChanged = function() { + var def = _.findWhere($scope.indexPatternTypes, {value: $scope.current.jsonData.interval}); + $scope.current.database = def.example || 'es-index-name'; + }; + } +} + +function editViewDirective() { + return { + templateUrl: 'app/plugins/datasource/elasticsearch/partials/edit_view.html', + controller: EditViewCtrl, + }; +}; + + +export default editViewDirective; diff --git a/public/app/plugins/datasource/elasticsearch/module.js b/public/app/plugins/datasource/elasticsearch/module.js new file mode 100644 index 00000000000..958eb3eb8e7 --- /dev/null +++ b/public/app/plugins/datasource/elasticsearch/module.js @@ -0,0 +1,60 @@ +define([ + 'angular', + './datasource', + './edit_view', + './bucket_agg', + './metric_agg', +], +function (angular, ElasticDatasource, editView) { + 'use strict'; + + var module = angular.module('grafana.directives'); + + module.directive('metricQueryEditorElasticsearch', function() { + return {controller: 'ElasticQueryCtrl', templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.editor.html'}; + }); + + module.directive('metricQueryOptionsElasticsearch', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.options.html'}; + }); + + module.directive('annotationsQueryEditorElasticsearch', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'}; + }); + + module.directive('elasticMetricAgg', function() { + return { + templateUrl: 'app/plugins/datasource/elasticsearch/partials/metric_agg.html', + controller: 'ElasticMetricAggCtrl', + restrict: 'E', + scope: { + target: "=", + index: "=", + onChange: "&", + getFields: "&", + esVersion: '=' + } + }; + }); + + module.directive('elasticBucketAgg', function() { + return { + templateUrl: 'app/plugins/datasource/elasticsearch/partials/bucket_agg.html', + controller: 'ElasticBucketAggCtrl', + restrict: 'E', + scope: { + target: "=", + index: "=", + onChange: "&", + getFields: "&", + } + }; + }); + + module.directive('datasourceCustomSettingsViewElasticsearch', editView.default); + + return { + Datasource: ElasticDatasource, + }; + +}); diff --git a/public/app/plugins/datasource/elasticsearch/partials/config.html b/public/app/plugins/datasource/elasticsearch/partials/edit_view.html similarity index 96% rename from public/app/plugins/datasource/elasticsearch/partials/config.html rename to public/app/plugins/datasource/elasticsearch/partials/edit_view.html index 595588c1be0..2f5b011d8cc 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/config.html +++ b/public/app/plugins/datasource/elasticsearch/partials/edit_view.html @@ -42,8 +42,8 @@
    -
    +
    Default query settings
    @@ -53,7 +53,7 @@
  • + spellcheck='false' placeholder="example: >10s">
  • diff --git a/public/app/plugins/datasource/elasticsearch/plugin.json b/public/app/plugins/datasource/elasticsearch/plugin.json index c06f9e7ba99..fecdb3ae7cc 100644 --- a/public/app/plugins/datasource/elasticsearch/plugin.json +++ b/public/app/plugins/datasource/elasticsearch/plugin.json @@ -3,14 +3,7 @@ "name": "Elasticsearch", "id": "elasticsearch", - "serviceName": "ElasticDatasource", - - "module": "app/plugins/datasource/elasticsearch/datasource", - - "partials": { - "config": "app/plugins/datasource/elasticsearch/partials/config.html", - "annotations": "app/plugins/datasource/elasticsearch/partials/annotations.editor.html" - }, + "module": "app/plugins/datasource/elasticsearch/module", "defaultMatchFormat": "lucene", "annotations": true, diff --git a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts index 88700838cc0..a7e6a642550 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/datasource_specs.ts @@ -3,7 +3,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/co import moment from 'moment'; import angular from 'angular'; import helpers from 'test/specs/helpers'; -import {Datasource} from "../datasource"; +import Datasource from "../datasource"; describe('ElasticDatasource', function() { var ctx = new helpers.ServiceTestContext(); diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index 9a7360ba50a..d6f5f8475a4 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -3,7 +3,6 @@ "type": "datasource", "id": "graphite", - "serviceName": "GraphiteDatasource", "module": "app/plugins/datasource/graphite/datasource", "partials": { diff --git a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts index 52ec58cf5bc..439e865bd43 100644 --- a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts @@ -5,7 +5,7 @@ import {Datasource} from "../datasource"; describe('graphiteDatasource', function() { var ctx = new helpers.ServiceTestContext(); - var instanceSettings: any = {url:['']}; + var instanceSettings: any = {url: ['']}; beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); From 7ae81a2195dea7650d226144883ef0f2d269b56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 18:20:43 +0100 Subject: [PATCH 20/36] feat(plugins): annotations view work again for elasticsearch --- .../features/annotations/partials/editor.html | 2 +- public/app/features/panel/panel_directive.js | 43 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/public/app/features/annotations/partials/editor.html b/public/app/features/annotations/partials/editor.html index 0f244998c17..875f205c1f9 100644 --- a/public/app/features/annotations/partials/editor.html +++ b/public/app/features/annotations/partials/editor.html @@ -44,7 +44,7 @@ diff --git a/public/app/features/panel/panel_directive.js b/public/app/features/panel/panel_directive.js index 504c5843004..0c3ab11a9a7 100644 --- a/public/app/features/panel/panel_directive.js +++ b/public/app/features/panel/panel_directive.js @@ -56,8 +56,8 @@ function (angular, $, config) { return; } - System.import(scope.dsMeta.module).then(function(module) { - console.log('datasourceCustomSettingsView', module); + System.import(scope.dsMeta.module).then(function() { + elem.empty(); var panelEl = angular.element(document.createElement('datasource-custom-settings-view-' + scope.dsMeta.id)); elem.append(panelEl); $compile(panelEl)(scope); @@ -70,6 +70,45 @@ function (angular, $, config) { }; }); + module.service('dynamicDirectiveSrv', function($compile, $parse, datasourceSrv) { + var self = this; + + this.addDirective = function(options, type, editorScope) { + var panelEl = angular.element(document.createElement(options.name + '-' + type)); + options.parentElem.append(panelEl); + $compile(panelEl)(editorScope); + }; + + this.define = function(options) { + var editorScope; + options.scope.$watch(options.datasourceProperty, function(newVal) { + if (editorScope) { + editorScope.$destroy(); + options.parentElem.empty(); + } + + editorScope = options.scope.$new(); + datasourceSrv.get(newVal).then(function(ds) { + self.addDirective(options, ds.meta.id, editorScope); + }); + }); + }; + }); + + module.directive('datasourceEditorView', function(dynamicDirectiveSrv) { + return { + restrict: 'E', + link: function(scope, elem, attrs) { + dynamicDirectiveSrv.define({ + datasourceProperty: attrs.datasource, + name: attrs.name, + scope: scope, + parentElem: elem, + }); + } + }; + }); + module.directive('queryEditorLoader', function($compile, $parse, datasourceSrv) { return { restrict: 'E', From bc328cbed7aa6b10ae7f08d823b8311bff25fe08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 18:36:25 +0100 Subject: [PATCH 21/36] feat(plugins): upgraded Cloudwatch to new plugin schema --- .../datasource/cloudwatch/datasource.d.ts | 3 + .../datasource/cloudwatch/datasource.js | 53 ++++++++---------- .../cloudwatch/{directives.js => module.js} | 10 +++- .../partials/{config.html => edit_view.html} | 0 .../plugins/datasource/cloudwatch/plugin.json | 4 +- .../cloudwatch/specs/datasource_specs.ts | 20 +++---- .../datasource/elasticsearch/directives.js | 56 ------------------- 7 files changed, 47 insertions(+), 99 deletions(-) create mode 100644 public/app/plugins/datasource/cloudwatch/datasource.d.ts rename public/app/plugins/datasource/cloudwatch/{directives.js => module.js} (74%) rename public/app/plugins/datasource/cloudwatch/partials/{config.html => edit_view.html} (100%) delete mode 100644 public/app/plugins/datasource/elasticsearch/directives.js diff --git a/public/app/plugins/datasource/cloudwatch/datasource.d.ts b/public/app/plugins/datasource/cloudwatch/datasource.d.ts new file mode 100644 index 00000000000..a50d7ca49cc --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/datasource.d.ts @@ -0,0 +1,3 @@ +declare var Datasource: any; +export default Datasource; + diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index f606b6e3dc8..a2a74ca1883 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -4,24 +4,19 @@ define([ 'moment', 'app/core/utils/datemath', './query_ctrl', - './directives', ], function (angular, _, moment, dateMath) { 'use strict'; - var module = angular.module('grafana.services'); + /** @ngInject */ + function CloudWatchDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.type = 'cloudwatch'; + this.name = instanceSettings.name; + this.supportMetrics = true; + this.proxyUrl = instanceSettings.url; + this.defaultRegion = instanceSettings.jsonData.defaultRegion; - module.factory('CloudWatchDatasource', function($q, backendSrv, templateSrv) { - - function CloudWatchDatasource(datasource) { - this.type = 'cloudwatch'; - this.name = datasource.name; - this.supportMetrics = true; - this.proxyUrl = datasource.url; - this.defaultRegion = datasource.jsonData.defaultRegion; - } - - CloudWatchDatasource.prototype.query = function(options) { + this.query = function(options) { var start = convertToCloudWatchTime(options.range.from, false); var end = convertToCloudWatchTime(options.range.to, true); @@ -72,7 +67,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.performTimeSeriesQuery = function(query, start, end) { + this.performTimeSeriesQuery = function(query, start, end) { return this.awsRequest({ region: query.region, action: 'GetMetricStatistics', @@ -88,15 +83,15 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.getRegions = function() { + this.getRegions = function() { return this.awsRequest({action: '__GetRegions'}); }; - CloudWatchDatasource.prototype.getNamespaces = function() { + this.getNamespaces = function() { return this.awsRequest({action: '__GetNamespaces'}); }; - CloudWatchDatasource.prototype.getMetrics = function(namespace) { + this.getMetrics = function(namespace) { return this.awsRequest({ action: '__GetMetrics', parameters: { @@ -105,7 +100,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.getDimensionKeys = function(namespace) { + this.getDimensionKeys = function(namespace) { return this.awsRequest({ action: '__GetDimensions', parameters: { @@ -114,7 +109,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { + this.getDimensionValues = function(region, namespace, metricName, dimensionKey, filterDimensions) { var request = { region: templateSrv.replace(region), action: 'ListMetrics', @@ -141,7 +136,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.performEC2DescribeInstances = function(region, filters, instanceIds) { + this.performEC2DescribeInstances = function(region, filters, instanceIds) { return this.awsRequest({ region: region, action: 'DescribeInstances', @@ -149,7 +144,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.metricFindQuery = function(query) { + this.metricFindQuery = function(query) { var region; var namespace; var metricName; @@ -210,7 +205,7 @@ function (angular, _, moment, dateMath) { return $q.when([]); }; - CloudWatchDatasource.prototype.performDescribeAlarmsForMetric = function(region, namespace, metricName, dimensions, statistic, period) { + this.performDescribeAlarmsForMetric = function(region, namespace, metricName, dimensions, statistic, period) { return this.awsRequest({ region: region, action: 'DescribeAlarmsForMetric', @@ -218,7 +213,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.performDescribeAlarmHistory = function(region, alarmName, startDate, endDate) { + this.performDescribeAlarmHistory = function(region, alarmName, startDate, endDate) { return this.awsRequest({ region: region, action: 'DescribeAlarmHistory', @@ -226,7 +221,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.annotationQuery = function(options) { + this.annotationQuery = function(options) { var annotation = options.annotation; var region = templateSrv.replace(annotation.region); var namespace = templateSrv.replace(annotation.namespace); @@ -278,7 +273,7 @@ function (angular, _, moment, dateMath) { return d.promise; }; - CloudWatchDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { /* use billing metrics for test */ var region = this.defaultRegion; var namespace = 'AWS/Billing'; @@ -290,7 +285,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.awsRequest = function(data) { + this.awsRequest = function(data) { var options = { method: 'POST', url: this.proxyUrl, @@ -302,7 +297,7 @@ function (angular, _, moment, dateMath) { }); }; - CloudWatchDatasource.prototype.getDefaultRegion = function() { + this.getDefaultRegion = function() { return this.defaultRegion; }; @@ -361,7 +356,7 @@ function (angular, _, moment, dateMath) { }); } - return CloudWatchDatasource; - }); + } + return CloudWatchDatasource; }); diff --git a/public/app/plugins/datasource/cloudwatch/directives.js b/public/app/plugins/datasource/cloudwatch/module.js similarity index 74% rename from public/app/plugins/datasource/cloudwatch/directives.js rename to public/app/plugins/datasource/cloudwatch/module.js index a08d4fc8d9a..bb9d9102063 100644 --- a/public/app/plugins/datasource/cloudwatch/directives.js +++ b/public/app/plugins/datasource/cloudwatch/module.js @@ -1,8 +1,9 @@ define([ 'angular', + './datasource', './query_parameter_ctrl', ], -function (angular) { +function (angular, CloudWatchDatasource) { 'use strict'; var module = angular.module('grafana.directives'); @@ -28,4 +29,11 @@ function (angular) { }; }); + module.directive('datasourceCustomSettingsViewCloudwatch', function() { + return {templateUrl: 'app/plugins/datasource/cloudwatch/partials/edit_view.html'}; + }); + + return { + Datasource: CloudWatchDatasource + }; }); diff --git a/public/app/plugins/datasource/cloudwatch/partials/config.html b/public/app/plugins/datasource/cloudwatch/partials/edit_view.html similarity index 100% rename from public/app/plugins/datasource/cloudwatch/partials/config.html rename to public/app/plugins/datasource/cloudwatch/partials/edit_view.html diff --git a/public/app/plugins/datasource/cloudwatch/plugin.json b/public/app/plugins/datasource/cloudwatch/plugin.json index 5e54db64f52..68e0a8d1dae 100644 --- a/public/app/plugins/datasource/cloudwatch/plugin.json +++ b/public/app/plugins/datasource/cloudwatch/plugin.json @@ -3,9 +3,7 @@ "name": "CloudWatch", "id": "cloudwatch", - "serviceName": "CloudWatchDatasource", - - "module": "app/plugins/datasource/cloudwatch/datasource", + "module": "app/plugins/datasource/cloudwatch/module", "partials": { "config": "app/plugins/datasource/cloudwatch/partials/config.html", diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts index 55603232fdf..7c5c06839de 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts @@ -3,25 +3,25 @@ import "../datasource"; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import moment from 'moment'; import helpers from 'test/specs/helpers'; +import Datasource from "../datasource"; describe('CloudWatchDatasource', function() { var ctx = new helpers.ServiceTestContext(); + var instanceSettings = { + jsonData: {defaultRegion: 'us-east-1', access: 'proxy'}, + }; beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); beforeEach(angularMocks.module('grafana.controllers')); - beforeEach(ctx.providePhase(['templateSrv', 'backendSrv'])); - beforeEach(ctx.createService('CloudWatchDatasource')); - beforeEach(function() { - ctx.ds = new ctx.service({ - jsonData: { - defaultRegion: 'us-east-1', - access: 'proxy' - } - }); - }); + beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + ctx.$q = $q; + ctx.$httpBackend = $httpBackend; + ctx.$rootScope = $rootScope; + ctx.ds = $injector.instantiate(Datasource, {instanceSettings: instanceSettings}); + })); describe('When performing CloudWatch query', function() { var requestParams; diff --git a/public/app/plugins/datasource/elasticsearch/directives.js b/public/app/plugins/datasource/elasticsearch/directives.js deleted file mode 100644 index 9246ca90039..00000000000 --- a/public/app/plugins/datasource/elasticsearch/directives.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - 'angular', - './bucket_agg', - './metric_agg', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.directives'); - - module.directive('metricQueryEditorElasticsearch', function() { - return {controller: 'ElasticQueryCtrl', templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.editor.html'}; - }); - - module.directive('metricQueryOptionsElasticsearch', function() { - return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.options.html'}; - }); - - module.directive('annotationsQueryEditorElasticsearch', function() { - return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'}; - }); - - module.directive('datasourceCustomSettingsViewElasticsearch', function() { - return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/config.html'}; - }); - - module.directive('elasticMetricAgg', function() { - return { - templateUrl: 'app/plugins/datasource/elasticsearch/partials/metric_agg.html', - controller: 'ElasticMetricAggCtrl', - restrict: 'E', - scope: { - target: "=", - index: "=", - onChange: "&", - getFields: "&", - esVersion: '=' - } - }; - }); - - module.directive('elasticBucketAgg', function() { - return { - templateUrl: 'app/plugins/datasource/elasticsearch/partials/bucket_agg.html', - controller: 'ElasticBucketAggCtrl', - restrict: 'E', - scope: { - target: "=", - index: "=", - onChange: "&", - getFields: "&", - } - }; - }); - -}); From 36ebfc747ad0190c81a1bf6cb0266412cc3a4e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 18:44:13 +0100 Subject: [PATCH 22/36] feat(plugins): more upgrading work --- .../datasource/elasticsearch/directives.js | 56 +++++++++++++++++++ .../plugins/datasource/grafana/datasource.js | 30 ---------- .../plugins/datasource/grafana/directives.js | 13 ----- .../plugins/datasource/grafana/plugin.json | 6 +- .../plugins/datasource/mixed/datasource.ts | 5 -- 5 files changed, 58 insertions(+), 52 deletions(-) create mode 100644 public/app/plugins/datasource/elasticsearch/directives.js delete mode 100644 public/app/plugins/datasource/grafana/datasource.js delete mode 100644 public/app/plugins/datasource/grafana/directives.js diff --git a/public/app/plugins/datasource/elasticsearch/directives.js b/public/app/plugins/datasource/elasticsearch/directives.js new file mode 100644 index 00000000000..3bb27885ef2 --- /dev/null +++ b/public/app/plugins/datasource/elasticsearch/directives.js @@ -0,0 +1,56 @@ +define([ + 'angular', + './bucket_agg', + './metric_agg', +], +function (angular) { + 'use strict'; + + var module = angular.module('grafana.directives'); + + module.directive('metricQueryEditorElasticsearch', function() { + return {controller: 'ElasticQueryCtrl', templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.editor.html'}; + }); + + module.directive('metricQueryOptionsElasticsearch', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.options.html'}; + }); + + module.directive('annotationsQueryEditorElasticsearch', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'}; + }); + + module.directive('elastic', function() { + return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/config.html'}; + }); + + module.directive('elasticMetricAgg', function() { + return { + templateUrl: 'app/plugins/datasource/elasticsearch/partials/metric_agg.html', + controller: 'ElasticMetricAggCtrl', + restrict: 'E', + scope: { + target: "=", + index: "=", + onChange: "&", + getFields: "&", + esVersion: '=' + } + }; + }); + + module.directive('elasticBucketAgg', function() { + return { + templateUrl: 'app/plugins/datasource/elasticsearch/partials/bucket_agg.html', + controller: 'ElasticBucketAggCtrl', + restrict: 'E', + scope: { + target: "=", + index: "=", + onChange: "&", + getFields: "&", + } + }; + }); + +}); diff --git a/public/app/plugins/datasource/grafana/datasource.js b/public/app/plugins/datasource/grafana/datasource.js deleted file mode 100644 index 2bc1e08137e..00000000000 --- a/public/app/plugins/datasource/grafana/datasource.js +++ /dev/null @@ -1,30 +0,0 @@ -define([ - 'angular' -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.services'); - - module.factory('GrafanaDatasource', function($q, backendSrv) { - - function GrafanaDatasource() { - } - - GrafanaDatasource.prototype.query = function(options) { - return backendSrv.get('/api/metrics/test', { - from: options.range.from.valueOf(), - to: options.range.to.valueOf(), - maxDataPoints: options.maxDataPoints - }); - }; - - GrafanaDatasource.prototype.metricFindQuery = function() { - return $q.when([]); - }; - - return GrafanaDatasource; - - }); - -}); diff --git a/public/app/plugins/datasource/grafana/directives.js b/public/app/plugins/datasource/grafana/directives.js deleted file mode 100644 index 9c29340e430..00000000000 --- a/public/app/plugins/datasource/grafana/directives.js +++ /dev/null @@ -1,13 +0,0 @@ -define([ - 'angular', -], -function (angular) { - 'use strict'; - - var module = angular.module('grafana.directives'); - - module.directive('metricQueryEditorGrafana', function() { - return {templateUrl: 'app/plugins/datasource/grafana/partials/query.editor.html'}; - }); - -}); diff --git a/public/app/plugins/datasource/grafana/plugin.json b/public/app/plugins/datasource/grafana/plugin.json index 5b74f9ea613..4d4f55b647d 100644 --- a/public/app/plugins/datasource/grafana/plugin.json +++ b/public/app/plugins/datasource/grafana/plugin.json @@ -3,10 +3,8 @@ "name": "Grafana", "id": "grafana", + "module": "app/plugins/datasource/grafana/module", + "builtIn": true, - - "serviceName": "GrafanaDatasource", - - "module": "app/plugins/datasource/grafana/datasource", "metrics": true } diff --git a/public/app/plugins/datasource/mixed/datasource.ts b/public/app/plugins/datasource/mixed/datasource.ts index 874773e7f45..bd0628fe210 100644 --- a/public/app/plugins/datasource/mixed/datasource.ts +++ b/public/app/plugins/datasource/mixed/datasource.ts @@ -30,8 +30,3 @@ class MixedDatasource { } export {MixedDatasource, MixedDatasource as Datasource} - -// var module = angular.module('grafana.services'); -// module.factory('MixedDatasource', MixedDatasource); -// - From ca3405afc5e689c37a444619708da282005b51d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 19:03:03 +0100 Subject: [PATCH 23/36] feat(plugins): moved http settings to directive instad of just ng-include partial --- public/app/features/datasources/all.js | 4 ++++ .../datasourceEditCtrl.js => datasources/edit_ctrl.js} | 7 ++++--- .../{org/datasourcesCtrl.js => datasources/list_ctrl.js} | 0 .../datasourceEdit.html => datasources/partials/edit.html} | 0 .../partials/http_settings.html} | 2 ++ .../datasources.html => datasources/partials/list.html} | 0 public/app/features/org/all.js | 3 +-- .../datasource/elasticsearch/partials/edit_view.html | 3 +-- public/app/plugins/datasource/graphite/datasource.d.ts | 2 +- public/app/plugins/datasource/graphite/datasource.js | 5 +---- .../datasource/graphite/{directives.js => module.js} | 6 +++++- .../app/plugins/datasource/graphite/partials/config.html | 3 +-- public/app/plugins/datasource/graphite/plugin.json | 6 +----- .../plugins/datasource/graphite/specs/datasource_specs.ts | 2 +- .../app/plugins/datasource/influxdb/partials/config.html | 3 +-- .../app/plugins/datasource/opentsdb/partials/config.html | 4 +--- .../app/plugins/datasource/prometheus/partials/config.html | 4 +--- tasks/options/watch.js | 2 +- 18 files changed, 26 insertions(+), 30 deletions(-) create mode 100644 public/app/features/datasources/all.js rename public/app/features/{org/datasourceEditCtrl.js => datasources/edit_ctrl.js} (95%) rename public/app/features/{org/datasourcesCtrl.js => datasources/list_ctrl.js} (100%) rename public/app/features/{org/partials/datasourceEdit.html => datasources/partials/edit.html} (100%) rename public/app/features/{org/partials/datasourceHttpConfig.html => datasources/partials/http_settings.html} (99%) rename public/app/features/{org/partials/datasources.html => datasources/partials/list.html} (100%) rename public/app/plugins/datasource/graphite/{directives.js => module.js} (84%) diff --git a/public/app/features/datasources/all.js b/public/app/features/datasources/all.js new file mode 100644 index 00000000000..b181fd475c2 --- /dev/null +++ b/public/app/features/datasources/all.js @@ -0,0 +1,4 @@ +define([ + './list_ctrl', + './edit_ctrl', +], function () {}); diff --git a/public/app/features/org/datasourceEditCtrl.js b/public/app/features/datasources/edit_ctrl.js similarity index 95% rename from public/app/features/org/datasourceEditCtrl.js rename to public/app/features/datasources/edit_ctrl.js index 5eadd9a07b1..468be95e24b 100644 --- a/public/app/features/org/datasourceEditCtrl.js +++ b/public/app/features/datasources/edit_ctrl.js @@ -9,9 +9,11 @@ function (angular, _, config) { var module = angular.module('grafana.controllers'); var datasourceTypes = []; - module.controller('DataSourceEditCtrl', function($scope, $q, backendSrv, $routeParams, $location, datasourceSrv) { + module.directive('datasourceHttpSettings', function() { + return {templateUrl: 'app/features/datasources/partials/http_settings.html'}; + }); - $scope.httpConfigPartialSrc = 'app/features/org/partials/datasourceHttpConfig.html'; + module.controller('DataSourceEditCtrl', function($scope, $q, backendSrv, $routeParams, $location, datasourceSrv) { var defaults = {name: '', type: 'graphite', url: '', access: 'proxy', jsonData: {}}; @@ -114,6 +116,5 @@ function (angular, _, config) { }; $scope.init(); - }); }); diff --git a/public/app/features/org/datasourcesCtrl.js b/public/app/features/datasources/list_ctrl.js similarity index 100% rename from public/app/features/org/datasourcesCtrl.js rename to public/app/features/datasources/list_ctrl.js diff --git a/public/app/features/org/partials/datasourceEdit.html b/public/app/features/datasources/partials/edit.html similarity index 100% rename from public/app/features/org/partials/datasourceEdit.html rename to public/app/features/datasources/partials/edit.html diff --git a/public/app/features/org/partials/datasourceHttpConfig.html b/public/app/features/datasources/partials/http_settings.html similarity index 99% rename from public/app/features/org/partials/datasourceHttpConfig.html rename to public/app/features/datasources/partials/http_settings.html index 4b5a72dbf11..bd70e419326 100644 --- a/public/app/features/org/partials/datasourceHttpConfig.html +++ b/public/app/features/datasources/partials/http_settings.html @@ -53,3 +53,5 @@
    + +
    diff --git a/public/app/features/org/partials/datasources.html b/public/app/features/datasources/partials/list.html similarity index 100% rename from public/app/features/org/partials/datasources.html rename to public/app/features/datasources/partials/list.html diff --git a/public/app/features/org/all.js b/public/app/features/org/all.js index d03d270709d..d232b3bcd0a 100644 --- a/public/app/features/org/all.js +++ b/public/app/features/org/all.js @@ -1,9 +1,8 @@ define([ - './datasourcesCtrl', - './datasourceEditCtrl', './orgUsersCtrl', './newOrgCtrl', './userInviteCtrl', './orgApiKeysCtrl', './orgDetailsCtrl', + '../datasources/all', ], function () {}); diff --git a/public/app/plugins/datasource/elasticsearch/partials/edit_view.html b/public/app/plugins/datasource/elasticsearch/partials/edit_view.html index 2f5b011d8cc..63a70ab8912 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/edit_view.html +++ b/public/app/plugins/datasource/elasticsearch/partials/edit_view.html @@ -1,5 +1,4 @@ -
    -
    +
    Elasticsearch details
    diff --git a/public/app/plugins/datasource/graphite/datasource.d.ts b/public/app/plugins/datasource/graphite/datasource.d.ts index 4de8bcda15d..a50d7ca49cc 100644 --- a/public/app/plugins/datasource/graphite/datasource.d.ts +++ b/public/app/plugins/datasource/graphite/datasource.d.ts @@ -1,3 +1,3 @@ declare var Datasource: any; -export {Datasource}; +export default Datasource; diff --git a/public/app/plugins/datasource/graphite/datasource.js b/public/app/plugins/datasource/graphite/datasource.js index 1baac516790..3a169eaae4e 100644 --- a/public/app/plugins/datasource/graphite/datasource.js +++ b/public/app/plugins/datasource/graphite/datasource.js @@ -4,7 +4,6 @@ define([ 'jquery', 'app/core/config', 'app/core/utils/datemath', - './directives', './query_ctrl', './func_editor', './add_graphite_func', @@ -293,7 +292,5 @@ function (angular, _, $, config, dateMath) { }; } - return { - Datasource: GraphiteDatasource - }; + return GraphiteDatasource; }); diff --git a/public/app/plugins/datasource/graphite/directives.js b/public/app/plugins/datasource/graphite/module.js similarity index 84% rename from public/app/plugins/datasource/graphite/directives.js rename to public/app/plugins/datasource/graphite/module.js index 91e52bb9546..b7910448304 100644 --- a/public/app/plugins/datasource/graphite/directives.js +++ b/public/app/plugins/datasource/graphite/module.js @@ -1,7 +1,8 @@ define([ 'angular', + './datasource', ], -function (angular) { +function (angular, GraphiteDatasource) { 'use strict'; var module = angular.module('grafana.directives'); @@ -18,4 +19,7 @@ function (angular) { return {templateUrl: 'app/plugins/datasource/graphite/partials/annotations.editor.html'}; }); + return { + Datasource: GraphiteDatasource, + }; }); diff --git a/public/app/plugins/datasource/graphite/partials/config.html b/public/app/plugins/datasource/graphite/partials/config.html index 0b454f4dc74..9f5259cb2ea 100644 --- a/public/app/plugins/datasource/graphite/partials/config.html +++ b/public/app/plugins/datasource/graphite/partials/config.html @@ -1,3 +1,2 @@ -
    - + diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index d6f5f8475a4..175ac5fa659 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -3,11 +3,7 @@ "type": "datasource", "id": "graphite", - "module": "app/plugins/datasource/graphite/datasource", - - "partials": { - "config": "app/plugins/datasource/graphite/partials/config.html" - }, + "module": "app/plugins/datasource/graphite/module", "defaultMatchFormat": "glob", "metrics": true, diff --git a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts index 439e865bd43..810e1be3516 100644 --- a/public/app/plugins/datasource/graphite/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/graphite/specs/datasource_specs.ts @@ -1,7 +1,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import helpers from 'test/specs/helpers'; -import {Datasource} from "../datasource"; +import Datasource from "../datasource"; describe('graphiteDatasource', function() { var ctx = new helpers.ServiceTestContext(); diff --git a/public/app/plugins/datasource/influxdb/partials/config.html b/public/app/plugins/datasource/influxdb/partials/config.html index 4d51a33e6b2..8a85ec2a16a 100644 --- a/public/app/plugins/datasource/influxdb/partials/config.html +++ b/public/app/plugins/datasource/influxdb/partials/config.html @@ -1,5 +1,4 @@ -
    -
    +
    InfluxDB Details
    diff --git a/public/app/plugins/datasource/opentsdb/partials/config.html b/public/app/plugins/datasource/opentsdb/partials/config.html index bb5bdda1e20..9f5259cb2ea 100644 --- a/public/app/plugins/datasource/opentsdb/partials/config.html +++ b/public/app/plugins/datasource/opentsdb/partials/config.html @@ -1,4 +1,2 @@ -
    - -
    + diff --git a/public/app/plugins/datasource/prometheus/partials/config.html b/public/app/plugins/datasource/prometheus/partials/config.html index bb5bdda1e20..9f5259cb2ea 100644 --- a/public/app/plugins/datasource/prometheus/partials/config.html +++ b/public/app/plugins/datasource/prometheus/partials/config.html @@ -1,4 +1,2 @@ -
    - -
    + diff --git a/tasks/options/watch.js b/tasks/options/watch.js index 2be128a3112..db250d56862 100644 --- a/tasks/options/watch.js +++ b/tasks/options/watch.js @@ -6,7 +6,7 @@ module.exports = function(config, grunt) { grunt.log.writeln('File Changed: ' + filepath); - if (/(\.html)$/.test(filepath)) { + if (/(\.html)|(\.json)$/.test(filepath)) { newPath = filepath.replace(/^public/, 'public_gen'); grunt.log.writeln('Copying to ' + newPath); grunt.file.copy(filepath, newPath); From 15546dd84e871299b1eea3fea5c768c243395447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 19:14:59 +0100 Subject: [PATCH 24/36] feat(plugins): added better error message when trying to load data source plugin module that is missing datasource constructor --- public/app/core/services/alert_srv.js | 4 ++++ public/app/core/services/datasource_srv.js | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/public/app/core/services/alert_srv.js b/public/app/core/services/alert_srv.js index cecc8eadadf..463be459659 100644 --- a/public/app/core/services/alert_srv.js +++ b/public/app/core/services/alert_srv.js @@ -46,6 +46,10 @@ function (angular, _, coreModule) { }, timeout); } + if (!$rootScope.$$phase) { + $rootScope.$digest(); + } + return(newAlert); }; diff --git a/public/app/core/services/datasource_srv.js b/public/app/core/services/datasource_srv.js index 1f2b492ee93..07e3f004d45 100644 --- a/public/app/core/services/datasource_srv.js +++ b/public/app/core/services/datasource_srv.js @@ -7,7 +7,7 @@ define([ function (angular, _, coreModule, config) { 'use strict'; - coreModule.default.service('datasourceSrv', function($q, $injector) { + coreModule.default.service('datasourceSrv', function($q, $injector, $rootScope) { var self = this; this.init = function() { @@ -60,7 +60,6 @@ function (angular, _, coreModule, config) { var deferred = $q.defer(); var pluginDef = dsConfig.meta; - console.log(pluginDef); System.import(pluginDef.module).then(function(plugin) { // check if its in cache now if (self.datasources[name]) { @@ -70,7 +69,7 @@ function (angular, _, coreModule, config) { // plugin module needs to export a constructor function named Datasource if (!plugin.Datasource) { - return; + throw "Plugin module is missing Datasource constructor"; } var instance = $injector.instantiate(plugin.Datasource, {instanceSettings: dsConfig}); @@ -79,7 +78,7 @@ function (angular, _, coreModule, config) { self.datasources[name] = instance; deferred.resolve(instance); }).catch(function(err) { - console.log('Failed to load data source: ' + err); + $rootScope.appEvent('alert-error', [dsConfig.name + ' plugin failed', err.toString()]); }); return deferred.promise; From b76449d151f2b99f1f8592805ec5b9848043af3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 21:42:26 +0100 Subject: [PATCH 25/36] feat(plugins): upgraded influxdb to new data source plugin model --- .../plugins/datasource/influxdb/datasource.js | 47 ++++++++----------- .../influxdb/{directives.js => module.js} | 10 +++- .../plugins/datasource/influxdb/plugin.json | 8 +--- 3 files changed, 30 insertions(+), 35 deletions(-) rename public/app/plugins/datasource/influxdb/{directives.js => module.js} (69%) diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index 9516abdeacd..62eca66dd9e 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -4,7 +4,6 @@ define([ 'app/core/utils/datemath', './influx_series', './influx_query', - './directives', './query_ctrl', ], function (angular, _, dateMath, InfluxSeries, InfluxQuery) { @@ -12,27 +11,22 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { InfluxQuery = InfluxQuery.default; - var module = angular.module('grafana.services'); + function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.type = 'influxdb'; + this.urls = _.map(instanceSettings.url.split(','), function(url) { + return url.trim(); + }); - module.factory('InfluxDatasource', function($q, backendSrv, templateSrv) { + this.username = instanceSettings.username; + this.password = instanceSettings.password; + this.name = instanceSettings.name; + this.database = instanceSettings.database; + this.basicAuth = instanceSettings.basicAuth; - function InfluxDatasource(datasource) { - this.type = 'influxdb'; - this.urls = _.map(datasource.url.split(','), function(url) { - return url.trim(); - }); + this.supportAnnotations = true; + this.supportMetrics = true; - this.username = datasource.username; - this.password = datasource.password; - this.name = datasource.name; - this.database = datasource.database; - this.basicAuth = datasource.basicAuth; - - this.supportAnnotations = true; - this.supportMetrics = true; - } - - InfluxDatasource.prototype.query = function(options) { + this.query = function(options) { var timeFilter = getTimeFilter(options); var queryTargets = []; var i, y; @@ -93,7 +87,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { }); }; - InfluxDatasource.prototype.annotationQuery = function(options) { + this.annotationQuery = function(options) { var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw}); var query = options.annotation.query.replace('$timeFilter', timeFilter); query = templateSrv.replace(query); @@ -106,7 +100,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { }); }; - InfluxDatasource.prototype.metricFindQuery = function (query) { + this.metricFindQuery = function (query) { var interpolated; try { interpolated = templateSrv.replace(query); @@ -133,17 +127,17 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { }); }; - InfluxDatasource.prototype._seriesQuery = function(query) { + this._seriesQuery = function(query) { return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'}); }; - InfluxDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () { return { status: "success", message: "Data source is working", title: "Success" }; }); }; - InfluxDatasource.prototype._influxRequest = function(method, url, data) { + this._influxRequest = function(method, url, data) { var self = this; var currentUrl = self.urls.shift(); @@ -219,9 +213,8 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { } return (date.valueOf() / 1000).toFixed(0) + 's'; } + } - return InfluxDatasource; - - }); + return InfluxDatasource; }); diff --git a/public/app/plugins/datasource/influxdb/directives.js b/public/app/plugins/datasource/influxdb/module.js similarity index 69% rename from public/app/plugins/datasource/influxdb/directives.js rename to public/app/plugins/datasource/influxdb/module.js index a4c66137751..2a15ecad839 100644 --- a/public/app/plugins/datasource/influxdb/directives.js +++ b/public/app/plugins/datasource/influxdb/module.js @@ -1,7 +1,8 @@ define([ 'angular', + './datasource', ], -function (angular) { +function (angular, InfluxDatasource) { 'use strict'; var module = angular.module('grafana.directives'); @@ -18,4 +19,11 @@ function (angular) { return {templateUrl: 'app/plugins/datasource/influxdb/partials/annotations.editor.html'}; }); + module.directive('datasourceCustomSettingsViewInfluxdb', function() { + return {templateUrl: 'app/plugins/datasource/influxdb/partials/config.html'}; + }); + + return { + Datasource: InfluxDatasource + }; }); diff --git a/public/app/plugins/datasource/influxdb/plugin.json b/public/app/plugins/datasource/influxdb/plugin.json index 3a9aea175cb..29d6a5a0f58 100644 --- a/public/app/plugins/datasource/influxdb/plugin.json +++ b/public/app/plugins/datasource/influxdb/plugin.json @@ -3,13 +3,7 @@ "name": "InfluxDB 0.9.x", "id": "influxdb", - "serviceName": "InfluxDatasource", - - "module": "app/plugins/datasource/influxdb/datasource", - - "partials": { - "config": "app/plugins/datasource/influxdb/partials/config.html" - }, + "module": "app/plugins/datasource/influxdb/module", "defaultMatchFormat": "regex values", "metrics": true, From 35f40b7312f2432aefcd15473b6955b3e4ef5779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 21:54:03 +0100 Subject: [PATCH 26/36] feat(plugins): upgraded opentsdb --- public/app/core/routes/all.js | 6 +- .../datasource/opentsdb/datasource.d.ts | 3 + .../plugins/datasource/opentsdb/datasource.js | 38 +++++----- .../opentsdb/{directives.js => module.js} | 10 ++- .../plugins/datasource/opentsdb/plugin.json | 7 +- .../opentsdb/specs/datasource-specs.ts | 71 +++++++++++++++++++ public/test/specs/opentsdbDatasource-specs.js | 71 ------------------- 7 files changed, 103 insertions(+), 103 deletions(-) create mode 100644 public/app/plugins/datasource/opentsdb/datasource.d.ts rename public/app/plugins/datasource/opentsdb/{directives.js => module.js} (53%) create mode 100644 public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts delete mode 100644 public/test/specs/opentsdbDatasource-specs.js diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index 1f18210f8a9..0d4741c9e47 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -42,17 +42,17 @@ define([ controller : 'DashboardImportCtrl', }) .when('/datasources', { - templateUrl: 'app/features/org/partials/datasources.html', + templateUrl: 'app/features/datasources/partials/list.html', controller : 'DataSourcesCtrl', resolve: loadOrgBundle, }) .when('/datasources/edit/:id', { - templateUrl: 'app/features/org/partials/datasourceEdit.html', + templateUrl: 'app/features/datasources/partials/edit.html', controller : 'DataSourceEditCtrl', resolve: loadOrgBundle, }) .when('/datasources/new', { - templateUrl: 'app/features/org/partials/datasourceEdit.html', + templateUrl: 'app/features/datasources/partials/edit.html', controller : 'DataSourceEditCtrl', resolve: loadOrgBundle, }) diff --git a/public/app/plugins/datasource/opentsdb/datasource.d.ts b/public/app/plugins/datasource/opentsdb/datasource.d.ts new file mode 100644 index 00000000000..a50d7ca49cc --- /dev/null +++ b/public/app/plugins/datasource/opentsdb/datasource.d.ts @@ -0,0 +1,3 @@ +declare var Datasource: any; +export default Datasource; + diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index b7d4bd2d37b..67b3f43a1ed 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -3,25 +3,19 @@ define([ 'lodash', 'app/core/utils/datemath', 'moment', - './directives', './queryCtrl', ], function (angular, _, dateMath) { 'use strict'; - var module = angular.module('grafana.services'); - - module.factory('OpenTSDBDatasource', function($q, backendSrv, templateSrv) { - - function OpenTSDBDatasource(datasource) { - this.type = 'opentsdb'; - this.url = datasource.url; - this.name = datasource.name; - this.supportMetrics = true; - } + function OpenTSDBDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.type = 'opentsdb'; + this.url = instanceSettings.url; + this.name = instanceSettings.name; + this.supportMetrics = true; // Called once per panel (graph) - OpenTSDBDatasource.prototype.query = function(options) { + this.query = function(options) { var start = convertToTSDBTime(options.rangeRaw.from, false); var end = convertToTSDBTime(options.rangeRaw.to, true); var qs = []; @@ -60,7 +54,7 @@ function (angular, _, dateMath) { }); }; - OpenTSDBDatasource.prototype.performTimeSeriesQuery = function(queries, start, end) { + this.performTimeSeriesQuery = function(queries, start, end) { var reqBody = { start: start, queries: queries @@ -80,13 +74,13 @@ function (angular, _, dateMath) { return backendSrv.datasourceRequest(options); }; - OpenTSDBDatasource.prototype._performSuggestQuery = function(query, type) { + this._performSuggestQuery = function(query, type) { return this._get('/api/suggest', {type: type, q: query, max: 1000}).then(function(result) { return result.data; }); }; - OpenTSDBDatasource.prototype._performMetricKeyValueLookup = function(metric, key) { + this._performMetricKeyValueLookup = function(metric, key) { if(!metric || !key) { return $q.when([]); } @@ -105,7 +99,7 @@ function (angular, _, dateMath) { }); }; - OpenTSDBDatasource.prototype._performMetricKeyLookup = function(metric) { + this._performMetricKeyLookup = function(metric) { if(!metric) { return $q.when([]); } return this._get('/api/search/lookup', {m: metric, limit: 1000}).then(function(result) { @@ -122,7 +116,7 @@ function (angular, _, dateMath) { }); }; - OpenTSDBDatasource.prototype._get = function(relativeUrl, params) { + this._get = function(relativeUrl, params) { return backendSrv.datasourceRequest({ method: 'GET', url: this.url + relativeUrl, @@ -130,7 +124,7 @@ function (angular, _, dateMath) { }); }; - OpenTSDBDatasource.prototype.metricFindQuery = function(query) { + this.metricFindQuery = function(query) { if (!query) { return $q.when([]); } var interpolated; @@ -181,14 +175,14 @@ function (angular, _, dateMath) { return $q.when([]); }; - OpenTSDBDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { return this._performSuggestQuery('cpu', 'metrics').then(function () { return { status: "success", message: "Data source is working", title: "Success" }; }); }; var aggregatorsPromise = null; - OpenTSDBDatasource.prototype.getAggregators = function() { + this.getAggregators = function() { if (aggregatorsPromise) { return aggregatorsPromise; } aggregatorsPromise = this._get('/api/aggregators').then(function(result) { @@ -311,7 +305,7 @@ function (angular, _, dateMath) { return date.valueOf(); } - return OpenTSDBDatasource; - }); + } + return OpenTSDBDatasource; }); diff --git a/public/app/plugins/datasource/opentsdb/directives.js b/public/app/plugins/datasource/opentsdb/module.js similarity index 53% rename from public/app/plugins/datasource/opentsdb/directives.js rename to public/app/plugins/datasource/opentsdb/module.js index 3ff4c3c2ccc..82a5a5e25d6 100644 --- a/public/app/plugins/datasource/opentsdb/directives.js +++ b/public/app/plugins/datasource/opentsdb/module.js @@ -1,7 +1,8 @@ define([ 'angular', + './datasource', ], -function (angular) { +function (angular, OpenTsDatasource) { 'use strict'; var module = angular.module('grafana.directives'); @@ -13,4 +14,11 @@ function (angular) { }; }); + module.directive('datasourceCustomSettingsViewOpentsdb', function() { + return {templateUrl: 'app/plugins/datasource/opentsdb/partials/config.html'}; + }); + + return { + Datasource: OpenTsDatasource + }; }); diff --git a/public/app/plugins/datasource/opentsdb/plugin.json b/public/app/plugins/datasource/opentsdb/plugin.json index a72e09a1ab0..ec01b48c24b 100644 --- a/public/app/plugins/datasource/opentsdb/plugin.json +++ b/public/app/plugins/datasource/opentsdb/plugin.json @@ -3,12 +3,7 @@ "name": "OpenTSDB", "id": "opentsdb", - "serviceName": "OpenTSDBDatasource", - "module": "app/plugins/datasource/opentsdb/datasource", - - "partials": { - "config": "app/plugins/datasource/opentsdb/partials/config.html" - }, + "module": "app/plugins/datasource/opentsdb/module", "metrics": true, "defaultMatchFormat": "pipe" diff --git a/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts new file mode 100644 index 00000000000..b1ad1b93737 --- /dev/null +++ b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts @@ -0,0 +1,71 @@ +import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; +import helpers from 'test/specs/helpers'; +import Datasource from "../datasource"; + +describe('opentsdb', function() { + var ctx = new helpers.ServiceTestContext(); + var instanceSettings = {url: '' }; + + beforeEach(angularMocks.module('grafana.core')); + beforeEach(angularMocks.module('grafana.services')); + beforeEach(ctx.providePhase(['backendSrv'])); + + beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + ctx.$q = $q; + ctx.$httpBackend = $httpBackend; + ctx.$rootScope = $rootScope; + ctx.ds = $injector.instantiate(Datasource, {instanceSettings: instanceSettings}); + })); + + describe('When performing metricFindQuery', function() { + var results; + var requestOptions; + + beforeEach(function() { + ctx.backendSrv.datasourceRequest = function(options) { + requestOptions = options; + return ctx.$q.when({data: [{ target: 'prod1.count', datapoints: [[10, 1], [12,1]] }]}); + }; + }); + + it('metrics() should generate api suggest query', function() { + ctx.ds.metricFindQuery('metrics(pew)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/suggest'); + expect(requestOptions.params.type).to.be('metrics'); + expect(requestOptions.params.q).to.be('pew'); + }); + + it('tag_names(cpu) should generate looku query', function() { + ctx.ds.metricFindQuery('tag_names(cpu)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/search/lookup'); + expect(requestOptions.params.m).to.be('cpu'); + }); + + it('tag_values(cpu, test) should generate looku query', function() { + ctx.ds.metricFindQuery('tag_values(cpu, hostname)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/search/lookup'); + expect(requestOptions.params.m).to.be('cpu{hostname=*}'); + }); + + it('suggest_tagk() should generate api suggest query', function() { + ctx.ds.metricFindQuery('suggest_tagk(foo)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/suggest'); + expect(requestOptions.params.type).to.be('tagk'); + expect(requestOptions.params.q).to.be('foo'); + }); + + it('suggest_tagv() should generate api suggest query', function() { + ctx.ds.metricFindQuery('suggest_tagv(bar)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/suggest'); + expect(requestOptions.params.type).to.be('tagv'); + expect(requestOptions.params.q).to.be('bar'); + }); + }); + +}); + diff --git a/public/test/specs/opentsdbDatasource-specs.js b/public/test/specs/opentsdbDatasource-specs.js deleted file mode 100644 index 663c9bd83bd..00000000000 --- a/public/test/specs/opentsdbDatasource-specs.js +++ /dev/null @@ -1,71 +0,0 @@ -define([ - './helpers', - 'app/plugins/datasource/opentsdb/datasource' -], function(helpers) { - 'use strict'; - - describe('opentsdb', function() { - var ctx = new helpers.ServiceTestContext(); - - beforeEach(module('grafana.core')); - beforeEach(module('grafana.services')); - beforeEach(ctx.providePhase(['backendSrv'])); - - beforeEach(ctx.createService('OpenTSDBDatasource')); - beforeEach(function() { - ctx.ds = new ctx.service({ url: [''] }); - }); - - describe('When performing metricFindQuery', function() { - var results; - var requestOptions; - - beforeEach(function() { - ctx.backendSrv.datasourceRequest = function(options) { - requestOptions = options; - return ctx.$q.when({data: [{ target: 'prod1.count', datapoints: [[10, 1], [12,1]] }]}); - }; - }); - - it('metrics() should generate api suggest query', function() { - ctx.ds.metricFindQuery('metrics(pew)').then(function(data) { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/api/suggest'); - expect(requestOptions.params.type).to.be('metrics'); - expect(requestOptions.params.q).to.be('pew'); - }); - - it('tag_names(cpu) should generate looku query', function() { - ctx.ds.metricFindQuery('tag_names(cpu)').then(function(data) { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/api/search/lookup'); - expect(requestOptions.params.m).to.be('cpu'); - }); - - it('tag_values(cpu, test) should generate looku query', function() { - ctx.ds.metricFindQuery('tag_values(cpu, hostname)').then(function(data) { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/api/search/lookup'); - expect(requestOptions.params.m).to.be('cpu{hostname=*}'); - }); - - it('suggest_tagk() should generate api suggest query', function() { - ctx.ds.metricFindQuery('suggest_tagk(foo)').then(function(data) { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/api/suggest'); - expect(requestOptions.params.type).to.be('tagk'); - expect(requestOptions.params.q).to.be('foo'); - }); - - it('suggest_tagv() should generate api suggest query', function() { - ctx.ds.metricFindQuery('suggest_tagv(bar)').then(function(data) { results = data; }); - ctx.$rootScope.$apply(); - expect(requestOptions.url).to.be('/api/suggest'); - expect(requestOptions.params.type).to.be('tagv'); - expect(requestOptions.params.q).to.be('bar'); - }); - - }); - }); -}); - From 1ffcea195294d3e5275c1b204200cc68c93b538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 23:34:20 +0100 Subject: [PATCH 27/36] feat(plugins): major improvement in plugins golang code --- pkg/plugins/app_plugin.go | 38 ++++++++++ pkg/plugins/datasource_plugin.go | 25 +++++++ pkg/plugins/frontend_plugin.go | 47 ++++++++++++ pkg/plugins/models.go | 63 ++++------------ pkg/plugins/panel_plugin.go | 19 +++++ pkg/plugins/plugins.go | 74 ++++--------------- pkg/plugins/plugins_test.go | 4 + .../plugins/datasource/cloudwatch/plugin.json | 7 -- .../datasource/elasticsearch/plugin.json | 2 - .../plugins/datasource/grafana/plugin.json | 2 - .../app/plugins/datasource/graphite/module.js | 4 + .../plugins/datasource/graphite/plugin.json | 2 - .../plugins/datasource/influxdb/plugin.json | 2 - .../app/plugins/datasource/mixed/plugin.json | 4 - .../plugins/datasource/opentsdb/plugin.json | 2 - .../datasource/prometheus/datasource.d.ts | 3 + .../datasource/prometheus/datasource.js | 69 ++++++++--------- .../prometheus/{directives.js => module.js} | 10 ++- .../plugins/datasource/prometheus/plugin.json | 8 -- .../prometheus/specs/datasource_specs.ts | 15 ++-- 20 files changed, 218 insertions(+), 182 deletions(-) create mode 100644 pkg/plugins/app_plugin.go create mode 100644 pkg/plugins/datasource_plugin.go create mode 100644 pkg/plugins/frontend_plugin.go create mode 100644 pkg/plugins/panel_plugin.go create mode 100644 public/app/plugins/datasource/prometheus/datasource.d.ts rename public/app/plugins/datasource/prometheus/{directives.js => module.js} (52%) diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go new file mode 100644 index 00000000000..13a9bc43f94 --- /dev/null +++ b/pkg/plugins/app_plugin.go @@ -0,0 +1,38 @@ +package plugins + +import ( + "encoding/json" + + "github.com/grafana/grafana/pkg/models" +) + +type AppPluginPage struct { + Text string `json:"text"` + Icon string `json:"icon"` + Url string `json:"url"` + ReqRole models.RoleType `json:"reqRole"` +} + +type AppPluginCss struct { + Light string `json:"light"` + Dark string `json:"dark"` +} + +type AppPlugin struct { + FrontendPluginBase + Enabled bool `json:"enabled"` + Pinned bool `json:"pinned"` + Css *AppPluginCss `json:"css"` + Page *AppPluginPage `json:"page"` +} + +func (p *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { + if err := decoder.Decode(&p); err != nil { + return err + } + + p.PluginDir = pluginDir + p.initFrontendPlugin() + Apps[p.Id] = p + return nil +} diff --git a/pkg/plugins/datasource_plugin.go b/pkg/plugins/datasource_plugin.go new file mode 100644 index 00000000000..e1bb9047297 --- /dev/null +++ b/pkg/plugins/datasource_plugin.go @@ -0,0 +1,25 @@ +package plugins + +import "encoding/json" + +type DataSourcePlugin struct { + FrontendPluginBase + DefaultMatchFormat string `json:"defaultMatchFormat"` + Annotations bool `json:"annotations"` + Metrics bool `json:"metrics"` + BuiltIn bool `json:"builtIn"` + Mixed bool `json:"mixed"` + App string `json:"app"` +} + +func (p *DataSourcePlugin) Load(decoder *json.Decoder, pluginDir string) error { + if err := decoder.Decode(&p); err != nil { + return err + } + + p.PluginDir = pluginDir + p.initFrontendPlugin() + DataSources[p.Id] = p + + return nil +} diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go new file mode 100644 index 00000000000..1e20db1e7f5 --- /dev/null +++ b/pkg/plugins/frontend_plugin.go @@ -0,0 +1,47 @@ +package plugins + +import ( + "net/url" + "path" +) + +type FrontendPluginBase struct { + PluginBase + Module string `json:"module"` + StaticRoot string `json:"staticRoot"` +} + +func (fp *FrontendPluginBase) initFrontendPlugin() { + if fp.StaticRoot != "" { + StaticRoutes = append(StaticRoutes, &PluginStaticRoute{ + Directory: fp.StaticRoot, + PluginId: fp.Id, + }) + } + + fp.Info.Logos.Small = evalRelativePluginUrlPath(fp.Info.Logos.Small, fp.Id) + fp.Info.Logos.Large = evalRelativePluginUrlPath(fp.Info.Logos.Large, fp.Id) + + fp.handleModuleDefaults() +} + +func (fp *FrontendPluginBase) handleModuleDefaults() { + if fp.Module != "" { + return + } + + if fp.StaticRoot != "" { + fp.Module = path.Join("plugins", fp.Type, fp.Id, "module") + return + } + + fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module") +} + +func evalRelativePluginUrlPath(pathStr string, pluginId string) string { + u, _ := url.Parse(pathStr) + if u.IsAbs() { + return pathStr + } + return path.Join("public/plugins", pluginId, pathStr) +} diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 4516bbd5491..2ddbcf1dd83 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -1,15 +1,22 @@ package plugins import ( + "encoding/json" + "github.com/grafana/grafana/pkg/models" ) -type PluginCommon struct { - Type string `json:"type"` - Name string `json:"name"` - Id string `json:"id"` - StaticRoot string `json:"staticRoot"` - Info PluginInfo `json:"info"` +type PluginLoader interface { + Load(decoder *json.Decoder, pluginDir string) error +} + +type PluginBase struct { + Type string `json:"type"` + Name string `json:"name"` + Id string `json:"id"` + App string `json:"app"` + Info PluginInfo `json:"info"` + PluginDir string `json:"-"` } type PluginInfo struct { @@ -29,30 +36,11 @@ type PluginLogos struct { Large string `json:"large"` } -type DataSourcePlugin struct { - PluginCommon - Module string `json:"module"` - ServiceName string `json:"serviceName"` - Partials map[string]interface{} `json:"partials"` - DefaultMatchFormat string `json:"defaultMatchFormat"` - Annotations bool `json:"annotations"` - Metrics bool `json:"metrics"` - BuiltIn bool `json:"builtIn"` - Mixed bool `json:"mixed"` - App string `json:"app"` -} - type PluginStaticRoute struct { Directory string PluginId string } -type PanelPlugin struct { - PluginCommon - Module string `json:"module"` - App string `json:"app"` -} - type ApiPluginRoute struct { Path string `json:"path"` Method string `json:"method"` @@ -60,34 +48,11 @@ type ApiPluginRoute struct { ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"` ReqRole models.RoleType `json:"reqRole"` Url string `json:"url"` - App string `json:"app"` -} - -type AppPluginPage struct { - Text string `json:"text"` - Icon string `json:"icon"` - Url string `json:"url"` - ReqRole models.RoleType `json:"reqRole"` -} - -type AppPluginCss struct { - Light string `json:"light"` - Dark string `json:"dark"` } type ApiPlugin struct { - PluginCommon + PluginBase Routes []*ApiPluginRoute `json:"routes"` - App string `json:"app"` -} - -type AppPlugin struct { - PluginCommon - Enabled bool `json:"enabled"` - Pinned bool `json:"pinned"` - Module string `json:"module"` - Css *AppPluginCss `json:"css"` - Page *AppPluginPage `json:"page"` } type EnabledPlugins struct { diff --git a/pkg/plugins/panel_plugin.go b/pkg/plugins/panel_plugin.go new file mode 100644 index 00000000000..5b99ac52344 --- /dev/null +++ b/pkg/plugins/panel_plugin.go @@ -0,0 +1,19 @@ +package plugins + +import "encoding/json" + +type PanelPlugin struct { + FrontendPluginBase +} + +func (p *PanelPlugin) Load(decoder *json.Decoder, pluginDir string) error { + if err := decoder.Decode(&p); err != nil { + return err + } + + p.PluginDir = pluginDir + p.initFrontendPlugin() + Panels[p.Id] = p + + return nil +} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 59b0b0db866..4626ad8df15 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -5,10 +5,10 @@ import ( "encoding/json" "errors" "io" - "net/url" "os" "path" "path/filepath" + "reflect" "strings" "text/template" @@ -24,6 +24,7 @@ var ( ApiPlugins map[string]*ApiPlugin StaticRoutes []*PluginStaticRoute Apps map[string]*AppPlugin + PluginTypes map[string]interface{} ) type PluginScanner struct { @@ -37,6 +38,12 @@ func Init() error { StaticRoutes = make([]*PluginStaticRoute, 0) Panels = make(map[string]*PanelPlugin) Apps = make(map[string]*AppPlugin) + PluginTypes = map[string]interface{}{ + "panel": PanelPlugin{}, + "datasource": DataSourcePlugin{}, + "api": ApiPlugin{}, + "app": AppPlugin{}, + } scan(path.Join(setting.StaticRootPath, "app/plugins")) checkPluginPaths() @@ -115,27 +122,7 @@ func (scanner *PluginScanner) walker(currentPath string, f os.FileInfo, err erro return nil } -func evalRelativePluginUrlPath(pathStr string, pluginId string) string { - u, _ := url.Parse(pathStr) - if u.IsAbs() { - return pathStr - } - return path.Join("public/plugins", pluginId, pathStr) -} - -func addPublicContent(plugin *PluginCommon, currentDir string) { - if plugin.StaticRoot != "" { - StaticRoutes = append(StaticRoutes, &PluginStaticRoute{ - Directory: path.Join(currentDir, plugin.StaticRoot), - PluginId: plugin.Id, - }) - } - - plugin.Info.Logos.Small = evalRelativePluginUrlPath(plugin.Info.Logos.Small, plugin.Id) - plugin.Info.Logos.Large = evalRelativePluginUrlPath(plugin.Info.Logos.Large, plugin.Id) -} - -func interpolatePluginJson(reader io.Reader, pluginCommon *PluginCommon) (io.Reader, error) { +func interpolatePluginJson(reader io.Reader, pluginCommon *PluginBase) (io.Reader, error) { buf := new(bytes.Buffer) buf.ReadFrom(reader) jsonStr := buf.String() // @@ -167,7 +154,7 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { defer reader.Close() jsonParser := json.NewDecoder(reader) - pluginCommon := PluginCommon{} + pluginCommon := PluginBase{} if err := jsonParser.Decode(&pluginCommon); err != nil { return err } @@ -177,52 +164,21 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { } reader.Seek(0, 0) - if newReader, err := interpolatePluginJson(reader, &pluginCommon); err != nil { return err } else { jsonParser = json.NewDecoder(newReader) } - switch pluginCommon.Type { - case "datasource": - p := DataSourcePlugin{} - if err := jsonParser.Decode(&p); err != nil { - return err - } + var loader PluginLoader - DataSources[p.Id] = &p - addPublicContent(&p.PluginCommon, currentDir) - - case "panel": - p := PanelPlugin{} - reader.Seek(0, 0) - if err := jsonParser.Decode(&p); err != nil { - return err - } - - Panels[p.Id] = &p - addPublicContent(&p.PluginCommon, currentDir) - case "api": - p := ApiPlugin{} - reader.Seek(0, 0) - if err := jsonParser.Decode(&p); err != nil { - return err - } - ApiPlugins[p.Id] = &p - case "app": - p := AppPlugin{} - reader.Seek(0, 0) - if err := jsonParser.Decode(&p); err != nil { - return err - } - Apps[p.Id] = &p - addPublicContent(&p.PluginCommon, currentDir) - default: + if pluginGoType, exists := PluginTypes[pluginCommon.Type]; !exists { return errors.New("Unkown plugin type " + pluginCommon.Type) + } else { + loader = reflect.New(reflect.TypeOf(pluginGoType)).Interface().(PluginLoader) } - return nil + return loader.Load(jsonParser, currentDir) } func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins { diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index dc95d0e2b40..1808f72ec0d 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -19,6 +19,10 @@ func TestPluginScans(t *testing.T) { So(err, ShouldBeNil) So(len(DataSources), ShouldBeGreaterThan, 1) So(len(Panels), ShouldBeGreaterThan, 1) + + Convey("Should set module automatically", func() { + So(DataSources["graphite"].Module, ShouldEqual, "app/plugins/datasource/graphite/module") + }) }) Convey("When reading app plugin definition", t, func() { diff --git a/public/app/plugins/datasource/cloudwatch/plugin.json b/public/app/plugins/datasource/cloudwatch/plugin.json index 68e0a8d1dae..49c5341bd21 100644 --- a/public/app/plugins/datasource/cloudwatch/plugin.json +++ b/public/app/plugins/datasource/cloudwatch/plugin.json @@ -3,13 +3,6 @@ "name": "CloudWatch", "id": "cloudwatch", - "module": "app/plugins/datasource/cloudwatch/module", - - "partials": { - "config": "app/plugins/datasource/cloudwatch/partials/config.html", - "query": "app/plugins/datasource/cloudwatch/partials/query.editor.html" - }, - "metrics": true, "annotations": true } diff --git a/public/app/plugins/datasource/elasticsearch/plugin.json b/public/app/plugins/datasource/elasticsearch/plugin.json index fecdb3ae7cc..7e975a7e93b 100644 --- a/public/app/plugins/datasource/elasticsearch/plugin.json +++ b/public/app/plugins/datasource/elasticsearch/plugin.json @@ -3,8 +3,6 @@ "name": "Elasticsearch", "id": "elasticsearch", - "module": "app/plugins/datasource/elasticsearch/module", - "defaultMatchFormat": "lucene", "annotations": true, "metrics": true diff --git a/public/app/plugins/datasource/grafana/plugin.json b/public/app/plugins/datasource/grafana/plugin.json index 4d4f55b647d..fdccb24b59d 100644 --- a/public/app/plugins/datasource/grafana/plugin.json +++ b/public/app/plugins/datasource/grafana/plugin.json @@ -3,8 +3,6 @@ "name": "Grafana", "id": "grafana", - "module": "app/plugins/datasource/grafana/module", - "builtIn": true, "metrics": true } diff --git a/public/app/plugins/datasource/graphite/module.js b/public/app/plugins/datasource/graphite/module.js index b7910448304..72dd9eeaf0a 100644 --- a/public/app/plugins/datasource/graphite/module.js +++ b/public/app/plugins/datasource/graphite/module.js @@ -19,6 +19,10 @@ function (angular, GraphiteDatasource) { return {templateUrl: 'app/plugins/datasource/graphite/partials/annotations.editor.html'}; }); + module.directive('datasourceCustomSettingsViewGraphite', function() { + return {templateUrl: 'app/plugins/datasource/graphite/partials/config.html'}; + }); + return { Datasource: GraphiteDatasource, }; diff --git a/public/app/plugins/datasource/graphite/plugin.json b/public/app/plugins/datasource/graphite/plugin.json index 175ac5fa659..d2836b2a107 100644 --- a/public/app/plugins/datasource/graphite/plugin.json +++ b/public/app/plugins/datasource/graphite/plugin.json @@ -3,8 +3,6 @@ "type": "datasource", "id": "graphite", - "module": "app/plugins/datasource/graphite/module", - "defaultMatchFormat": "glob", "metrics": true, "annotations": true diff --git a/public/app/plugins/datasource/influxdb/plugin.json b/public/app/plugins/datasource/influxdb/plugin.json index 29d6a5a0f58..4007010fd21 100644 --- a/public/app/plugins/datasource/influxdb/plugin.json +++ b/public/app/plugins/datasource/influxdb/plugin.json @@ -3,8 +3,6 @@ "name": "InfluxDB 0.9.x", "id": "influxdb", - "module": "app/plugins/datasource/influxdb/module", - "defaultMatchFormat": "regex values", "metrics": true, "annotations": true diff --git a/public/app/plugins/datasource/mixed/plugin.json b/public/app/plugins/datasource/mixed/plugin.json index fb9bb340a04..b8c08446cb3 100644 --- a/public/app/plugins/datasource/mixed/plugin.json +++ b/public/app/plugins/datasource/mixed/plugin.json @@ -5,9 +5,5 @@ "builtIn": true, "mixed": true, - - "serviceName": "MixedDatasource", - - "module": "app/plugins/datasource/mixed/datasource", "metrics": true } diff --git a/public/app/plugins/datasource/opentsdb/plugin.json b/public/app/plugins/datasource/opentsdb/plugin.json index ec01b48c24b..82fe2c32062 100644 --- a/public/app/plugins/datasource/opentsdb/plugin.json +++ b/public/app/plugins/datasource/opentsdb/plugin.json @@ -3,8 +3,6 @@ "name": "OpenTSDB", "id": "opentsdb", - "module": "app/plugins/datasource/opentsdb/module", - "metrics": true, "defaultMatchFormat": "pipe" } diff --git a/public/app/plugins/datasource/prometheus/datasource.d.ts b/public/app/plugins/datasource/prometheus/datasource.d.ts new file mode 100644 index 00000000000..a50d7ca49cc --- /dev/null +++ b/public/app/plugins/datasource/prometheus/datasource.d.ts @@ -0,0 +1,3 @@ +declare var Datasource: any; +export default Datasource; + diff --git a/public/app/plugins/datasource/prometheus/datasource.js b/public/app/plugins/datasource/prometheus/datasource.js index 391affb0c8d..9560fe8aa5f 100644 --- a/public/app/plugins/datasource/prometheus/datasource.js +++ b/public/app/plugins/datasource/prometheus/datasource.js @@ -3,31 +3,25 @@ define([ 'lodash', 'moment', 'app/core/utils/datemath', - './directives', './query_ctrl', ], function (angular, _, moment, dateMath) { 'use strict'; - var module = angular.module('grafana.services'); - var durationSplitRegexp = /(\d+)(ms|s|m|h|d|w|M|y)/; - module.factory('PrometheusDatasource', function($q, backendSrv, templateSrv) { + function PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv) { + this.type = 'prometheus'; + this.editorSrc = 'app/features/prometheus/partials/query.editor.html'; + this.name = instanceSettings.name; + this.supportMetrics = true; + this.url = instanceSettings.url; + this.directUrl = instanceSettings.directUrl; + this.basicAuth = instanceSettings.basicAuth; + this.withCredentials = instanceSettings.withCredentials; + this.lastErrors = {}; - function PrometheusDatasource(datasource) { - this.type = 'prometheus'; - this.editorSrc = 'app/features/prometheus/partials/query.editor.html'; - this.name = datasource.name; - this.supportMetrics = true; - this.url = datasource.url; - this.directUrl = datasource.directUrl; - this.basicAuth = datasource.basicAuth; - this.withCredentials = datasource.withCredentials; - this.lastErrors = {}; - } - - PrometheusDatasource.prototype._request = function(method, url) { + this._request = function(method, url) { var options = { url: this.url + url, method: method @@ -46,7 +40,7 @@ function (angular, _, moment, dateMath) { }; // Called once per panel (graph) - PrometheusDatasource.prototype.query = function(options) { + this.query = function(options) { var start = getPrometheusTime(options.range.from, false); var end = getPrometheusTime(options.range.to, true); @@ -86,31 +80,31 @@ function (angular, _, moment, dateMath) { var self = this; return $q.all(allQueryPromise) - .then(function(allResponse) { - var result = []; + .then(function(allResponse) { + var result = []; - _.each(allResponse, function(response, index) { - if (response.status === 'error') { - self.lastErrors.query = response.error; - throw response.error; - } - delete self.lastErrors.query; + _.each(allResponse, function(response, index) { + if (response.status === 'error') { + self.lastErrors.query = response.error; + throw response.error; + } + delete self.lastErrors.query; - _.each(response.data.data.result, function(metricData) { - result.push(transformMetricData(metricData, options.targets[index])); - }); + _.each(response.data.data.result, function(metricData) { + result.push(transformMetricData(metricData, options.targets[index])); }); - - return { data: result }; }); + + return { data: result }; + }); }; - PrometheusDatasource.prototype.performTimeSeriesQuery = function(query, start, end) { + this.performTimeSeriesQuery = function(query, start, end) { var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step; return this._request('GET', url); }; - PrometheusDatasource.prototype.performSuggestQuery = function(query) { + this.performSuggestQuery = function(query) { var url = '/api/v1/label/__name__/values'; return this._request('GET', url).then(function(result) { @@ -120,7 +114,7 @@ function (angular, _, moment, dateMath) { }); }; - PrometheusDatasource.prototype.metricFindQuery = function(query) { + this.metricFindQuery = function(query) { if (!query) { return $q.when([]); } var interpolated; @@ -196,7 +190,7 @@ function (angular, _, moment, dateMath) { } }; - PrometheusDatasource.prototype.testDatasource = function() { + this.testDatasource = function() { return this.metricFindQuery('metrics(.*)').then(function() { return { status: 'success', message: 'Data source is working', title: 'Success' }; }); @@ -276,8 +270,7 @@ function (angular, _, moment, dateMath) { } return (date.valueOf() / 1000).toFixed(0); } + } - return PrometheusDatasource; - }); - + return PrometheusDatasource; }); diff --git a/public/app/plugins/datasource/prometheus/directives.js b/public/app/plugins/datasource/prometheus/module.js similarity index 52% rename from public/app/plugins/datasource/prometheus/directives.js rename to public/app/plugins/datasource/prometheus/module.js index 2ceed8bffdb..91b8d498645 100644 --- a/public/app/plugins/datasource/prometheus/directives.js +++ b/public/app/plugins/datasource/prometheus/module.js @@ -1,7 +1,8 @@ define([ 'angular', + './datasource', ], -function (angular) { +function (angular, PromDatasource) { 'use strict'; var module = angular.module('grafana.directives'); @@ -10,4 +11,11 @@ function (angular) { return {controller: 'PrometheusQueryCtrl', templateUrl: 'app/plugins/datasource/prometheus/partials/query.editor.html'}; }); + module.directive('datasourceCustomSettingsViewPrometheus', function() { + return {templateUrl: 'app/plugins/datasource/prometheus/partials/config.html'}; + }); + + return { + Datasource: PromDatasource + }; }); diff --git a/public/app/plugins/datasource/prometheus/plugin.json b/public/app/plugins/datasource/prometheus/plugin.json index 2580db9e5c9..4cd55605816 100644 --- a/public/app/plugins/datasource/prometheus/plugin.json +++ b/public/app/plugins/datasource/prometheus/plugin.json @@ -3,13 +3,5 @@ "name": "Prometheus", "id": "prometheus", - "serviceName": "PrometheusDatasource", - - "module": "app/plugins/datasource/prometheus/datasource", - - "partials": { - "config": "app/plugins/datasource/prometheus/partials/config.html" - }, - "metrics": true } diff --git a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts index a03e39a9351..92620678eaf 100644 --- a/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/prometheus/specs/datasource_specs.ts @@ -1,17 +1,20 @@ -import '../datasource'; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import moment from 'moment'; import helpers from 'test/specs/helpers'; +import Datasource from '../datasource'; describe('PrometheusDatasource', function() { - var ctx = new helpers.ServiceTestContext(); + var instanceSettings = {url: 'proxied', directUrl: 'direct', user: 'test', password: 'mupp' }; + beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); - beforeEach(ctx.createService('PrometheusDatasource')); - beforeEach(function() { - ctx.ds = new ctx.service({ url: 'proxied', directUrl: 'direct', user: 'test', password: 'mupp' }); - }); + beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) { + ctx.$q = $q; + ctx.$httpBackend = $httpBackend; + ctx.$rootScope = $rootScope; + ctx.ds = $injector.instantiate(Datasource, {instanceSettings: instanceSettings}); + })); describe('When querying prometheus with one target using query editor target spec', function() { var results; From d83e24572aca9afb01eb9fb0a6aa01509012fd1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 23:52:13 +0100 Subject: [PATCH 28/36] feat(plugins): more refactoring --- public/app/features/dashboard/dashboardCtrl.js | 8 -------- public/app/plugins/{panels => panel}/dashlist/editor.html | 0 public/app/plugins/{panels => panel}/dashlist/module.html | 0 public/app/plugins/{panels => panel}/dashlist/module.js | 4 ++-- public/app/plugins/panel/dashlist/plugin.json | 5 +++++ .../app/plugins/{panels => panel}/graph/axisEditor.html | 0 public/app/plugins/{panels => panel}/graph/graph.js | 0 .../app/plugins/{panels => panel}/graph/graph.tooltip.js | 0 public/app/plugins/{panels => panel}/graph/legend.js | 0 .../plugins/{panels => panel}/graph/legend.popover.html | 0 public/app/plugins/{panels => panel}/graph/module.html | 0 public/app/plugins/{panels => panel}/graph/module.js | 6 +++--- public/app/plugins/panel/graph/plugin.json | 5 +++++ .../{panels => panel}/graph/seriesOverridesCtrl.js | 0 .../app/plugins/{panels => panel}/graph/styleEditor.html | 0 .../app/plugins/{panels => panel}/singlestat/editor.html | 0 .../app/plugins/{panels => panel}/singlestat/module.html | 0 public/app/plugins/{panels => panel}/singlestat/module.js | 4 ++-- public/app/plugins/panel/singlestat/plugin.json | 5 +++++ .../{panels => panel}/singlestat/singleStatPanel.js | 0 public/app/plugins/{panels => panel}/table/controller.ts | 0 public/app/plugins/{panels => panel}/table/editor.html | 0 public/app/plugins/{panels => panel}/table/editor.ts | 0 public/app/plugins/{panels => panel}/table/module.html | 0 public/app/plugins/{panels => panel}/table/module.ts | 2 +- public/app/plugins/{panels => panel}/table/options.html | 0 public/app/plugins/panel/table/plugin.json | 5 +++++ public/app/plugins/{panels => panel}/table/renderer.ts | 0 .../{panels => panel}/table/specs/renderer_specs.ts | 0 .../{panels => panel}/table/specs/transformers_specs.ts | 0 .../app/plugins/{panels => panel}/table/transformers.ts | 0 public/app/plugins/{panels => panel}/text/editor.html | 0 public/app/plugins/{panels => panel}/text/module.html | 0 public/app/plugins/{panels => panel}/text/module.js | 4 ++-- public/app/plugins/panel/text/plugin.json | 5 +++++ public/app/plugins/panels/dashlist/plugin.json | 7 ------- public/app/plugins/panels/graph/plugin.json | 7 ------- public/app/plugins/panels/singlestat/plugin.json | 7 ------- public/app/plugins/panels/table/plugin.json | 7 ------- public/app/plugins/panels/text/plugin.json | 7 ------- public/test/specs/graph-ctrl-specs.js | 2 +- public/test/specs/graph-specs.js | 2 +- public/test/specs/graph-tooltip-specs.js | 2 +- public/test/specs/seriesOverridesCtrl-specs.js | 2 +- public/test/specs/singlestat-specs.js | 2 +- tasks/options/jscs.js | 2 +- tasks/options/requirejs.js | 6 +++--- tasks/systemjs_task.js | 2 +- 48 files changed, 45 insertions(+), 63 deletions(-) rename public/app/plugins/{panels => panel}/dashlist/editor.html (100%) rename public/app/plugins/{panels => panel}/dashlist/module.html (100%) rename public/app/plugins/{panels => panel}/dashlist/module.js (91%) create mode 100644 public/app/plugins/panel/dashlist/plugin.json rename public/app/plugins/{panels => panel}/graph/axisEditor.html (100%) rename public/app/plugins/{panels => panel}/graph/graph.js (100%) rename public/app/plugins/{panels => panel}/graph/graph.tooltip.js (100%) rename public/app/plugins/{panels => panel}/graph/legend.js (100%) rename public/app/plugins/{panels => panel}/graph/legend.popover.html (100%) rename public/app/plugins/{panels => panel}/graph/module.html (100%) rename public/app/plugins/{panels => panel}/graph/module.js (98%) create mode 100644 public/app/plugins/panel/graph/plugin.json rename public/app/plugins/{panels => panel}/graph/seriesOverridesCtrl.js (100%) rename public/app/plugins/{panels => panel}/graph/styleEditor.html (100%) rename public/app/plugins/{panels => panel}/singlestat/editor.html (100%) rename public/app/plugins/{panels => panel}/singlestat/module.html (100%) rename public/app/plugins/{panels => panel}/singlestat/module.js (97%) create mode 100644 public/app/plugins/panel/singlestat/plugin.json rename public/app/plugins/{panels => panel}/singlestat/singleStatPanel.js (100%) rename public/app/plugins/{panels => panel}/table/controller.ts (100%) rename public/app/plugins/{panels => panel}/table/editor.html (100%) rename public/app/plugins/{panels => panel}/table/editor.ts (100%) rename public/app/plugins/{panels => panel}/table/module.html (100%) rename public/app/plugins/{panels => panel}/table/module.ts (98%) rename public/app/plugins/{panels => panel}/table/options.html (100%) create mode 100644 public/app/plugins/panel/table/plugin.json rename public/app/plugins/{panels => panel}/table/renderer.ts (100%) rename public/app/plugins/{panels => panel}/table/specs/renderer_specs.ts (100%) rename public/app/plugins/{panels => panel}/table/specs/transformers_specs.ts (100%) rename public/app/plugins/{panels => panel}/table/transformers.ts (100%) rename public/app/plugins/{panels => panel}/text/editor.html (100%) rename public/app/plugins/{panels => panel}/text/module.html (100%) rename public/app/plugins/{panels => panel}/text/module.js (97%) create mode 100644 public/app/plugins/panel/text/plugin.json delete mode 100644 public/app/plugins/panels/dashlist/plugin.json delete mode 100644 public/app/plugins/panels/graph/plugin.json delete mode 100644 public/app/plugins/panels/singlestat/plugin.json delete mode 100644 public/app/plugins/panels/table/plugin.json delete mode 100644 public/app/plugins/panels/text/plugin.json diff --git a/public/app/features/dashboard/dashboardCtrl.js b/public/app/features/dashboard/dashboardCtrl.js index eb2aa3bad89..20b3122230c 100644 --- a/public/app/features/dashboard/dashboardCtrl.js +++ b/public/app/features/dashboard/dashboardCtrl.js @@ -106,14 +106,6 @@ function (angular, $, config, moment) { }; }; - $scope.panelEditorPath = function(type) { - return 'app/' + config.panels[type].path + '/editor.html'; - }; - - $scope.pulldownEditorPath = function(type) { - return 'app/panels/'+type+'/editor.html'; - }; - $scope.showJsonEditor = function(evt, options) { var editScope = $rootScope.$new(); editScope.object = options.object; diff --git a/public/app/plugins/panels/dashlist/editor.html b/public/app/plugins/panel/dashlist/editor.html similarity index 100% rename from public/app/plugins/panels/dashlist/editor.html rename to public/app/plugins/panel/dashlist/editor.html diff --git a/public/app/plugins/panels/dashlist/module.html b/public/app/plugins/panel/dashlist/module.html similarity index 100% rename from public/app/plugins/panels/dashlist/module.html rename to public/app/plugins/panel/dashlist/module.html diff --git a/public/app/plugins/panels/dashlist/module.js b/public/app/plugins/panel/dashlist/module.js similarity index 91% rename from public/app/plugins/panels/dashlist/module.js rename to public/app/plugins/panel/dashlist/module.js index fddc762ffe2..d9152566975 100644 --- a/public/app/plugins/panels/dashlist/module.js +++ b/public/app/plugins/panel/dashlist/module.js @@ -14,7 +14,7 @@ function (angular, app, _, config, PanelMeta) { module.directive('grafanaPanelDashlist', function() { return { controller: 'DashListPanelCtrl', - templateUrl: 'app/plugins/panels/dashlist/module.html', + templateUrl: 'app/plugins/panel/dashlist/module.html', }; }); @@ -26,7 +26,7 @@ function (angular, app, _, config, PanelMeta) { fullscreen: true, }); - $scope.panelMeta.addEditorTab('Options', 'app/plugins/panels/dashlist/editor.html'); + $scope.panelMeta.addEditorTab('Options', 'app/plugins/panel/dashlist/editor.html'); var defaults = { mode: 'starred', diff --git a/public/app/plugins/panel/dashlist/plugin.json b/public/app/plugins/panel/dashlist/plugin.json new file mode 100644 index 00000000000..1f1266d8444 --- /dev/null +++ b/public/app/plugins/panel/dashlist/plugin.json @@ -0,0 +1,5 @@ +{ + "type": "panel", + "name": "Dashboard list", + "id": "dashlist" +} diff --git a/public/app/plugins/panels/graph/axisEditor.html b/public/app/plugins/panel/graph/axisEditor.html similarity index 100% rename from public/app/plugins/panels/graph/axisEditor.html rename to public/app/plugins/panel/graph/axisEditor.html diff --git a/public/app/plugins/panels/graph/graph.js b/public/app/plugins/panel/graph/graph.js similarity index 100% rename from public/app/plugins/panels/graph/graph.js rename to public/app/plugins/panel/graph/graph.js diff --git a/public/app/plugins/panels/graph/graph.tooltip.js b/public/app/plugins/panel/graph/graph.tooltip.js similarity index 100% rename from public/app/plugins/panels/graph/graph.tooltip.js rename to public/app/plugins/panel/graph/graph.tooltip.js diff --git a/public/app/plugins/panels/graph/legend.js b/public/app/plugins/panel/graph/legend.js similarity index 100% rename from public/app/plugins/panels/graph/legend.js rename to public/app/plugins/panel/graph/legend.js diff --git a/public/app/plugins/panels/graph/legend.popover.html b/public/app/plugins/panel/graph/legend.popover.html similarity index 100% rename from public/app/plugins/panels/graph/legend.popover.html rename to public/app/plugins/panel/graph/legend.popover.html diff --git a/public/app/plugins/panels/graph/module.html b/public/app/plugins/panel/graph/module.html similarity index 100% rename from public/app/plugins/panels/graph/module.html rename to public/app/plugins/panel/graph/module.html diff --git a/public/app/plugins/panels/graph/module.js b/public/app/plugins/panel/graph/module.js similarity index 98% rename from public/app/plugins/panels/graph/module.js rename to public/app/plugins/panel/graph/module.js index 731fb47ae6d..5936275d797 100644 --- a/public/app/plugins/panels/graph/module.js +++ b/public/app/plugins/panel/graph/module.js @@ -17,7 +17,7 @@ function (angular, _, moment, kbn, TimeSeries, PanelMeta) { module.directive('grafanaPanelGraph', function() { return { controller: 'GraphCtrl', - templateUrl: 'app/plugins/panels/graph/module.html', + templateUrl: 'app/plugins/panel/graph/module.html', }; }); @@ -30,8 +30,8 @@ function (angular, _, moment, kbn, TimeSeries, PanelMeta) { metricsEditor: true, }); - $scope.panelMeta.addEditorTab('Axes & Grid', 'app/plugins/panels/graph/axisEditor.html'); - $scope.panelMeta.addEditorTab('Display Styles', 'app/plugins/panels/graph/styleEditor.html'); + $scope.panelMeta.addEditorTab('Axes & Grid', 'app/plugins/panel/graph/axisEditor.html'); + $scope.panelMeta.addEditorTab('Display Styles', 'app/plugins/panel/graph/styleEditor.html'); $scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); $scope.panelMeta.addExtendedMenuItem('Export CSV', '', 'exportCsv()'); diff --git a/public/app/plugins/panel/graph/plugin.json b/public/app/plugins/panel/graph/plugin.json new file mode 100644 index 00000000000..f603e5e4b06 --- /dev/null +++ b/public/app/plugins/panel/graph/plugin.json @@ -0,0 +1,5 @@ +{ + "type": "panel", + "name": "Graph", + "id": "graph" +} diff --git a/public/app/plugins/panels/graph/seriesOverridesCtrl.js b/public/app/plugins/panel/graph/seriesOverridesCtrl.js similarity index 100% rename from public/app/plugins/panels/graph/seriesOverridesCtrl.js rename to public/app/plugins/panel/graph/seriesOverridesCtrl.js diff --git a/public/app/plugins/panels/graph/styleEditor.html b/public/app/plugins/panel/graph/styleEditor.html similarity index 100% rename from public/app/plugins/panels/graph/styleEditor.html rename to public/app/plugins/panel/graph/styleEditor.html diff --git a/public/app/plugins/panels/singlestat/editor.html b/public/app/plugins/panel/singlestat/editor.html similarity index 100% rename from public/app/plugins/panels/singlestat/editor.html rename to public/app/plugins/panel/singlestat/editor.html diff --git a/public/app/plugins/panels/singlestat/module.html b/public/app/plugins/panel/singlestat/module.html similarity index 100% rename from public/app/plugins/panels/singlestat/module.html rename to public/app/plugins/panel/singlestat/module.html diff --git a/public/app/plugins/panels/singlestat/module.js b/public/app/plugins/panel/singlestat/module.js similarity index 97% rename from public/app/plugins/panels/singlestat/module.js rename to public/app/plugins/panel/singlestat/module.js index 47b18ba526f..5c99cf7d3b1 100644 --- a/public/app/plugins/panels/singlestat/module.js +++ b/public/app/plugins/panel/singlestat/module.js @@ -16,7 +16,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) { module.directive('grafanaPanelSinglestat', function() { return { controller: 'SingleStatCtrl', - templateUrl: 'app/plugins/panels/singlestat/module.html', + templateUrl: 'app/plugins/panel/singlestat/module.html', }; }); @@ -31,7 +31,7 @@ function (angular, app, _, kbn, TimeSeries, PanelMeta) { $scope.fontSizes = ['20%', '30%','50%','70%','80%','100%', '110%', '120%', '150%', '170%', '200%']; - $scope.panelMeta.addEditorTab('Options', 'app/plugins/panels/singlestat/editor.html'); + $scope.panelMeta.addEditorTab('Options', 'app/plugins/panel/singlestat/editor.html'); $scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); // Set and populate defaults diff --git a/public/app/plugins/panel/singlestat/plugin.json b/public/app/plugins/panel/singlestat/plugin.json new file mode 100644 index 00000000000..8372e4b2c2d --- /dev/null +++ b/public/app/plugins/panel/singlestat/plugin.json @@ -0,0 +1,5 @@ +{ + "type": "panel", + "name": "Singlestat", + "id": "singlestat" +} diff --git a/public/app/plugins/panels/singlestat/singleStatPanel.js b/public/app/plugins/panel/singlestat/singleStatPanel.js similarity index 100% rename from public/app/plugins/panels/singlestat/singleStatPanel.js rename to public/app/plugins/panel/singlestat/singleStatPanel.js diff --git a/public/app/plugins/panels/table/controller.ts b/public/app/plugins/panel/table/controller.ts similarity index 100% rename from public/app/plugins/panels/table/controller.ts rename to public/app/plugins/panel/table/controller.ts diff --git a/public/app/plugins/panels/table/editor.html b/public/app/plugins/panel/table/editor.html similarity index 100% rename from public/app/plugins/panels/table/editor.html rename to public/app/plugins/panel/table/editor.html diff --git a/public/app/plugins/panels/table/editor.ts b/public/app/plugins/panel/table/editor.ts similarity index 100% rename from public/app/plugins/panels/table/editor.ts rename to public/app/plugins/panel/table/editor.ts diff --git a/public/app/plugins/panels/table/module.html b/public/app/plugins/panel/table/module.html similarity index 100% rename from public/app/plugins/panels/table/module.html rename to public/app/plugins/panel/table/module.html diff --git a/public/app/plugins/panels/table/module.ts b/public/app/plugins/panel/table/module.ts similarity index 98% rename from public/app/plugins/panels/table/module.ts rename to public/app/plugins/panel/table/module.ts index 72122ecbd97..4344eb41229 100644 --- a/public/app/plugins/panels/table/module.ts +++ b/public/app/plugins/panel/table/module.ts @@ -14,7 +14,7 @@ export function tablePanel() { 'use strict'; return { restrict: 'E', - templateUrl: 'app/plugins/panels/table/module.html', + templateUrl: 'app/plugins/panel/table/module.html', controller: TablePanelCtrl, link: function(scope, elem) { var data; diff --git a/public/app/plugins/panels/table/options.html b/public/app/plugins/panel/table/options.html similarity index 100% rename from public/app/plugins/panels/table/options.html rename to public/app/plugins/panel/table/options.html diff --git a/public/app/plugins/panel/table/plugin.json b/public/app/plugins/panel/table/plugin.json new file mode 100644 index 00000000000..7f8c0bb23cf --- /dev/null +++ b/public/app/plugins/panel/table/plugin.json @@ -0,0 +1,5 @@ +{ + "type": "panel", + "name": "Table", + "id": "table" +} diff --git a/public/app/plugins/panels/table/renderer.ts b/public/app/plugins/panel/table/renderer.ts similarity index 100% rename from public/app/plugins/panels/table/renderer.ts rename to public/app/plugins/panel/table/renderer.ts diff --git a/public/app/plugins/panels/table/specs/renderer_specs.ts b/public/app/plugins/panel/table/specs/renderer_specs.ts similarity index 100% rename from public/app/plugins/panels/table/specs/renderer_specs.ts rename to public/app/plugins/panel/table/specs/renderer_specs.ts diff --git a/public/app/plugins/panels/table/specs/transformers_specs.ts b/public/app/plugins/panel/table/specs/transformers_specs.ts similarity index 100% rename from public/app/plugins/panels/table/specs/transformers_specs.ts rename to public/app/plugins/panel/table/specs/transformers_specs.ts diff --git a/public/app/plugins/panels/table/transformers.ts b/public/app/plugins/panel/table/transformers.ts similarity index 100% rename from public/app/plugins/panels/table/transformers.ts rename to public/app/plugins/panel/table/transformers.ts diff --git a/public/app/plugins/panels/text/editor.html b/public/app/plugins/panel/text/editor.html similarity index 100% rename from public/app/plugins/panels/text/editor.html rename to public/app/plugins/panel/text/editor.html diff --git a/public/app/plugins/panels/text/module.html b/public/app/plugins/panel/text/module.html similarity index 100% rename from public/app/plugins/panels/text/module.html rename to public/app/plugins/panel/text/module.html diff --git a/public/app/plugins/panels/text/module.js b/public/app/plugins/panel/text/module.js similarity index 97% rename from public/app/plugins/panels/text/module.js rename to public/app/plugins/panel/text/module.js index bb3c5faae03..d3add3a15b8 100644 --- a/public/app/plugins/panels/text/module.js +++ b/public/app/plugins/panel/text/module.js @@ -16,7 +16,7 @@ function (angular, app, _, require, PanelMeta) { module.directive('grafanaPanelText', function() { return { controller: 'TextPanelCtrl', - templateUrl: 'app/plugins/panels/text/module.html', + templateUrl: 'app/plugins/panel/text/module.html', }; }); @@ -28,7 +28,7 @@ function (angular, app, _, require, PanelMeta) { fullscreen: true, }); - $scope.panelMeta.addEditorTab('Edit text', 'app/plugins/panels/text/editor.html'); + $scope.panelMeta.addEditorTab('Edit text', 'app/plugins/panel/text/editor.html'); // Set and populate defaults var _d = { diff --git a/public/app/plugins/panel/text/plugin.json b/public/app/plugins/panel/text/plugin.json new file mode 100644 index 00000000000..4cf046cec36 --- /dev/null +++ b/public/app/plugins/panel/text/plugin.json @@ -0,0 +1,5 @@ +{ + "type": "panel", + "name": "Text", + "id": "text" +} diff --git a/public/app/plugins/panels/dashlist/plugin.json b/public/app/plugins/panels/dashlist/plugin.json deleted file mode 100644 index e1fcb2f9221..00000000000 --- a/public/app/plugins/panels/dashlist/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "panel", - "name": "Dashboard list", - "id": "dashlist", - - "module": "app/plugins/panels/dashlist/module" -} diff --git a/public/app/plugins/panels/graph/plugin.json b/public/app/plugins/panels/graph/plugin.json deleted file mode 100644 index 7e4dc3093bb..00000000000 --- a/public/app/plugins/panels/graph/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "panel", - "name": "Graph", - "id": "graph", - - "module": "app/plugins/panels/graph/module" -} diff --git a/public/app/plugins/panels/singlestat/plugin.json b/public/app/plugins/panels/singlestat/plugin.json deleted file mode 100644 index 5bc8e536510..00000000000 --- a/public/app/plugins/panels/singlestat/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "panel", - "name": "Singlestat", - "id": "singlestat", - - "module": "app/plugins/panels/singlestat/module" -} diff --git a/public/app/plugins/panels/table/plugin.json b/public/app/plugins/panels/table/plugin.json deleted file mode 100644 index 4fdb393b3db..00000000000 --- a/public/app/plugins/panels/table/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "panel", - "name": "Table", - "id": "table", - - "module": "app/plugins/panels/table/module" -} diff --git a/public/app/plugins/panels/text/plugin.json b/public/app/plugins/panels/text/plugin.json deleted file mode 100644 index 33c49b2f8a4..00000000000 --- a/public/app/plugins/panels/text/plugin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "panel", - "name": "Text", - "id": "text", - - "module": "app/plugins/panels/text/module" -} diff --git a/public/test/specs/graph-ctrl-specs.js b/public/test/specs/graph-ctrl-specs.js index 81be9a40b46..607c13cf528 100644 --- a/public/test/specs/graph-ctrl-specs.js +++ b/public/test/specs/graph-ctrl-specs.js @@ -2,7 +2,7 @@ define([ './helpers', 'app/features/panel/panel_srv', 'app/features/panel/panel_helper', - 'app/plugins/panels/graph/module' + 'app/plugins/panel/graph/module' ], function(helpers) { 'use strict'; diff --git a/public/test/specs/graph-specs.js b/public/test/specs/graph-specs.js index 29fdeeb825e..db3a4acf61f 100644 --- a/public/test/specs/graph-specs.js +++ b/public/test/specs/graph-specs.js @@ -3,7 +3,7 @@ define([ 'angular', 'jquery', 'app/core/time_series', - 'app/plugins/panels/graph/graph' + 'app/plugins/panel/graph/graph' ], function(helpers, angular, $, TimeSeries) { 'use strict'; diff --git a/public/test/specs/graph-tooltip-specs.js b/public/test/specs/graph-tooltip-specs.js index 9dc84daefa3..de39d855a70 100644 --- a/public/test/specs/graph-tooltip-specs.js +++ b/public/test/specs/graph-tooltip-specs.js @@ -1,6 +1,6 @@ define([ 'jquery', - 'app/plugins/panels/graph/graph.tooltip' + 'app/plugins/panel/graph/graph.tooltip' ], function($, GraphTooltip) { 'use strict'; diff --git a/public/test/specs/seriesOverridesCtrl-specs.js b/public/test/specs/seriesOverridesCtrl-specs.js index 1290e5f0987..ba820f065ab 100644 --- a/public/test/specs/seriesOverridesCtrl-specs.js +++ b/public/test/specs/seriesOverridesCtrl-specs.js @@ -1,6 +1,6 @@ define([ './helpers', - 'app/plugins/panels/graph/seriesOverridesCtrl' + 'app/plugins/panel/graph/seriesOverridesCtrl' ], function(helpers) { 'use strict'; diff --git a/public/test/specs/singlestat-specs.js b/public/test/specs/singlestat-specs.js index 14e1ca63cca..733f7f37e98 100644 --- a/public/test/specs/singlestat-specs.js +++ b/public/test/specs/singlestat-specs.js @@ -2,7 +2,7 @@ define([ './helpers', 'app/features/panel/panel_srv', 'app/features/panel/panel_helper', - 'app/plugins/panels/singlestat/module' + 'app/plugins/panel/singlestat/module' ], function(helpers) { 'use strict'; diff --git a/tasks/options/jscs.js b/tasks/options/jscs.js index c27c1aff09d..8296e59a506 100644 --- a/tasks/options/jscs.js +++ b/tasks/options/jscs.js @@ -3,7 +3,7 @@ module.exports = function(config) { src: [ 'Gruntfile.js', '<%= srcDir %>/app/**/*.js', - '<%= srcDir %>/plugins/**/*.js', + '<%= srcDir %>/plugin/**/*.js', '!<%= srcDir %>/app/dashboards/*' ], options: { diff --git a/tasks/options/requirejs.js b/tasks/options/requirejs.js index fd6603e16f4..ecd28d8c914 100644 --- a/tasks/options/requirejs.js +++ b/tasks/options/requirejs.js @@ -62,11 +62,11 @@ module.exports = function(config,grunt) { ]; var fs = require('fs'); - var panelPath = config.srcDir + '/app/plugins/panels'; + var panelPath = config.srcDir + '/app/plugins/panel'; - // create a module for each directory in public/app/panels/ + // create a module for each directory in public/app/panel/ fs.readdirSync(panelPath).forEach(function (panelName) { - requireModules[0].include.push('app/plugins/panels/'+panelName+'/module'); + requireModules[0].include.push('app/plugins/panel/'+panelName+'/module'); }); return { options: options }; diff --git a/tasks/systemjs_task.js b/tasks/systemjs_task.js index 6340ce532b8..0f1a63883e0 100644 --- a/tasks/systemjs_task.js +++ b/tasks/systemjs_task.js @@ -13,7 +13,7 @@ module.exports = function(grunt) { var modules = [ 'app/app', 'app/features/all', - 'app/plugins/panels/**/module', + 'app/plugins/panel/**/module', 'app/plugins/datasource/graphite/datasource', 'app/plugins/datasource/influxdb/datasource', 'app/plugins/datasource/elasticsearch/datasource', From ab79348af50790f494d628ead77213fad680e9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Jan 2016 23:56:39 +0100 Subject: [PATCH 29/36] feat(plugins): minor fix for external plugins with staticRoot --- pkg/plugins/frontend_plugin.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go index 1e20db1e7f5..0f0d1676066 100644 --- a/pkg/plugins/frontend_plugin.go +++ b/pkg/plugins/frontend_plugin.go @@ -3,6 +3,7 @@ package plugins import ( "net/url" "path" + "path/filepath" ) type FrontendPluginBase struct { @@ -14,7 +15,7 @@ type FrontendPluginBase struct { func (fp *FrontendPluginBase) initFrontendPlugin() { if fp.StaticRoot != "" { StaticRoutes = append(StaticRoutes, &PluginStaticRoute{ - Directory: fp.StaticRoot, + Directory: filepath.Join(fp.PluginDir, fp.StaticRoot), PluginId: fp.Id, }) } @@ -31,7 +32,7 @@ func (fp *FrontendPluginBase) handleModuleDefaults() { } if fp.StaticRoot != "" { - fp.Module = path.Join("plugins", fp.Type, fp.Id, "module") + fp.Module = path.Join("plugins", fp.Id, "module") return } From c1e94e61d01d8fe7a6d0ffbcf894a56c197ae7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 10 Jan 2016 21:37:11 +0100 Subject: [PATCH 30/36] 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 --- pkg/api/api.go | 9 +- pkg/api/app_plugin.go | 63 ------------ pkg/api/app_settings.go | 59 ++++++++++++ pkg/api/datasources.go | 19 ++-- pkg/api/dtos/app_plugin.go | 13 --- pkg/api/dtos/apps.go | 31 ++++++ pkg/api/frontendsettings.go | 5 +- pkg/api/index.go | 6 +- pkg/models/{app_plugin.go => app_settings.go} | 15 ++- pkg/plugins/plugins.go | 76 --------------- pkg/plugins/queries.go | 96 +++++++++++++++++++ .../{app_plugin.go => app_settings.go} | 18 ++-- .../{app_plugin.go => app_settings.go} | 14 +-- .../sqlstore/migrations/migrations.go | 2 +- public/app/core/routes/all.js | 2 +- public/app/features/apps/all.ts | 1 - public/app/features/apps/app_srv.ts | 5 +- public/app/features/apps/edit_ctrl.ts | 28 ++++-- public/app/features/apps/list_ctrl.ts | 6 +- public/app/features/apps/partials/edit.html | 10 +- public/app/features/apps/partials/list.html | 5 +- public/less/filter-list.less | 6 ++ tasks/options/watch.js | 3 + 23 files changed, 272 insertions(+), 220 deletions(-) delete mode 100644 pkg/api/app_plugin.go create mode 100644 pkg/api/app_settings.go delete mode 100644 pkg/api/dtos/app_plugin.go create mode 100644 pkg/api/dtos/apps.go rename pkg/models/{app_plugin.go => app_settings.go} (64%) create mode 100644 pkg/plugins/queries.go rename pkg/services/sqlstore/{app_plugin.go => app_settings.go} (64%) rename pkg/services/sqlstore/migrations/{app_plugin.go => app_settings.go} (62%) diff --git a/pkg/api/api.go b/pkg/api/api.go index ae523b662a6..0ffe5b9508f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -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("/org/apps", reqSignedIn, Index) - r.Get("/org/apps/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) @@ -119,8 +119,9 @@ func Register(r *macaron.Macaron) { r.Patch("/invites/:code/revoke", wrap(RevokeInvite)) // apps - r.Get("/apps", wrap(GetAppPlugins)) - r.Post("/apps", bind(m.UpdateAppPluginCmd{}), wrap(UpdateAppPlugin)) + 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 diff --git a/pkg/api/app_plugin.go b/pkg/api/app_plugin.go deleted file mode 100644 index bcab5fa4788..00000000000 --- a/pkg/api/app_plugin.go +++ /dev/null @@ -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") -} diff --git a/pkg/api/app_settings.go b/pkg/api/app_settings.go new file mode 100644 index 00000000000..fd0f1a1eab1 --- /dev/null +++ b/pkg/api/app_settings.go @@ -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") +} diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 04fdca8242a..54959840d03 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -118,18 +118,17 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) { func GetDataSourcePlugins(c *middleware.Context) { dsList := make(map[string]*plugins.DataSourcePlugin) - orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} - err := bus.Dispatch(&orgApps) - if err != nil { + if enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId); err != nil { c.JsonApiErr(500, "Failed to get org apps", err) - } - enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) + return + } else { - for key, value := range enabledPlugins.DataSources { - if !value.BuiltIn { - dsList[key] = value + for key, value := range enabledPlugins.DataSources { + if !value.BuiltIn { + dsList[key] = value + } } - } - c.JSON(200, dsList) + c.JSON(200, dsList) + } } diff --git a/pkg/api/dtos/app_plugin.go b/pkg/api/dtos/app_plugin.go deleted file mode 100644 index 7213c224cf8..00000000000 --- a/pkg/api/dtos/app_plugin.go +++ /dev/null @@ -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"` -} diff --git a/pkg/api/dtos/apps.go b/pkg/api/dtos/apps.go new file mode 100644 index 00000000000..2db2879f5f7 --- /dev/null +++ b/pkg/api/dtos/apps.go @@ -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 +} diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 486d59608ba..0f9cdee02a9 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -29,14 +29,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro datasources := make(map[string]interface{}) var defaultDatasource string - orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} - err := bus.Dispatch(&orgApps) + enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId) if err != nil { return nil, err } - enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) - for _, ds := range orgDataSources { url := ds.Url diff --git a/pkg/api/index.go b/pkg/api/index.go index 3a56a7f1205..bbe0c6565a8 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -2,7 +2,6 @@ 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" @@ -69,14 +68,11 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { }) } - orgApps := m.GetAppPluginsQuery{OrgId: c.OrgId} - err = bus.Dispatch(&orgApps) + enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId) if err != nil { return nil, err } - enabledPlugins := plugins.GetEnabledPlugins(orgApps.Result) - for _, plugin := range enabledPlugins.Apps { if plugin.Module != "" { data.PluginModules = append(data.PluginModules, plugin.Module) diff --git a/pkg/models/app_plugin.go b/pkg/models/app_settings.go similarity index 64% rename from pkg/models/app_plugin.go rename to pkg/models/app_settings.go index 3676d85ab01..558946d0277 100644 --- a/pkg/models/app_plugin.go +++ b/pkg/models/app_settings.go @@ -2,9 +2,9 @@ package models import "time" -type AppPlugin struct { +type AppSettings struct { Id int64 - Type string + AppId string OrgId int64 Enabled bool Pinned bool @@ -18,19 +18,18 @@ type AppPlugin struct { // COMMANDS // Also acts as api DTO -type UpdateAppPluginCmd struct { - Type string `json:"type" binding:"Required"` +type UpdateAppSettingsCmd struct { Enabled bool `json:"enabled"` Pinned bool `json:"pinned"` JsonData map[string]interface{} `json:"jsonData"` - Id int64 `json:"-"` - OrgId int64 `json:"-"` + AppId string `json:"-"` + OrgId int64 `json:"-"` } // --------------------- // QUERIES -type GetAppPluginsQuery struct { +type GetAppSettingsQuery struct { OrgId int64 - Result []*AppPlugin + Result []*AppSettings } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 4626ad8df15..1b945141f6a 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -13,7 +13,6 @@ import ( "text/template" "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -180,78 +179,3 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error { 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 -} diff --git a/pkg/plugins/queries.go b/pkg/plugins/queries.go new file mode 100644 index 00000000000..4a7d5294128 --- /dev/null +++ b/pkg/plugins/queries.go @@ -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 +} diff --git a/pkg/services/sqlstore/app_plugin.go b/pkg/services/sqlstore/app_settings.go similarity index 64% rename from pkg/services/sqlstore/app_plugin.go rename to pkg/services/sqlstore/app_settings.go index fd0c2bc7be1..e9bfbeaa73b 100644 --- a/pkg/services/sqlstore/app_plugin.go +++ b/pkg/services/sqlstore/app_settings.go @@ -8,27 +8,27 @@ import ( ) func init() { - bus.AddHandler("sql", GetAppPlugins) - bus.AddHandler("sql", UpdateAppPlugin) + bus.AddHandler("sql", GetAppSettings) + bus.AddHandler("sql", UpdateAppSettings) } -func GetAppPlugins(query *m.GetAppPluginsQuery) error { +func GetAppSettings(query *m.GetAppSettingsQuery) error { sess := x.Where("org_id=?", query.OrgId) - query.Result = make([]*m.AppPlugin, 0) + query.Result = make([]*m.AppSettings, 0) return sess.Find(&query.Result) } -func UpdateAppPlugin(cmd *m.UpdateAppPluginCmd) error { +func UpdateAppSettings(cmd *m.UpdateAppSettingsCmd) 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("pinned") if !exists { - app = m.AppPlugin{ - Type: cmd.Type, + app = m.AppSettings{ + AppId: cmd.AppId, OrgId: cmd.OrgId, Enabled: cmd.Enabled, Pinned: cmd.Pinned, diff --git a/pkg/services/sqlstore/migrations/app_plugin.go b/pkg/services/sqlstore/migrations/app_settings.go similarity index 62% rename from pkg/services/sqlstore/migrations/app_plugin.go rename to pkg/services/sqlstore/migrations/app_settings.go index 7a1e67cf191..437debbe95b 100644 --- a/pkg/services/sqlstore/migrations/app_plugin.go +++ b/pkg/services/sqlstore/migrations/app_settings.go @@ -2,14 +2,14 @@ package migrations import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" -func addAppPluginMigration(mg *Migrator) { +func addAppSettingsMigration(mg *Migrator) { - var appPluginV2 = Table{ - Name: "app_plugin", + appSettingsV1 := Table{ + Name: "app_settings", Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: 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: "pinned", Type: DB_Bool, Nullable: false}, {Name: "json_data", Type: DB_Text, Nullable: true}, @@ -17,12 +17,12 @@ func addAppPluginMigration(mg *Migrator) { {Name: "updated", Type: DB_DateTime, Nullable: false}, }, 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 ------------------ - addTableIndicesMigrations(mg, "v2", appPluginV2) + addTableIndicesMigrations(mg, "v3", appSettingsV1) } diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index a6f3eacffc3..a2baac7be5e 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -18,7 +18,7 @@ func AddMigrations(mg *Migrator) { addApiKeyMigrations(mg) addDashboardSnapshotMigrations(mg) addQuotaMigration(mg) - addAppPluginMigration(mg) + addAppSettingsMigration(mg) addSessionMigration(mg) } diff --git a/public/app/core/routes/all.js b/public/app/core/routes/all.js index 0d4741c9e47..cc4d73ef708 100644 --- a/public/app/core/routes/all.js +++ b/public/app/core/routes/all.js @@ -138,7 +138,7 @@ define([ controllerAs: 'ctrl', resolve: loadAppsBundle, }) - .when('/apps/edit/:type', { + .when('/apps/edit/:appId', { templateUrl: 'app/features/apps/partials/edit.html', controller: 'AppEditCtrl', controllerAs: 'ctrl', diff --git a/public/app/features/apps/all.ts b/public/app/features/apps/all.ts index 005c0796493..fcdd27dff4d 100644 --- a/public/app/features/apps/all.ts +++ b/public/app/features/apps/all.ts @@ -1,3 +1,2 @@ import './edit_ctrl'; import './list_ctrl'; -import './app_srv'; diff --git a/public/app/features/apps/app_srv.ts b/public/app/features/apps/app_srv.ts index 0f937e601bc..18c6979b388 100644 --- a/public/app/features/apps/app_srv.ts +++ b/public/app/features/apps/app_srv.ts @@ -15,9 +15,6 @@ export class AppSrv { } get(type) { - if (this.apps[type]) { - return this.$q.when(this.apps[type]); - } return this.getAll().then(() => { return this.apps[type]; }); @@ -38,7 +35,7 @@ export class AppSrv { update(app) { return this.backendSrv.post('api/org/apps', app).then(resp => { - this.apps[app.type] = app; + }); } } diff --git a/public/app/features/apps/edit_ctrl.ts b/public/app/features/apps/edit_ctrl.ts index 7c4553ac332..fe77c0a6797 100644 --- a/public/app/features/apps/edit_ctrl.ts +++ b/public/app/features/apps/edit_ctrl.ts @@ -8,20 +8,36 @@ export class AppEditCtrl { appModel: any; /** @ngInject */ - constructor(private appSrv: any, private $routeParams: any) {} + constructor(private backendSrv: any, private $routeParams: any) {} init() { this.appModel = {}; - this.appSrv.get(this.$routeParams.type).then(result => { - this.appModel = _.clone(result); + this.backendSrv.get(`/api/org/apps/${this.$routeParams.appId}/settings`).then(result => { + this.appModel = result; }); } - update() { - this.appSrv.update(this.appModel).then(function() { - window.location.href = config.appSubUrl + "org/apps"; + update(options) { + var updateCmd = _.extend({ + 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); diff --git a/public/app/features/apps/list_ctrl.ts b/public/app/features/apps/list_ctrl.ts index 7d89a3baffe..3f195536ae4 100644 --- a/public/app/features/apps/list_ctrl.ts +++ b/public/app/features/apps/list_ctrl.ts @@ -7,11 +7,11 @@ export class AppListCtrl { apps: any[]; /** @ngInject */ - constructor(private appSrv: any) {} + constructor(private backendSrv: any) {} init() { - this.appSrv.getAll().then(result => { - this.apps = result; + this.backendSrv.get('api/org/apps').then(apps => { + this.apps = apps; }); } } diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index 3dd8e24d593..da029b51b8c 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -1,7 +1,7 @@ @@ -25,10 +25,12 @@ {{ctrl.appModel.info.description}} +

    - - + +       +
    diff --git a/public/app/features/apps/partials/list.html b/public/app/features/apps/partials/list.html index 37897546eed..c682d2fc8ef 100644 --- a/public/app/features/apps/partials/list.html +++ b/public/app/features/apps/partials/list.html @@ -15,10 +15,13 @@
      • +
      • + +
      • diff --git a/public/less/filter-list.less b/public/less/filter-list.less index 181aedf4d3c..2e9ea259d0f 100644 --- a/public/less/filter-list.less +++ b/public/less/filter-list.less @@ -52,6 +52,12 @@ font-weight: normal; } +.filter-list-card-image { + width: 50px; + padding: 5px 50px 5px 5px; +} + + .filter-list-card-status { color: #777; font-size: 12px; diff --git a/tasks/options/watch.js b/tasks/options/watch.js index db250d56862..515877b102e 100644 --- a/tasks/options/watch.js +++ b/tasks/options/watch.js @@ -33,6 +33,9 @@ module.exports = function(config, grunt) { grunt.config(option, result); grunt.task.run('typescript:build'); grunt.task.run('tslint'); + // copy ts file also used by source maps + newPath = filepath.replace(/^public/, 'public_gen'); + grunt.file.copy(filepath, newPath); } }); From 4da31291d265edaebb7e3de7c7062c981b9864b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 11 Jan 2016 10:44:04 +0100 Subject: [PATCH 31/36] feat(apps): minor progress to apps list --- pkg/plugins/app_plugin.go | 9 +++++---- public/app/features/apps/partials/list.html | 10 +++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index 13a9bc43f94..7ffc24cfc0b 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -20,10 +20,11 @@ type AppPluginCss struct { type AppPlugin struct { FrontendPluginBase - Enabled bool `json:"enabled"` - Pinned bool `json:"pinned"` - Css *AppPluginCss `json:"css"` - Page *AppPluginPage `json:"page"` + Css *AppPluginCss `json:"css"` + Page *AppPluginPage `json:"page"` + + Pinned bool `json:"-"` + Enabled bool `json:"-"` } func (p *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { diff --git a/public/app/features/apps/partials/list.html b/public/app/features/apps/partials/list.html index c682d2fc8ef..0bdaebe3657 100644 --- a/public/app/features/apps/partials/list.html +++ b/public/app/features/apps/partials/list.html @@ -26,7 +26,15 @@
        - {{app.name}} + + + {{app.name}} + +     + + enabled + + Dashboards: 1 From e081a5c5a0fdf274433e5c5d40e65575079ea1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 11 Jan 2016 18:03:08 +0100 Subject: [PATCH 32/36] feat(apps): worked on pinning apps --- pkg/api/dtos/index.go | 1 + pkg/api/index.go | 14 ++++----- pkg/plugins/app_plugin.go | 5 ++-- pkg/plugins/queries.go | 31 ++++---------------- public/app/core/controllers/sidemenu_ctrl.js | 1 + public/app/features/apps/partials/list.html | 7 ++++- public/app/partials/sidemenu.html | 5 +++- public/less/sidemenu.less | 4 +++ 8 files changed, 29 insertions(+), 39 deletions(-) diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go index 64abec6f4e5..c5b81ee0e98 100644 --- a/pkg/api/dtos/index.go +++ b/pkg/api/dtos/index.go @@ -21,5 +21,6 @@ type PluginCss struct { type NavLink struct { Text string `json:"text"` Icon string `json:"icon"` + Img string `json:"img"` Url string `json:"url"` } diff --git a/pkg/api/index.go b/pkg/api/index.go index bbe0c6565a8..ddc2429baf5 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -82,14 +82,12 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { data.PluginCss = append(data.PluginCss, &dtos.PluginCss{Light: plugin.Css.Light, Dark: plugin.Css.Dark}) } - if plugin.Pinned && plugin.Page != nil { - if c.HasUserRole(plugin.Page.ReqRole) { - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: plugin.Page.Text, - Url: plugin.Page.Url, - Icon: plugin.Page.Icon, - }) - } + if plugin.Pinned { + data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ + Text: plugin.Name, + Url: setting.AppSubUrl + "/apps/edit/" + plugin.Id, + Img: plugin.Info.Logos.Small, + }) } } diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index 7ffc24cfc0b..b8a3eee2bc0 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -8,7 +8,6 @@ import ( type AppPluginPage struct { Text string `json:"text"` - Icon string `json:"icon"` Url string `json:"url"` ReqRole models.RoleType `json:"reqRole"` } @@ -20,8 +19,8 @@ type AppPluginCss struct { type AppPlugin struct { FrontendPluginBase - Css *AppPluginCss `json:"css"` - Page *AppPluginPage `json:"page"` + Css *AppPluginCss `json:"css"` + Page []*AppPluginPage `json:"page"` Pinned bool `json:"-"` Enabled bool `json:"-"` diff --git a/pkg/plugins/queries.go b/pkg/plugins/queries.go index 4a7d5294128..889cbe654d5 100644 --- a/pkg/plugins/queries.go +++ b/pkg/plugins/queries.go @@ -30,41 +30,20 @@ func GetEnabledPlugins(orgId int64) (*EnabledPlugins, error) { seenPanels := make(map[string]bool) seenApi := make(map[string]bool) - for appType, installedApp := range Apps { + for appId, 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 { + if b, ok := orgApps[appId]; 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) - // } + if app.Enabled { + enabledPlugins.Apps = append(enabledPlugins.Apps, &app) + } } // add all plugins that are not part of an App. diff --git a/public/app/core/controllers/sidemenu_ctrl.js b/public/app/core/controllers/sidemenu_ctrl.js index 368d275a3df..5bca63cb1cd 100644 --- a/public/app/core/controllers/sidemenu_ctrl.js +++ b/public/app/core/controllers/sidemenu_ctrl.js @@ -19,6 +19,7 @@ function (angular, _, $, coreModule, config) { $scope.mainLinks.push({ text: item.text, icon: item.icon, + img: item.img, url: $scope.getUrl(item.url) }); }); diff --git a/public/app/features/apps/partials/list.html b/public/app/features/apps/partials/list.html index 0bdaebe3657..f6c915ff4ce 100644 --- a/public/app/features/apps/partials/list.html +++ b/public/app/features/apps/partials/list.html @@ -32,8 +32,13 @@     - enabled + Enabled +   + + Pinned + + Dashboards: 1 diff --git a/public/app/partials/sidemenu.html b/public/app/partials/sidemenu.html index bf75b465be8..5e83b623438 100644 --- a/public/app/partials/sidemenu.html +++ b/public/app/partials/sidemenu.html @@ -46,7 +46,10 @@
      • - + + + + {{item.text}}
      • diff --git a/public/less/sidemenu.less b/public/less/sidemenu.less index ac3470c65ea..6e9691eaa11 100644 --- a/public/less/sidemenu.less +++ b/public/less/sidemenu.less @@ -92,6 +92,10 @@ top: 5px; font-size: 150%; } + img { + left: 7px; + position: relative; + } } .sidemenu-item { From 2fe58461d5ff1ce0a776d8dcd55600f02ef87acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 11 Jan 2016 22:51:40 +0100 Subject: [PATCH 33/36] feat(apps): minor fix for images --- public/app/features/apps/partials/list.html | 2 +- public/app/partials/sidemenu.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/apps/partials/list.html b/public/app/features/apps/partials/list.html index f6c915ff4ce..c8d284712a5 100644 --- a/public/app/features/apps/partials/list.html +++ b/public/app/features/apps/partials/list.html @@ -16,7 +16,7 @@
        • - +
        • diff --git a/public/app/partials/sidemenu.html b/public/app/partials/sidemenu.html index 5e83b623438..87eab7b5fb4 100644 --- a/public/app/partials/sidemenu.html +++ b/public/app/partials/sidemenu.html @@ -48,7 +48,7 @@ - + {{item.text}} From ffe1407217abb585468cb239a35ef0b79568809f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 12 Jan 2016 10:20:04 +0100 Subject: [PATCH 34/36] feat(apps): minor progress --- pkg/api/index.go | 2 +- pkg/plugins/app_plugin.go | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/api/index.go b/pkg/api/index.go index ddc2429baf5..e5375945c6b 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -85,7 +85,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { if plugin.Pinned { data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ Text: plugin.Name, - Url: setting.AppSubUrl + "/apps/edit/" + plugin.Id, + Url: "/apps/edit/" + plugin.Id, Img: plugin.Info.Logos.Small, }) } diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index b8a3eee2bc0..3176352f269 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -26,13 +26,18 @@ type AppPlugin struct { Enabled bool `json:"-"` } -func (p *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { - if err := decoder.Decode(&p); err != nil { +func (app *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { + if err := decoder.Decode(&app); err != nil { return err } - p.PluginDir = pluginDir - p.initFrontendPlugin() - Apps[p.Id] = p + if app.Css != nil { + app.Css.Dark = evalRelativePluginUrlPath(app.Css.Dark, app.Id) + app.Css.Light = evalRelativePluginUrlPath(app.Css.Light, app.Id) + } + + app.PluginDir = pluginDir + app.initFrontendPlugin() + Apps[app.Id] = app return nil } From 4c59e48cc277138681524ffed80c8d4ab2535810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 12 Jan 2016 12:25:07 +0100 Subject: [PATCH 35/36] feat(apps): worked on apps edit view styles --- public/app/features/apps/partials/edit.html | 64 ++++++++++++++++++++- public/less/grafana.less | 1 + public/less/simple-box.less | 46 +++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 public/less/simple-box.less diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index da029b51b8c..9b041270d28 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -21,7 +21,7 @@
          -

          {{ctrl.appModel.name}}

          +

          {{ctrl.appModel.name}}

          {{ctrl.appModel.info.description}} @@ -33,6 +33,66 @@
          - +
          +

          Included with app:

          +
          +
          +
          + + Dashboards +
          +
            +
          • Test
          • +
          • Test2
          • +
          +
          +
          +
          + + Panels +
          +
            +
          • Test
          • +
          • Test2
          • +
          +
          +
          +
          + + Datasources +
          +
            +
          • Test
          • +
          • Test2
          • +
          +
          +
          +
          + + Pages +
          +
            +
          • Test
          • +
          • Test2
          • +
          +
          + +
          +
          + +
          +

          Dependencies:

          +
          + Grafana 2.6.x +
          +
          + +
          +

          Configuration:

          +
          +
          +
          + + diff --git a/public/less/grafana.less b/public/less/grafana.less index 6e31e628c82..9cf3630db3e 100644 --- a/public/less/grafana.less +++ b/public/less/grafana.less @@ -25,6 +25,7 @@ @import "filter-controls.less"; @import "filter-list.less"; @import "filter-table.less"; +@import "simple-box.less"; .row-control-inner { padding:0px; diff --git a/public/less/simple-box.less b/public/less/simple-box.less new file mode 100644 index 00000000000..65cd63fe0e3 --- /dev/null +++ b/public/less/simple-box.less @@ -0,0 +1,46 @@ + +@simpleBoxBorderWidth: 0.2rem; +@simpleBoxMargin: 1.5rem; +@simpleBoxBodyPadding: 0.5rem 0 0.5rem 1rem; + +.simple-box { + margin-top: @simpleBoxMargin; + background: @grafanaPanelBackground; +} + +.simple-box-header { + font-weight: normal; + line-height: 2.5rem; + color: @textColor; + margin: 0; + padding-left: 1rem; + border-bottom: @simpleBoxBorderWidth solid @bodyBackground; +} + +.simple-box-column { + flex-direction: row; + width: 25%; + border-right: @simpleBoxBorderWidth solid @bodyBackground; + ul { + margin: 0.7rem 0 1rem 1.2rem; + } +} + +.simple-box-column:last-child { + border: none; +} + +.simple-box-column-header { + font-size: @fontSizeLarge; + i { + padding-right: 0.3rem; + } +} + +.simple-box-body { + padding: @simpleBoxBodyPadding; +} + +.flex-container { + display: flex; +} From a15984b6633efbb1c5e38ad3a93819d3e7e75e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 12 Jan 2016 15:39:29 +0100 Subject: [PATCH 36/36] feat(apps): pages work --- pkg/api/dtos/apps.go | 14 ++++++------ pkg/plugins/app_plugin.go | 6 +++--- pkg/plugins/models.go | 2 ++ public/app/features/apps/partials/edit.html | 24 ++++++++++++--------- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/pkg/api/dtos/apps.go b/pkg/api/dtos/apps.go index 2db2879f5f7..c520b6921a1 100644 --- a/pkg/api/dtos/apps.go +++ b/pkg/api/dtos/apps.go @@ -6,12 +6,13 @@ import ( ) 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"` + 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 { @@ -19,6 +20,7 @@ func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSet AppId: def.Id, Name: def.Name, Info: &def.Info, + Pages: def.Pages, } if data != nil { diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index 3176352f269..9580f0024f4 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -7,7 +7,7 @@ import ( ) type AppPluginPage struct { - Text string `json:"text"` + Name string `json:"name"` Url string `json:"url"` ReqRole models.RoleType `json:"reqRole"` } @@ -19,8 +19,8 @@ type AppPluginCss struct { type AppPlugin struct { FrontendPluginBase - Css *AppPluginCss `json:"css"` - Page []*AppPluginPage `json:"page"` + Css *AppPluginCss `json:"css"` + Pages []*AppPluginPage `json:"pages"` Pinned bool `json:"-"` Enabled bool `json:"-"` diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 2ddbcf1dd83..65bd0ef1f2d 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -24,6 +24,8 @@ type PluginInfo struct { Description string `json:"description"` Links []PluginInfoLink `json:"links"` Logos PluginLogos `json:"logos"` + Version string `json:"version"` + Updated string `json:"updated"` } type PluginInfoLink struct { diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html index 9b041270d28..ff022299ac2 100644 --- a/public/app/features/apps/partials/edit.html +++ b/public/app/features/apps/partials/edit.html @@ -21,9 +21,15 @@
          -

          {{ctrl.appModel.name}}

          +

          + {{ctrl.appModel.name}} +

          - {{ctrl.appModel.info.description}} + {{ctrl.appModel.info.description}}
          + + Version: {{ctrl.appModel.info.version}}     Updated: {{ctrl.appModel.info.updated}} + +


          @@ -42,8 +48,7 @@ Dashboards
            -
          • Test
          • -
          • Test2
          • +
          • None
          @@ -52,8 +57,7 @@ Panels
            -
          • Test
          • -
          • Test2
          • +
          • None
          @@ -62,8 +66,7 @@ Datasources
            -
          • Test
          • -
          • Test2
          • +
          • None
          @@ -72,8 +75,9 @@ Pages
    -   +   {{annotation.name}}