feat(apps): progress on app dashboard imports

This commit is contained in:
Torkel Ödegaard 2016-07-08 09:35:06 +02:00
parent b62f1f00cd
commit d44325affd
11 changed files with 116 additions and 35 deletions

View File

@ -211,7 +211,7 @@ func Register(r *macaron.Macaron) {
// Dashboard // Dashboard
r.Group("/dashboards", func() { r.Group("/dashboards", func() {
r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard) r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard) r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
r.Get("/file/:file", GetDashboardFromJsonFile) r.Get("/file/:file", GetDashboardFromJsonFile)
r.Get("/home", wrap(GetHomeDashboard)) r.Get("/home", wrap(GetHomeDashboard))
r.Get("/tags", GetDashboardTags) r.Get("/tags", GetDashboardTags)

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
@ -109,7 +110,7 @@ func DeleteDashboard(c *middleware.Context) {
c.JSON(200, resp) c.JSON(200, resp)
} }
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) { func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if !c.IsSignedIn { if !c.IsSignedIn {
@ -122,35 +123,43 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) {
if dash.Id == 0 { if dash.Id == 0 {
limitReached, err := middleware.QuotaReached(c, "dashboard") limitReached, err := middleware.QuotaReached(c, "dashboard")
if err != nil { if err != nil {
c.JsonApiErr(500, "failed to get quota", err) return ApiError(500, "failed to get quota", err)
return
} }
if limitReached { if limitReached {
c.JsonApiErr(403, "Quota reached", nil) return ApiError(403, "Quota reached", nil)
return }
}
if !cmd.Overwrite {
if autoUpdate, exists := dash.Data.CheckGet("autoUpdate"); exists {
message := "Dashboard marked as auto updated."
if pluginId, err := autoUpdate.Get("pluginId").String(); err == nil {
if pluginDef, ok := plugins.Plugins[pluginId]; ok {
message = "Dashboard updated automatically when plugin " + pluginDef.Name + " is updated."
}
}
return Json(412, util.DynMap{"status": "auto-update-dashboard", "message": message})
} }
} }
err := bus.Dispatch(&cmd) err := bus.Dispatch(&cmd)
if err != nil { if err != nil {
if err == m.ErrDashboardWithSameNameExists { if err == m.ErrDashboardWithSameNameExists {
c.JSON(412, util.DynMap{"status": "name-exists", "message": err.Error()}) return Json(412, util.DynMap{"status": "name-exists", "message": err.Error()})
return
} }
if err == m.ErrDashboardVersionMismatch { if err == m.ErrDashboardVersionMismatch {
c.JSON(412, util.DynMap{"status": "version-mismatch", "message": err.Error()}) return Json(412, util.DynMap{"status": "version-mismatch", "message": err.Error()})
return
} }
if err == m.ErrDashboardNotFound { if err == m.ErrDashboardNotFound {
c.JSON(404, util.DynMap{"status": "not-found", "message": err.Error()}) return Json(404, util.DynMap{"status": "not-found", "message": err.Error()})
return
} }
c.JsonApiErr(500, "Failed to save dashboard", err) return ApiError(500, "Failed to save dashboard", err)
return
} }
c.TimeRequest(metrics.M_Api_Dashboard_Save) c.TimeRequest(metrics.M_Api_Dashboard_Save)
c.JSON(200, util.DynMap{"status": "success", "slug": cmd.Result.Slug, "version": cmd.Result.Version}) return Json(200, util.DynMap{"status": "success", "slug": cmd.Result.Slug, "version": cmd.Result.Version})
} }
func canEditDashboard(role m.RoleType) bool { func canEditDashboard(role m.RoleType) bool {

View File

@ -18,7 +18,7 @@ func populateDashboardsById(dashboardByIds []int64) ([]m.PlaylistDashboardDto, e
return result, err return result, err
} }
for _, item := range *dashboardQuery.Result { for _, item := range dashboardQuery.Result {
result = append(result, m.PlaylistDashboardDto{ result = append(result, m.PlaylistDashboardDto{
Id: item.Id, Id: item.Id,
Slug: item.Slug, Slug: item.Slug,

View File

@ -26,11 +26,12 @@ var (
// Dashboard model // Dashboard model
type Dashboard struct { type Dashboard struct {
Id int64 Id int64
Slug string Slug string
OrgId int64 OrgId int64
GnetId int64 GnetId int64
Version int Version int
PluginId string
Created time.Time Created time.Time
Updated time.Time Updated time.Time
@ -151,7 +152,13 @@ type GetDashboardTagsQuery struct {
type GetDashboardsQuery struct { type GetDashboardsQuery struct {
DashboardIds []int64 DashboardIds []int64
Result *[]Dashboard Result []*Dashboard
}
type GetDashboardsByPluginIdQuery struct {
OrgId int64
PluginId string
Result []*Dashboard
} }
type GetDashboardSlugByIdQuery struct { type GetDashboardSlugByIdQuery struct {

View File

@ -18,6 +18,7 @@ type PluginDashboardInfoDTO struct {
Revision int64 `json:"revision"` Revision int64 `json:"revision"`
Description string `json:"description"` Description string `json:"description"`
Path string `json:"path"` Path string `json:"path"`
Removed bool
} }
func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDTO, error) { func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDTO, error) {
@ -29,14 +30,40 @@ func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDT
result := make([]*PluginDashboardInfoDTO, 0) result := make([]*PluginDashboardInfoDTO, 0)
// load current dashboards
query := m.GetDashboardsByPluginIdQuery{OrgId: orgId, PluginId: pluginId}
if err := bus.Dispatch(&query); err != nil {
return nil, err
}
for _, include := range plugin.Includes { for _, include := range plugin.Includes {
if include.Type == PluginTypeDashboard { if include.Type != PluginTypeDashboard {
if dashInfo, err := getDashboardImportStatus(orgId, plugin, include.Path); err != nil { continue
return nil, err }
} else {
result = append(result, dashInfo) res := &PluginDashboardInfoDTO{}
var dashboard *m.Dashboard
var err error
if dashboard, err = loadPluginDashboard(plugin.Id, include.Path); err != nil {
return nil, err
}
res.Path = include.Path
res.PluginId = plugin.Id
res.Title = dashboard.Title
res.Revision = dashboard.Data.Get("revision").MustInt64(1)
// find existing dashboard
for _, existingDash := range query.Result {
if existingDash.Slug == dashboard.Slug {
res.Imported = true
res.ImportedUri = "db/" + existingDash.Slug
res.ImportedRevision = existingDash.Data.Get("revision").MustInt64(1)
} }
} }
result = append(result, res)
} }
return result, nil return result, nil

View File

@ -19,6 +19,7 @@ func init() {
bus.AddHandler("sql", SearchDashboards) bus.AddHandler("sql", SearchDashboards)
bus.AddHandler("sql", GetDashboardTags) bus.AddHandler("sql", GetDashboardTags)
bus.AddHandler("sql", GetDashboardSlugById) bus.AddHandler("sql", GetDashboardSlugById)
bus.AddHandler("sql", GetDashboardsByPluginId)
} }
func SaveDashboard(cmd *m.SaveDashboardCommand) error { func SaveDashboard(cmd *m.SaveDashboardCommand) error {
@ -245,10 +246,23 @@ func GetDashboards(query *m.GetDashboardsQuery) error {
return m.ErrCommandValidationFailed return m.ErrCommandValidationFailed
} }
var dashboards = make([]m.Dashboard, 0) var dashboards = make([]*m.Dashboard, 0)
err := x.In("id", query.DashboardIds).Find(&dashboards) err := x.In("id", query.DashboardIds).Find(&dashboards)
query.Result = &dashboards query.Result = dashboards
if err != nil {
return err
}
return nil
}
func GetDashboardsByPluginId(query *m.GetDashboardsByPluginIdQuery) error {
var dashboards = make([]*m.Dashboard, 0)
err := x.Where("org_id=? AND plugin_id=?", query.OrgId, query.PluginId).Find(&dashboards)
query.Result = dashboards
if err != nil { if err != nil {
return err return err

View File

@ -111,4 +111,13 @@ func addDashboardMigration(mg *Migrator) {
mg.AddMigration("Add index for gnetId in dashboard", NewAddIndexMigration(dashboardV2, &Index{ mg.AddMigration("Add index for gnetId in dashboard", NewAddIndexMigration(dashboardV2, &Index{
Cols: []string{"gnet_id"}, Type: IndexType, Cols: []string{"gnet_id"}, Type: IndexType,
})) }))
// add column to store plugin_id
mg.AddMigration("Add column plugin_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 255,
}))
mg.AddMigration("Add index for plugin_id in dashboard", NewAddIndexMigration(dashboardV2, &Index{
Cols: []string{"org_id", "plugin_id"}, Type: IndexType,
}))
} }

View File

@ -28,10 +28,6 @@ export class AlertSrv {
}, this.$rootScope); }, this.$rootScope);
appEvents.on('confirm-modal', this.showConfirmModal.bind(this)); appEvents.on('confirm-modal', this.showConfirmModal.bind(this));
this.$rootScope.onAppEvent('confirm-modal', (e, data) => {
this.showConfirmModal(data);
}, this.$rootScope);
} }
set(title, text, severity, timeout) { set(title, text, severity, timeout) {

View File

@ -22,6 +22,7 @@ function (angular, $, _, moment) {
this.id = data.id || null; this.id = data.id || null;
this.title = data.title || 'No Title'; this.title = data.title || 'No Title';
this.autoUpdate = data.autoUpdate;
this.description = data.description; this.description = data.description;
this.tags = data.tags || []; this.tags = data.tags || [];
this.style = data.style || "dark"; this.style = data.style || "dark";

View File

@ -134,6 +134,21 @@ export class DashNavCtrl {
} }
}); });
} }
if (err.data && err.data.status === "auto-update-dashboard") {
err.isHandled = true;
$scope.appEvent('confirm-modal', {
title: 'Auto Update Dashboard',
text: err.data.message,
text2: 'Use Save As... to create copy or ignore this warning.',
yesText: "Save & Overwrite",
icon: "fa-warning",
onConfirm: function() {
$scope.saveDashboard({overwrite: true});
}
});
}
}; };
$scope.deleteDashboard = function() { $scope.deleteDashboard = function() {

View File

@ -12,6 +12,8 @@ function (angular) {
$scope.clone.id = null; $scope.clone.id = null;
$scope.clone.editable = true; $scope.clone.editable = true;
$scope.clone.title = $scope.clone.title + " Copy"; $scope.clone.title = $scope.clone.title + " Copy";
// remove auto update
delete $scope.clone.autoUpdate;
}; };
function saveDashboard(options) { function saveDashboard(options) {
@ -37,8 +39,9 @@ function (angular) {
err.isHandled = true; err.isHandled = true;
$scope.appEvent('confirm-modal', { $scope.appEvent('confirm-modal', {
title: 'Another dashboard with the same name exists', title: 'Conflict',
text: "Would you still like to save this dashboard?", text: 'Dashboard with the same name exists.',
text2: 'Would you still like to save this dashboard?',
yesText: "Save & Overwrite", yesText: "Save & Overwrite",
icon: "fa-warning", icon: "fa-warning",
onConfirm: function() { onConfirm: function() {