feat(plugins): progress on plugin details page, # 4275

This commit is contained in:
Torkel Ödegaard 2016-03-07 14:31:02 +01:00
parent 1ff428087e
commit 135679096b
14 changed files with 107 additions and 37 deletions

View File

@ -35,7 +35,7 @@
}, },
"dependencies": { "dependencies": {
"grafanaVersion": "2.6.x", "grafanaVersion": "3.x.x",
"plugins": [ "plugins": [
{"type": "datasource", "id": "graphite", "name": "Graphite", "version": "1.0.0"}, {"type": "datasource", "id": "graphite", "name": "Graphite", "version": "1.0.0"},
{"type": "panel", "id": "graph", "name": "Graph", "version": "1.0.0"} {"type": "panel", "id": "graph", "name": "Graph", "version": "1.0.0"}

View File

@ -3,17 +3,18 @@ package dtos
import "github.com/grafana/grafana/pkg/plugins" import "github.com/grafana/grafana/pkg/plugins"
type PluginSetting struct { type PluginSetting struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
PluginId string `json:"pluginId"` PluginId string `json:"pluginId"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Pinned bool `json:"pinned"` Pinned bool `json:"pinned"`
Module string `json:"module"` Module string `json:"module"`
BaseUrl string `json:"baseUrl"` BaseUrl string `json:"baseUrl"`
Info *plugins.PluginInfo `json:"info"` Info *plugins.PluginInfo `json:"info"`
Pages []*plugins.AppPluginPage `json:"pages"` Pages []*plugins.AppPluginPage `json:"pages"`
Includes []*plugins.AppIncludeInfo `json:"includes"` Includes []*plugins.AppIncludeInfo `json:"includes"`
JsonData map[string]interface{} `json:"jsonData"` Dependencies *plugins.PluginDependencies `json:"dependencies"`
JsonData map[string]interface{} `json:"jsonData"`
} }
type PluginListItem struct { type PluginListItem struct {

View File

@ -42,10 +42,11 @@ func GetPluginSettingById(c *middleware.Context) Response {
return ApiError(404, "Plugin not found, no installed plugin with that id", nil) return ApiError(404, "Plugin not found, no installed plugin with that id", nil)
} else { } else {
dto := &dtos.PluginSetting{ dto := &dtos.PluginSetting{
Type: def.Type, Type: def.Type,
PluginId: def.Id, PluginId: def.Id,
Name: def.Name, Name: def.Name,
Info: &def.Info, Info: &def.Info,
Dependencies: &def.Dependencies,
} }
if app, exists := plugins.Apps[pluginId]; exists { if app, exists := plugins.Apps[pluginId]; exists {

View File

@ -24,7 +24,7 @@ import (
"github.com/grafana/grafana/pkg/social" "github.com/grafana/grafana/pkg/social"
) )
var version = "master" var version = "3.0.0-pre1"
var commit = "NA" var commit = "NA"
var buildstamp string var buildstamp string
var build_date string var build_date string

View File

@ -28,8 +28,8 @@ func (fp *FrontendPluginBase) initFrontendPlugin() {
fp.handleModuleDefaults() fp.handleModuleDefaults()
fp.Info.Logos.Small = evalRelativePluginUrlPath(fp.Info.Logos.Small, fp.Id) fp.Info.Logos.Small = evalRelativePluginUrlPath(fp.Info.Logos.Small, fp.BaseUrl)
fp.Info.Logos.Large = evalRelativePluginUrlPath(fp.Info.Logos.Large, fp.Id) fp.Info.Logos.Large = evalRelativePluginUrlPath(fp.Info.Logos.Large, fp.BaseUrl)
for i := 0; i < len(fp.Info.Screenshots); i++ { for i := 0; i < len(fp.Info.Screenshots); i++ {
fp.Info.Screenshots[i].Path = evalRelativePluginUrlPath(fp.Info.Screenshots[i].Path, fp.Id) fp.Info.Screenshots[i].Path = evalRelativePluginUrlPath(fp.Info.Screenshots[i].Path, fp.Id)
@ -55,7 +55,7 @@ func (fp *FrontendPluginBase) handleModuleDefaults() {
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id) fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id)
} }
func evalRelativePluginUrlPath(pathStr string, pluginId string) string { func evalRelativePluginUrlPath(pathStr string, baseUrl string) string {
if pathStr == "" { if pathStr == "" {
return "" return ""
} }
@ -64,5 +64,5 @@ func evalRelativePluginUrlPath(pathStr string, pluginId string) string {
if u.IsAbs() { if u.IsAbs() {
return pathStr return pathStr
} }
return path.Join("public/plugins", pluginId, pathStr) return path.Join(baseUrl, pathStr)
} }

View File

@ -14,10 +14,11 @@ type PluginLoader interface {
} }
type PluginBase struct { type PluginBase struct {
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Id string `json:"id"` Id string `json:"id"`
Info PluginInfo `json:"info"` Info PluginInfo `json:"info"`
Dependencies PluginDependencies `json:"dependencies"`
IncludedInAppId string `json:"-"` IncludedInAppId string `json:"-"`
PluginDir string `json:"-"` PluginDir string `json:"-"`
@ -37,6 +38,18 @@ func (pb *PluginBase) registerPlugin(pluginDir string) error {
return nil return nil
} }
type PluginDependencies struct {
GrafanaVersion string `json:"grafanaVersion"`
Plugins []PluginDependencyItem `json:"plugins"`
}
type PluginDependencyItem struct {
Type string `json:"type"`
Id string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
}
type PluginInfo struct { type PluginInfo struct {
Author PluginInfoLink `json:"author"` Author PluginInfoLink `json:"author"`
Description string `json:"description"` Description string `json:"description"`

View File

@ -19,7 +19,6 @@
<div class="tabbed-view-body"> <div class="tabbed-view-body">
<div ng-if="editor.index == 0"> <div ng-if="editor.index == 0">
<h5 class="section-heading">Dashboard Detail</h5>
<div class="gf-form-group"> <div class="gf-form-group">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-7">Title</label> <label class="gf-form-label width-7">Title</label>

View File

@ -5,6 +5,7 @@ import _ from 'lodash';
export class PluginEditCtrl { export class PluginEditCtrl {
model: any; model: any;
pluginIcon: string;
pluginId: any; pluginId: any;
includedPanels: any; includedPanels: any;
includedDatasources: any; includedDatasources: any;
@ -22,9 +23,22 @@ export class PluginEditCtrl {
this.model = result; this.model = result;
this.includedPanels = _.where(result.includes, {type: 'panel'}); this.includedPanels = _.where(result.includes, {type: 'panel'});
this.includedDatasources = _.where(result.includes, {type: 'datasource'}); this.includedDatasources = _.where(result.includes, {type: 'datasource'});
this.pluginIcon = this.getPluginIcon(this.model.type);
this.model.dependencies.plugins.forEach(plug => {
plug.icon = this.getPluginIcon(plug.type);
});
}); });
} }
getPluginIcon(type) {
switch (type) {
case 'datasource': return 'icon-gf icon-gf-datasources';
case 'panel': return 'icon-gf icon-gf-panel';
case 'app': return 'icon-gf icon-gf-apps';
}
}
update() { update() {
var chain = Promise.resolve(); var chain = Promise.resolve();
var self = this; var self = this;
@ -53,7 +67,7 @@ export class PluginEditCtrl {
// if set, performt he postUpdate hook. If a promise is returned it will block // if set, performt he postUpdate hook. If a promise is returned it will block
// the final step of the update procedure (reloading the page) until the promise // the final step of the update procedure (reloading the page) until the promise
// resolves. If the promise is rejected the page will not be reloaded. // resolves. If the promise is rejected the page will not be reloaded.
if (this.postUpdateHook != null) { if (this.postUpdateHook != null) {
chain = chain.then(function() { chain = chain.then(function() {
return Promise.resolve(this.postUpdateHook()); return Promise.resolve(this.postUpdateHook());

View File

@ -1,7 +1,6 @@
<navbar title="Plugins" title-url="plugins" icon="icon-gf icon-gf-apps"> <navbar title="Plugins" title-url="plugins" icon="icon-gf icon-gf-apps">
<a href="plugins/apps" class="navbar-page-btn"> <a href="plugins/apps" class="navbar-page-btn">
<i class="fa fa-chevron-right"></i> Plugin details
Apps
</a> </a>
</navbar> </navbar>
@ -15,7 +14,7 @@
<div class="plugin-header-author">By {{ctrl.model.info.author.name}}</div> <div class="plugin-header-author">By {{ctrl.model.info.author.name}}</div>
<div class="plugin-header-stamps"> <div class="plugin-header-stamps">
<span class="plugin-header-stamps-type"> <span class="plugin-header-stamps-type">
<i class="icon-gf icon-gf-apps"></i> {{ctrl.model.type}} <i class="{{ctrl.pluginIcon}}"></i> {{ctrl.model.type}}
</span> </span>
</div> </div>
</div> </div>
@ -59,7 +58,7 @@
<aside class="page-sidebar"> <aside class="page-sidebar">
<section class="page-sidebar-section"> <section class="page-sidebar-section">
<h4>Version</h4> <h4>Version</h4>
<span>1.0.1</span> <span>{{ctrl.model.info.version}}</span>
</section> </section>
<section class="page-sidebar-section" ng-show="ctrl.model.type === 'app'"> <section class="page-sidebar-section" ng-show="ctrl.model.type === 'app'">
<h5>Includes</h4> <h5>Includes</h4>
@ -78,7 +77,30 @@
</section> </section>
<section class="page-sidebar-section"> <section class="page-sidebar-section">
<h5>Dependencies</h4> <h5>Dependencies</h4>
<span>TODO</span> <ul class="ui-list">
<li>
<span class="plugin-dependency-icon">
<img src="public/img/grafana_icon.svg"></img>
</span>
<span class="plugin-dependency-name">
Grafana
</span>
<span class="plugin-dependency-version">
{{ctrl.model.dependencies.grafanaVersion}}
</span>
</li>
<li ng-repeat="plugDep in ctrl.model.dependencies.plugins">
<span class="plugin-dependency-icon">
<i class="{{plugDep.icon}}"></i>
</span>
<span class="plugin-dependency-name">
{{plugDep.name}}
</span>
<span class="plugin-dependency-version">
{{plugDep.version}}
</span>
</li>
</ul>
</section> </section>
<section class="page-sidebar-section"> <section class="page-sidebar-section">
<h5>Links</h4> <h5>Links</h4>

View File

@ -12,7 +12,7 @@
<div class="modal-content text-center"> <div class="modal-content text-center">
<div class="confirm-modal-title"> <div class="confirm-modal-text">
What do you want to do? What do you want to do?
</div> </div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -3,7 +3,23 @@
"name": "Elasticsearch", "name": "Elasticsearch",
"id": "elasticsearch", "id": "elasticsearch",
"defaultMatchFormat": "lucene", "info": {
"description": "Elasticsearch Data Source for Grafana",
"author": {
"name": "Grafana Core",
"url": "http://grafana.org"
},
"keywords": ["elasticsearch"],
"logos": {
"small": "img/logo_large.png",
"large": "img/logo_large.png"
},
"links": [
{"name": "elastic.co", "url": "https://www.elastic.co/products/elasticsearch"}
],
"version": "3.0.0"
},
"annotations": true, "annotations": true,
"metrics": true "metrics": true
} }

View File

@ -84,11 +84,9 @@
h4 { h4 {
font-size: $font-size-base; font-size: $font-size-base;
font-weight: $font-weight-semi-bold; font-weight: $font-weight-semi-bold;
color: $text-color-strong;
} }
h5 { h5 {
font-size: $font-size-base; font-size: $font-size-base;
color: $text-color-weak;
font-weight: $font-weight-semi-bold; font-weight: $font-weight-semi-bold;
} }
} }

View File

@ -22,10 +22,16 @@
} }
.plugin-header-stamps-type { .plugin-header-stamps-type {
color: $link-color-disabled; color: $headings-color-disabled;
text-transform: uppercase; text-transform: uppercase;
} }
.plugin-dependency-icon {
img {
width: 16px;
}
}
// .app-edit-logo-box { // .app-edit-logo-box {
// padding: 1.2rem; // padding: 1.2rem;
// background: $panel-bg; // background: $panel-bg;