mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(apps): progress on app dashboard imports
This commit is contained in:
parent
b62f1f00cd
commit
d44325affd
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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";
|
||||||
|
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user