diff --git a/examples/nginx-app/package.json b/examples/nginx-app/package.json
index 32c070f96b0..91c53734ec8 100644
--- a/examples/nginx-app/package.json
+++ b/examples/nginx-app/package.json
@@ -31,7 +31,7 @@
"dependencies": {
"babel-plugin-transform-es2015-modules-systemjs": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
- "lodash": "~4.0.0",
+ "lodash": "~4.0.0"
},
"homepage": "https://github.com/raintank/kentik-app-poc#readme"
}
diff --git a/examples/nginx-app/plugin.json b/examples/nginx-app/plugin.json
index 65f01ad62fc..6de4fbd4daa 100644
--- a/examples/nginx-app/plugin.json
+++ b/examples/nginx-app/plugin.json
@@ -26,6 +26,10 @@
"small": "img/logo_small.png",
"large": "img/logo_large.png"
},
+ "screenshots": [
+ {"name": "img1", "path": "img/screenshot1.png"},
+ {"name": "img2", "path": "img/screenshot2.png"}
+ ],
"links": [
{"name": "Project site", "url": "http://project.com"},
{"name": "License & Terms", "url": "http://license.com"}
@@ -35,7 +39,8 @@
},
"includes": [
- {"type": "dashboard", "name": "Nginx Connection stats", "path": "dashboards/nginx_connection_stats.json"},
+ {"type": "dashboard", "name": "Nginx Connections", "path": "dashboards/connections.json"},
+ {"type": "dashboard", "name": "Nginx Memory", "path": "dashboards/memory.json"},
{"type": "panel", "name": "Nginx Panel"},
{"type": "datasource", "name": "Nginx Datasource"}
],
diff --git a/examples/nginx-app/src/dashboards/connections.json b/examples/nginx-app/src/dashboards/connections.json
new file mode 100644
index 00000000000..f1f62826f73
--- /dev/null
+++ b/examples/nginx-app/src/dashboards/connections.json
@@ -0,0 +1,5 @@
+{
+ "title": "Nginx Connections",
+ "revision": "1.5",
+ "schemaVersion": 11
+}
diff --git a/examples/nginx-app/src/dashboards/dashboard.js b/examples/nginx-app/src/dashboards/dashboard.js
deleted file mode 100644
index 794e2c5217b..00000000000
--- a/examples/nginx-app/src/dashboards/dashboard.js
+++ /dev/null
@@ -1,17 +0,0 @@
-require([
-], function () {
-
- function Dashboard() {
-
- this.getInputs = function() {
-
- };
-
- this.buildDashboard = function() {
-
- };
- }
-
- return Dashboard;
-});
-
diff --git a/examples/nginx-app/src/dashboards/memory.json b/examples/nginx-app/src/dashboards/memory.json
new file mode 100644
index 00000000000..b79cb4d7dba
--- /dev/null
+++ b/examples/nginx-app/src/dashboards/memory.json
@@ -0,0 +1,5 @@
+{
+ "title": "Nginx Memory",
+ "revision": "2.0",
+ "schemaVersion": 11
+}
diff --git a/examples/nginx-app/src/dashboards/nginx_connection_stats.json b/examples/nginx-app/src/dashboards/nginx_connection_stats.json
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go
index 1015dfbe28c..3e87f504a77 100644
--- a/pkg/models/dashboards.go
+++ b/pkg/models/dashboards.go
@@ -102,8 +102,11 @@ func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
}
// GetString a
-func (dash *Dashboard) GetString(prop string) string {
- return dash.Data[prop].(string)
+func (dash *Dashboard) GetString(prop string, defaultValue string) string {
+ if val, exists := dash.Data[prop]; exists {
+ return val.(string)
+ }
+ return defaultValue
}
// UpdateSlug updates the slug
diff --git a/pkg/plugins/dashboards.go b/pkg/plugins/dashboards.go
new file mode 100644
index 00000000000..f253db480a0
--- /dev/null
+++ b/pkg/plugins/dashboards.go
@@ -0,0 +1,77 @@
+package plugins
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+
+ "github.com/grafana/grafana/pkg/bus"
+ m "github.com/grafana/grafana/pkg/models"
+)
+
+type PluginDashboardInfoDTO struct {
+ Title string
+ InstalledURI string
+ InstalledRevision string
+ Revision string
+ Description string
+}
+
+func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDTO, error) {
+ plugin, exists := Plugins[pluginId]
+
+ if !exists {
+ return nil, &PluginNotFoundError{pluginId}
+ }
+
+ result := make([]*PluginDashboardInfoDTO, 0)
+
+ for _, include := range plugin.Includes {
+ if include.Type == PluginTypeDashboard {
+ if dashInfo, err := getDashboardImportStatus(orgId, plugin, include); err != nil {
+ return nil, err
+ } else {
+ result = append(result, dashInfo)
+ }
+ }
+ }
+
+ return result, nil
+}
+
+func getDashboardImportStatus(orgId int64, plugin *PluginBase, dashInclude *PluginInclude) (*PluginDashboardInfoDTO, error) {
+ res := &PluginDashboardInfoDTO{}
+
+ dashboardFilePath := filepath.Join(plugin.PluginDir, dashInclude.Path)
+ reader, err := os.Open(dashboardFilePath)
+ if err != nil {
+ return nil, err
+ }
+
+ defer reader.Close()
+
+ jsonParser := json.NewDecoder(reader)
+ var data map[string]interface{}
+
+ if err := jsonParser.Decode(&data); err != nil {
+ return nil, err
+ }
+
+ dashboard := m.NewDashboardFromJson(data)
+
+ res.Title = dashboard.Title
+ res.Revision = dashboard.GetString("revision", "1.0")
+
+ query := m.GetDashboardQuery{OrgId: orgId, Slug: dashboard.Slug}
+
+ if err := bus.Dispatch(&query); err != nil {
+ if err != m.ErrDashboardNotFound {
+ return nil, err
+ }
+ } else {
+ res.InstalledURI = "db/" + query.Result.Slug
+ res.InstalledRevision = query.Result.GetString("revision", "1.0")
+ }
+
+ return res, nil
+}
diff --git a/pkg/plugins/dashboards_test.go b/pkg/plugins/dashboards_test.go
new file mode 100644
index 00000000000..b8ab51940a1
--- /dev/null
+++ b/pkg/plugins/dashboards_test.go
@@ -0,0 +1,53 @@
+package plugins
+
+import (
+ "testing"
+
+ "github.com/grafana/grafana/pkg/bus"
+ m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/setting"
+ . "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
+)
+
+func TestPluginDashboards(t *testing.T) {
+
+ Convey("When asking plugin dashboard info", t, func() {
+ setting.Cfg = ini.Empty()
+ sec, _ := setting.Cfg.NewSection("plugin.nginx-app")
+ sec.NewKey("path", "../../examples/nginx-app")
+ err := Init()
+
+ So(err, ShouldBeNil)
+
+ bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
+ if query.Slug == "nginx-connections" {
+ dash := m.NewDashboard("Nginx Connections")
+ dash.Data["revision"] = "1.1"
+ query.Result = dash
+ return nil
+ }
+
+ return m.ErrDashboardNotFound
+ })
+
+ dashboards, err := GetPluginDashboards(1, "nginx-app")
+
+ So(err, ShouldBeNil)
+
+ Convey("should return 2 dashboarrd", func() {
+ So(len(dashboards), ShouldEqual, 2)
+ })
+
+ Convey("should include installed version info", func() {
+ So(dashboards[0].Title, ShouldEqual, "Nginx Connections")
+ So(dashboards[0].Revision, ShouldEqual, "1.5")
+ So(dashboards[0].InstalledRevision, ShouldEqual, "1.1")
+ So(dashboards[0].InstalledURI, ShouldEqual, "db/nginx-connections")
+
+ So(dashboards[1].Revision, ShouldEqual, "2.0")
+ So(dashboards[1].InstalledRevision, ShouldEqual, "")
+ })
+ })
+
+}
diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go
index 0addaac9bb7..ac9fb5e04dc 100644
--- a/pkg/plugins/models.go
+++ b/pkg/plugins/models.go
@@ -3,12 +3,28 @@ package plugins
import (
"encoding/json"
"errors"
+ "fmt"
"strings"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/setting"
)
+var (
+ PluginTypeApp = "app"
+ PluginTypeDatasource = "datasource"
+ PluginTypePanel = "panel"
+ PluginTypeDashboard = "dashboard"
+)
+
+type PluginNotFoundError struct {
+ PluginId string
+}
+
+func (e *PluginNotFoundError) Error() string {
+ return fmt.Sprintf("Plugin with id %s not found", e.PluginId)
+}
+
type PluginLoader interface {
Load(decoder *json.Decoder, pluginDir string) error
}
diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go
index 08ff3cbdfdd..b7f4b845fb5 100644
--- a/pkg/plugins/plugins_test.go
+++ b/pkg/plugins/plugins_test.go
@@ -27,14 +27,15 @@ func TestPluginScans(t *testing.T) {
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")
+ sec, _ := setting.Cfg.NewSection("plugin.nginx-app")
+ sec.NewKey("path", "../../examples/nginx-app")
err := Init()
So(err, ShouldBeNil)
So(len(Apps), ShouldBeGreaterThan, 0)
- So(Apps["app-example"].Info.Logos.Large, ShouldEqual, "public/plugins/app-example/img/logo_large.png")
- So(Apps["app-example"].Info.Screenshots[1].Path, ShouldEqual, "public/plugins/app-example/img/screenshot2.png")
+
+ So(Apps["nginx-app"].Info.Logos.Large, ShouldEqual, "public/plugins/nginx-app/img/logo_large.png")
+ So(Apps["nginx-app"].Info.Screenshots[1].Path, ShouldEqual, "public/plugins/nginx-app/img/screenshot2.png")
})
}
diff --git a/public/app/features/dashboard/import_list/import_list.ts b/public/app/features/dashboard/import_list/import_list.ts
index b4fe3c36352..09a5b65de76 100644
--- a/public/app/features/dashboard/import_list/import_list.ts
+++ b/public/app/features/dashboard/import_list/import_list.ts
@@ -1,10 +1,10 @@
///