Преглед изворни кода

feat(apps): lots of progress

Torkel Ödegaard пре 10 година
родитељ
комит
7a8b3c419b

+ 1 - 0
pkg/api/app_plugin.go

@@ -22,6 +22,7 @@ func GetAppPlugins(c *middleware.Context) Response {
 			Enabled: app.Enabled,
 			Enabled: app.Enabled,
 			Pinned:  app.Pinned,
 			Pinned:  app.Pinned,
 			Module:  app.Module,
 			Module:  app.Module,
+			Info:    app.Info,
 		}
 		}
 	}
 	}
 
 

+ 3 - 0
pkg/api/dtos/app_plugin.go

@@ -1,10 +1,13 @@
 package dtos
 package dtos
 
 
+import "github.com/grafana/grafana/pkg/plugins"
+
 type AppPlugin struct {
 type AppPlugin struct {
 	Name     string                 `json:"name"`
 	Name     string                 `json:"name"`
 	Type     string                 `json:"type"`
 	Type     string                 `json:"type"`
 	Enabled  bool                   `json:"enabled"`
 	Enabled  bool                   `json:"enabled"`
 	Pinned   bool                   `json:"pinned"`
 	Pinned   bool                   `json:"pinned"`
 	Module   string                 `json:"module"`
 	Module   string                 `json:"module"`
+	Info     *plugins.PluginInfo    `json:"info"`
 	JsonData map[string]interface{} `json:"jsonData"`
 	JsonData map[string]interface{} `json:"jsonData"`
 }
 }

+ 5 - 5
pkg/plugins/models.go

@@ -5,13 +5,13 @@ import (
 )
 )
 
 
 type PluginInfo struct {
 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"`
 	Name string `json:"name"`
 	Url  string `json:"url"`
 	Url  string `json:"url"`
 }
 }

+ 33 - 2
pkg/plugins/plugins.go

@@ -1,12 +1,15 @@
 package plugins
 package plugins
 
 
 import (
 import (
+	"bytes"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
+	"io"
 	"os"
 	"os"
 	"path"
 	"path"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
+	"text/template"
 
 
 	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/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 {
 func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
 	currentDir := filepath.Dir(pluginJsonFilePath)
 	currentDir := filepath.Dir(pluginJsonFilePath)
 	reader, err := os.Open(pluginJsonFilePath)
 	reader, err := os.Open(pluginJsonFilePath)
@@ -128,7 +153,6 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
 	defer reader.Close()
 	defer reader.Close()
 
 
 	jsonParser := json.NewDecoder(reader)
 	jsonParser := json.NewDecoder(reader)
-
 	pluginJson := make(map[string]interface{})
 	pluginJson := make(map[string]interface{})
 	if err := jsonParser.Decode(&pluginJson); err != nil {
 	if err := jsonParser.Decode(&pluginJson); err != nil {
 		return err
 		return err
@@ -139,9 +163,16 @@ func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
 		return errors.New("Did not find pluginType property in plugin.json")
 		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" {
 	if pluginType == "datasource" {
 		p := DataSourcePlugin{}
 		p := DataSourcePlugin{}
-		reader.Seek(0, 0)
 		if err := jsonParser.Decode(&p); err != nil {
 		if err := jsonParser.Decode(&p); err != nil {
 			return err
 			return err
 		}
 		}

+ 13 - 0
pkg/plugins/plugins_test.go

@@ -18,5 +18,18 @@ func TestPluginScans(t *testing.T) {
 
 
 		So(err, ShouldBeNil)
 		So(err, ShouldBeNil)
 		So(len(DataSources), ShouldBeGreaterThan, 1)
 		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")
+	})
+
 }
 }

+ 12 - 1
public/app/features/apps/partials/edit.html

@@ -6,8 +6,20 @@
 </topnav>
 </topnav>
 
 
 <div class="page-container" style="background: transparent; border: 0;">
 <div class="page-container" style="background: transparent; border: 0;">
+	<div class="apps-side-box">
+		<img class="apps-ide-box-logo" src="{{ctrl.appModel.info.logos.large}}">
+		</img>
+		<ul class="app-side-box-links">
+			<li ng-repeat="link in ctrl.appModel.info.links">
+				<a href="{{link.url}}">{{link.name}}</a>
+			</li>
+		</ul>
+	</div>
   <div class="page-wide" ng-init="ctrl.init()">
   <div class="page-wide" ng-init="ctrl.init()">
 		<h2>{{ctrl.appModel.name}}</h2>
 		<h2>{{ctrl.appModel.name}}</h2>
+		<em>
+			{{ctrl.appModel.info.description}}
+		</em>
 
 
 		<form name="editForm">
 		<form name="editForm">
 			<div class="tight-form">
 			<div class="tight-form">
@@ -24,6 +36,5 @@
 
 
 			<app-config-loader></app-config-loader>
 			<app-config-loader></app-config-loader>
 		</form>
 		</form>
-
 	</div>
 	</div>
 </div>
 </div>

+ 50 - 0
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"}
+    ]
+  }
+}