Commit 77c046aa by sanchitraizada Committed by Ben Tranter

Implement review feedback

parent a927b893
...@@ -224,11 +224,11 @@ func (hs *HttpServer) registerRoutes() { ...@@ -224,11 +224,11 @@ func (hs *HttpServer) registerRoutes() {
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.Get("/db/:dashboardId/versions", GetDashboardVersions) r.Get("/db/:dashboardId/versions", wrap(GetDashboardVersions))
r.Get("/db/:dashboardId/versions/:id", GetDashboardVersion) r.Get("/db/:dashboardId/versions/:id", wrap(GetDashboardVersion))
r.Get("/db/:dashboardId/compare/:versions", CompareDashboardVersions) r.Get("/db/:dashboardId/compare/:versions", wrap(CompareDashboardVersions))
r.Get("/db/:dashboardId/compare/:versions/html", CompareDashboardVersionsJSON) r.Get("/db/:dashboardId/compare/:versions/html", wrap(CompareDashboardVersionsJSON))
r.Get("/db/:dashboardId/compare/:versions/basic", CompareDashboardVersionsBasic) r.Get("/db/:dashboardId/compare/:versions/basic", wrap(CompareDashboardVersionsBasic))
r.Post("/db/:dashboardId/restore", reqEditorRole, bind(m.RestoreDashboardVersionCommand{}), wrap(RestoreDashboardVersion)) r.Post("/db/:dashboardId/restore", reqEditorRole, bind(m.RestoreDashboardVersionCommand{}), wrap(RestoreDashboardVersion))
r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard)) r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
......
...@@ -258,16 +258,9 @@ func GetDashboardFromJsonFile(c *middleware.Context) { ...@@ -258,16 +258,9 @@ func GetDashboardFromJsonFile(c *middleware.Context) {
c.JSON(200, &dash) c.JSON(200, &dash)
} }
// GetDashboardVersions returns all dashboardversions as JSON // GetDashboardVersions returns all dashboard versions as JSON
func GetDashboardVersions(c *middleware.Context) { func GetDashboardVersions(c *middleware.Context) Response {
dashboardIdStr := c.Params(":dashboardId") dashboardId := c.ParamsInt64(":dashboardId")
dashboardId, err := strconv.Atoi(dashboardIdStr)
if err != nil {
c.JsonApiErr(400, err.Error(), err)
return
}
// TODO(ben) the orderBy arg should be split into snake_case?
orderBy := c.Query("orderBy") orderBy := c.Query("orderBy")
limit := c.QueryInt("limit") limit := c.QueryInt("limit")
start := c.QueryInt("start") start := c.QueryInt("start")
...@@ -279,62 +272,54 @@ func GetDashboardVersions(c *middleware.Context) { ...@@ -279,62 +272,54 @@ func GetDashboardVersions(c *middleware.Context) {
} }
query := m.GetDashboardVersionsCommand{ query := m.GetDashboardVersionsCommand{
DashboardId: int64(dashboardId), DashboardId: dashboardId,
OrderBy: orderBy, OrderBy: orderBy,
Limit: limit, Limit: limit,
Start: start, Start: start,
} }
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(404, fmt.Sprintf("No versions found for dashboardId %d", dashboardId), err) return ApiError(404, fmt.Sprintf("No versions found for dashboardId %d", dashboardId), err)
return }
}
// // TODO(ben) use inner join with DTO
dashboardVersions := make([]*m.DashboardVersionDTO, len(query.Result)) // dashboardVersions := make([]*m.DashboardVersionDTO, len(query.Result))
for i, dashboardVersion := range query.Result { // for i, dashboardVersion := range query.Result {
creator := "Anonymous" // creator := "Anonymous"
if dashboardVersion.CreatedBy > 0 { // if dashboardVersion.CreatedBy > 0 {
creator = getUserLogin(dashboardVersion.CreatedBy) // creator = getUserLogin(dashboardVersion.CreatedBy)
} // }
dashboardVersions[i] = &m.DashboardVersionDTO{ // dashboardVersions[i] = &m.DashboardVersionDTO{
Id: dashboardVersion.Id, // Id: dashboardVersion.Id,
DashboardId: dashboardVersion.DashboardId, // DashboardId: dashboardVersion.DashboardId,
ParentVersion: dashboardVersion.ParentVersion, // ParentVersion: dashboardVersion.ParentVersion,
RestoredFrom: dashboardVersion.RestoredFrom, // RestoredFrom: dashboardVersion.RestoredFrom,
Version: dashboardVersion.Version, // Version: dashboardVersion.Version,
Created: dashboardVersion.Created, // Created: dashboardVersion.Created,
CreatedBy: creator, // CreatedBy: creator,
Message: dashboardVersion.Message, // Message: dashboardVersion.Message,
} // }
} // }
c.JSON(200, dashboardVersions) return Json(200, query.Result)
} }
// GetDashboardVersion returns the dashboard version with the given ID. // GetDashboardVersion returns the dashboard version with the given ID.
func GetDashboardVersion(c *middleware.Context) { func GetDashboardVersion(c *middleware.Context) Response {
dashboardIdStr := c.Params(":dashboardId") dashboardId := c.ParamsInt64(":dashboardId")
dashboardId, err := strconv.Atoi(dashboardIdStr) version := c.ParamsInt(":id")
if err != nil {
c.JsonApiErr(400, err.Error(), err)
return
}
versionStr := c.Params(":id")
version, err := strconv.Atoi(versionStr)
if err != nil {
c.JsonApiErr(400, err.Error(), err)
return
}
query := m.GetDashboardVersionCommand{ query := m.GetDashboardVersionCommand{
DashboardId: int64(dashboardId), DashboardId: dashboardId,
Version: version, Version: version,
} }
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(
return 500,
fmt.Sprintf("Dashboard version %d not found for dashboardId %d", version, dashboardId),
err,
)
} }
creator := "Anonymous" creator := "Anonymous"
...@@ -347,10 +332,10 @@ func GetDashboardVersion(c *middleware.Context) { ...@@ -347,10 +332,10 @@ func GetDashboardVersion(c *middleware.Context) {
CreatedBy: creator, CreatedBy: creator,
} }
c.JSON(200, dashVersionMeta) return Json(200, dashVersionMeta)
} }
func dashCmd(c *middleware.Context) (m.CompareDashboardVersionsCommand, error) { func createCompareDashboardVersionCommand(c *middleware.Context) (m.CompareDashboardVersionsCommand, error) {
cmd := m.CompareDashboardVersionsCommand{} cmd := m.CompareDashboardVersionsCommand{}
dashboardIdStr := c.Params(":dashboardId") dashboardIdStr := c.Params(":dashboardId")
...@@ -381,106 +366,82 @@ func dashCmd(c *middleware.Context) (m.CompareDashboardVersionsCommand, error) { ...@@ -381,106 +366,82 @@ func dashCmd(c *middleware.Context) (m.CompareDashboardVersionsCommand, error) {
} }
// CompareDashboardVersions compares dashboards the way the GitHub API does. // CompareDashboardVersions compares dashboards the way the GitHub API does.
func CompareDashboardVersions(c *middleware.Context) { func CompareDashboardVersions(c *middleware.Context) Response {
cmd, err := dashCmd(c) cmd, err := createCompareDashboardVersionCommand(c)
if err != nil { if err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
} }
cmd.DiffType = m.DiffDelta cmd.DiffType = m.DiffDelta
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "cannot-compute-diff", err) return ApiError(500, "Unable to compute diff", err)
return
} }
// here the output is already JSON, so we need to unmarshal it into a // here the output is already JSON, so we need to unmarshal it into a
// map before marshaling the entire response // map before marshaling the entire response
deltaMap := make(map[string]interface{}) deltaMap := make(map[string]interface{})
err = json.Unmarshal(cmd.Delta, &deltaMap) err = json.Unmarshal(cmd.Delta, &deltaMap)
if err != nil { if err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
return
} }
c.JSON(200, simplejson.NewFromAny(util.DynMap{ return Json(200, util.DynMap{
"meta": util.DynMap{ "meta": util.DynMap{
"original": cmd.Original, "original": cmd.Original,
"new": cmd.New, "new": cmd.New,
}, },
"delta": deltaMap, "delta": deltaMap,
})) })
} }
// CompareDashboardVersionsJSON compares dashboards the way the GitHub API does, // CompareDashboardVersionsJSON compares dashboards the way the GitHub API does,
// returning a human-readable JSON diff. // returning a human-readable JSON diff.
func CompareDashboardVersionsJSON(c *middleware.Context) { func CompareDashboardVersionsJSON(c *middleware.Context) Response {
cmd, err := dashCmd(c) cmd, err := createCompareDashboardVersionCommand(c)
if err != nil { if err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
} }
cmd.DiffType = m.DiffJSON cmd.DiffType = m.DiffJSON
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
return
} }
c.Header().Set("Content-Type", "text/html") return Respond(200, cmd.Delta).Header("Content-Type", "text/html")
c.WriteHeader(200)
c.Write(cmd.Delta)
} }
// CompareDashboardVersionsBasic compares dashboards the way the GitHub API does, // CompareDashboardVersionsBasic compares dashboards the way the GitHub API does,
// returning a human-readable diff. // returning a human-readable diff.
func CompareDashboardVersionsBasic(c *middleware.Context) { func CompareDashboardVersionsBasic(c *middleware.Context) Response {
cmd, err := dashCmd(c) cmd, err := createCompareDashboardVersionCommand(c)
if err != nil { if err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
} }
cmd.DiffType = m.DiffBasic cmd.DiffType = m.DiffBasic
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, err.Error(), err) return ApiError(500, err.Error(), err)
return
} }
c.Header().Set("Content-Type", "text/html") return Respond(200, cmd.Delta).Header("Content-Type", "text/html")
c.WriteHeader(200)
c.Write(cmd.Delta)
} }
// RestoreDashboardVersion restores a dashboard to the given version. // RestoreDashboardVersion restores a dashboard to the given version.
func RestoreDashboardVersion(c *middleware.Context, cmd m.RestoreDashboardVersionCommand) Response { func RestoreDashboardVersion(c *middleware.Context, cmd m.RestoreDashboardVersionCommand) Response {
if !c.IsSignedIn { if !c.IsSignedIn {
return Json(401, util.DynMap{ return ApiError(401, "Must be signed in to restore a version", nil)
"message": "Must be signed in to restore a version",
"status": "unauthorized",
})
} }
cmd.UserId = c.UserId cmd.UserId = c.UserId
dashboardIdStr := c.Params(":dashboardId") cmd.DashboardId = c.ParamsInt64(":dashboardId")
dashboardId, err := strconv.Atoi(dashboardIdStr)
if err != nil {
return Json(404, util.DynMap{
"message": err.Error(),
"status": "cannot-find-dashboard",
})
}
cmd.DashboardId = int64(dashboardId)
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
return Json(500, util.DynMap{ return ApiError(500, "Cannot restore version", err)
"message": err.Error(),
"status": "cannot-restore-version",
})
} }
isStarred, err := isDashboardStarredByUser(c, cmd.Result.Id) isStarred, err := isDashboardStarredByUser(c, cmd.Result.Id)
if err != nil { if err != nil {
return Json(500, util.DynMap{ return ApiError(500, "Error checking if dashboard is starred by user", err)
"message": "Error while checking if dashboard was starred by user",
"status": err.Error(),
})
} }
// Finding creator and last updater of the dashboard // Finding creator and last updater of the dashboard
......
...@@ -80,7 +80,7 @@ type GetDashboardVersionsCommand struct { ...@@ -80,7 +80,7 @@ type GetDashboardVersionsCommand struct {
Limit int `json:"limit"` Limit int `json:"limit"`
Start int `json:"start"` Start int `json:"start"`
Result []*DashboardVersion Result []*DashboardVersionDTO
} }
// RestoreDashboardVersionCommand creates a new dashboard version. // RestoreDashboardVersionCommand creates a new dashboard version.
......
...@@ -91,15 +91,25 @@ func GetDashboardVersion(query *m.GetDashboardVersionCommand) error { ...@@ -91,15 +91,25 @@ func GetDashboardVersion(query *m.GetDashboardVersionCommand) error {
// GetDashboardVersions gets all dashboard versions for the given dashboard ID. // GetDashboardVersions gets all dashboard versions for the given dashboard ID.
func GetDashboardVersions(query *m.GetDashboardVersionsCommand) error { func GetDashboardVersions(query *m.GetDashboardVersionsCommand) error {
order := "" if query.OrderBy == "" {
query.OrderBy = "version"
// the query builder in xorm doesn't provide a way to set
// a default order, so we perform this check
if query.OrderBy != "" {
order = " desc"
} }
err := x.In("dashboard_id", query.DashboardId). query.OrderBy += " desc"
OrderBy(query.OrderBy+order).
err := x.Table("dashboard_version").
Select(`dashboard_version.id,
dashboard_version.dashboard_id,
dashboard_version.parent_version,
dashboard_version.restored_from,
dashboard_version.version,
dashboard_version.created,
dashboard_version.created_by as created_by_id,
dashboard_version.message,
dashboard_version.data,
"user".login as created_by`).
Join("LEFT", "user", `dashboard_version.created_by = "user".id`).
Where("dashboard_version.dashboard_id=?", query.DashboardId).
OrderBy("dashboard_version."+query.OrderBy).
Limit(query.Limit, query.Start). Limit(query.Limit, query.Start).
Find(&query.Result) Find(&query.Result)
if err != nil { if err != nil {
......
...@@ -8,7 +8,7 @@ function ($, coreModule) { ...@@ -8,7 +8,7 @@ function ($, coreModule) {
var editViewMap = { var editViewMap = {
'settings': { src: 'public/app/features/dashboard/partials/settings.html'}, 'settings': { src: 'public/app/features/dashboard/partials/settings.html'},
'annotations': { src: 'public/app/features/annotations/partials/editor.html'}, 'annotations': { src: 'public/app/features/annotations/partials/editor.html'},
'audit': { src: 'public/app/features/dashboard/audit/partials/audit.html'}, 'history': { src: 'public/app/features/dashboard/history/partials/history.html'},
'templating': { src: 'public/app/features/templating/partials/editor.html'}, 'templating': { src: 'public/app/features/templating/partials/editor.html'},
'import': { src: '<dash-import></dash-import>' } 'import': { src: '<dash-import></dash-import>' }
}; };
......
...@@ -6,6 +6,7 @@ import coreModule from '../core_module'; ...@@ -6,6 +6,7 @@ import coreModule from '../core_module';
export class DeltaCtrl { export class DeltaCtrl {
observer: any; observer: any;
/** @ngInject */
constructor(private $rootScope) { constructor(private $rootScope) {
const waitForCompile = function(mutations) { const waitForCompile = function(mutations) {
if (mutations.length === 1) { if (mutations.length === 1) {
...@@ -70,7 +71,7 @@ export function linkJson() { ...@@ -70,7 +71,7 @@ export function linkJson() {
link: '@lineLink', link: '@lineLink',
switchView: '&', switchView: '&',
}, },
templateUrl: 'public/app/features/dashboard/audit/partials/link-json.html', templateUrl: 'public/app/features/dashboard/history/partials/link-json.html',
}; };
} }
coreModule.directive('diffLinkJson', linkJson); coreModule.directive('diffLinkJson', linkJson);
...@@ -2,7 +2,6 @@ define([ ...@@ -2,7 +2,6 @@ define([
'./panellinks/module', './panellinks/module',
'./dashlinks/module', './dashlinks/module',
'./annotations/all', './annotations/all',
'./annotations/annotations_srv',
'./templating/all', './templating/all',
'./dashboard/all', './dashboard/all',
'./playlist/all', './playlist/all',
......
define([ define([
'./dashboard_ctrl', './dashboard_ctrl',
'./alerting_srv', './alerting_srv',
'./audit/audit_srv', './history/history',
'./dashboardLoaderSrv', './dashboardLoaderSrv',
'./dashnav/dashnav', './dashnav/dashnav',
'./submenu/submenu', './submenu/submenu',
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('settings');">Settings</a></li> <li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('settings');">Settings</a></li>
<li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('annotations');">Annotations</a></li> <li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('annotations');">Annotations</a></li>
<li ng-if="dashboardMeta.canEdit && dashboard.version > 0 && !dashboardMeta.isHome"><a class="pointer" ng-click="openEditView('audit');">Changelog</a></li> <li ng-if="dashboardMeta.canEdit && dashboard.version > 0 && !dashboardMeta.isHome"><a class="pointer" ng-click="openEditView('history');">Changelog</a></li>
<li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('templating');">Templating</a></li> <li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="openEditView('templating');">Templating</a></li>
<li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="viewJson();">View JSON</a></li> <li ng-if="dashboardMeta.canEdit"><a class="pointer" ng-click="viewJson();">View JSON</a></li>
<li ng-if="contextSrv.isEditor && !dashboard.editable"><a class="pointer" ng-click="makeEditable();">Make Editable</a></li> <li ng-if="contextSrv.isEditor && !dashboard.editable"><a class="pointer" ng-click="makeEditable();">Make Editable</a></li>
......
<div ng-controller="AuditLogCtrl"> <div>
<div class="tabbed-view-header"> <div class="tabbed-view-header">
<h2 class="tabbed-view-title"> <h2 class="tabbed-view-title">
Changelog Changelog
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
</li> </li>
<li class="gf-tabs-item" ng-show="ctrl.mode === 'compare'"> <li class="gf-tabs-item" ng-show="ctrl.mode === 'compare'">
<span ng-if="ctrl.isOriginalCurrent()" class="active gf-tabs-link"> <span ng-if="ctrl.isOriginalCurrent()" class="active gf-tabs-link">
Version {{ctrl.selected[0]}} <i class="fa fa-arrows-h" /> Current Version {{ctrl.selected[0]}} <i class="fa fa-arrows-h"></i> Current
</span> </span>
<span ng-if="!ctrl.isOriginalCurrent()" class="active gf-tabs-link"> <span ng-if="!ctrl.isOriginalCurrent()" class="active gf-tabs-link">
Version {{ctrl.selected[0]}} <i class="fa fa-arrows-h" /> Version {{ctrl.selected[1]}} Version {{ctrl.selected[0]}} <i class="fa fa-arrows-h"></i> Version {{ctrl.selected[1]}}
</span> </span>
</li> </li>
</ul> </ul>
...@@ -30,11 +30,11 @@ ...@@ -30,11 +30,11 @@
<div ng-if="ctrl.mode === 'list'"> <div ng-if="ctrl.mode === 'list'">
<div ng-if="ctrl.loading"> <div ng-if="ctrl.loading">
<i class="fa fa-spinner fa-spin"></i> <i class="fa fa-spinner fa-spin"></i>
<em>Fetching audit log&hellip;</em> <em>Fetching history list&hellip;</em>
</div> </div>
<div ng-if="!ctrl.loading"> <div ng-if="!ctrl.loading">
<div class="audit-table gf-form"> <div class="history-table gf-form">
<div class="gf-form-group"> <div class="gf-form-group">
<table class="filter-table"> <table class="filter-table">
<thead> <thead>
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
</div> </div>
</div> </div>
<div class="audit-log" ng-if="ctrl.mode === 'compare'"> <div class="history-list" ng-if="ctrl.mode === 'compare'">
<div class="page-container"> <div class="page-container">
<div class="page-body"> <div class="page-body">
<aside class="page-sidebar"> <aside class="page-sidebar">
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
</a> </a>
<h4> <h4>
Comparing Version {{ctrl.selected[0]}} Comparing Version {{ctrl.selected[0]}}
<i class="fa fa-arrows-h" /> <i class="fa fa-arrows-h"></i>
Version {{ctrl.selected[1]}} Version {{ctrl.selected[1]}}
<cite class="muted" ng-if="ctrl.isOriginalCurrent()">(Current)</cite> <cite class="muted" ng-if="ctrl.isOriginalCurrent()">(Current)</cite>
</h4> </h4>
...@@ -148,8 +148,8 @@ ...@@ -148,8 +148,8 @@
</p> </p>
</section> </section>
<div id="delta" diff-delta> <div id="delta" diff-delta>
<div class="delta-basic" ng-show="ctrl.diff === 'basic'" compile="ctrl.delta.basic" /> <div class="delta-basic" ng-show="ctrl.diff === 'basic'" compile="ctrl.delta.basic"></div>
<div class="delta-html" ng-show="ctrl.diff === 'html'" compile="ctrl.delta.html" /> <div class="delta-html" ng-show="ctrl.diff === 'html'" compile="ctrl.delta.html"></div>
</div> </div>
</div> </div>
</div> </div>
......
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import './history_srv';
import _ from 'lodash'; import _ from 'lodash';
import angular from 'angular'; import angular from 'angular';
import moment from 'moment'; import moment from 'moment';
import coreModule from 'app/core/core_module';
import {DashboardModel} from '../model'; import {DashboardModel} from '../model';
import {AuditLogOpts, RevisionsModel} from './models'; import {HistoryListOpts, RevisionsModel} from './models';
export class AuditLogCtrl { export class HistoryListCtrl {
appending: boolean; appending: boolean;
dashboard: DashboardModel; dashboard: DashboardModel;
delta: { basic: string; html: string; }; delta: { basic: string; html: string; };
...@@ -29,11 +29,10 @@ export class AuditLogCtrl { ...@@ -29,11 +29,10 @@ export class AuditLogCtrl {
private $window, private $window,
private $q, private $q,
private contextSrv, private contextSrv,
private auditSrv) { private historySrv) {
$scope.ctrl = this; $scope.ctrl = this;
this.appending = false; this.appending = false;
this.dashboard = $scope.dashboard;
this.diff = 'basic'; this.diff = 'basic';
this.limit = 10; this.limit = 10;
this.loading = false; this.loading = false;
...@@ -106,7 +105,7 @@ export class AuditLogCtrl { ...@@ -106,7 +105,7 @@ export class AuditLogCtrl {
this.loading = false; this.loading = false;
return this.$q.when(this.delta[this.diff]); return this.$q.when(this.delta[this.diff]);
} else { } else {
return this.auditSrv.compareVersions(this.dashboard, compare, diff).then(response => { return this.historySrv.compareVersions(this.dashboard, compare, diff).then(response => {
this.delta[this.diff] = response; this.delta[this.diff] = response;
}).catch(err => { }).catch(err => {
this.mode = 'list'; this.mode = 'list';
...@@ -118,12 +117,12 @@ export class AuditLogCtrl { ...@@ -118,12 +117,12 @@ export class AuditLogCtrl {
getLog(append = false) { getLog(append = false) {
this.loading = !append; this.loading = !append;
this.appending = append; this.appending = append;
const options: AuditLogOpts = { const options: HistoryListOpts = {
limit: this.limit, limit: this.limit,
start: this.start, start: this.start,
orderBy: this.orderBy, orderBy: this.orderBy,
}; };
return this.auditSrv.getAuditLog(this.dashboard, options).then(revisions => { return this.historySrv.getHistoryList(this.dashboard, options).then(revisions => {
const formattedRevisions = _.flow( const formattedRevisions = _.flow(
_.partialRight(_.map, rev => _.extend({}, rev, { _.partialRight(_.map, rev => _.extend({}, rev, {
checked: false, checked: false,
...@@ -149,7 +148,7 @@ export class AuditLogCtrl { ...@@ -149,7 +148,7 @@ export class AuditLogCtrl {
this.revisions = append ? this.revisions.concat(formattedRevisions) : formattedRevisions; this.revisions = append ? this.revisions.concat(formattedRevisions) : formattedRevisions;
}).catch(err => { }).catch(err => {
this.$rootScope.appEvent('alert-error', ['There was an error fetching the audit log', (err.message || err)]); this.$rootScope.appEvent('alert-error', ['There was an error fetching the history list', (err.message || err)]);
}).finally(() => { }).finally(() => {
this.loading = false; this.loading = false;
this.appending = false; this.appending = false;
...@@ -209,7 +208,7 @@ export class AuditLogCtrl { ...@@ -209,7 +208,7 @@ export class AuditLogCtrl {
restoreConfirm(version: number) { restoreConfirm(version: number) {
this.loading = true; this.loading = true;
return this.auditSrv.restoreDashboard(this.dashboard, version).then(response => { return this.historySrv.restoreDashboard(this.dashboard, version).then(response => {
this.revisions.unshift({ this.revisions.unshift({
id: this.revisions[0].id + 1, id: this.revisions[0].id + 1,
checked: false, checked: false,
...@@ -232,4 +231,17 @@ export class AuditLogCtrl { ...@@ -232,4 +231,17 @@ export class AuditLogCtrl {
} }
} }
coreModule.controller('AuditLogCtrl', AuditLogCtrl); export function dashboardHistoryDirective() {
return {
restrict: 'E',
templateUrl: 'public/app/features/dashboard/history/history.html',
controller: HistoryListCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
dashboard: "="
}
};
}
angular.module('grafana.directives').directive('gfDashboardHistory', dashboardHistoryDirective);
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import './audit_ctrl';
import _ from 'lodash'; import _ from 'lodash';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import {DashboardModel} from '../model'; import {DashboardModel} from '../model';
import {AuditLogOpts} from './models'; import {HistoryListOpts} from './models';
export class AuditSrv { export class HistorySrv {
/** @ngInject */ /** @ngInject */
constructor(private backendSrv, private $q) {} constructor(private backendSrv, private $q) {}
getAuditLog(dashboard: DashboardModel, options: AuditLogOpts) { getHistoryList(dashboard: DashboardModel, options: HistoryListOpts) {
const id = dashboard && dashboard.id ? dashboard.id : void 0; const id = dashboard && dashboard.id ? dashboard.id : void 0;
return id ? this.backendSrv.get(`api/dashboards/db/${id}/versions`, options) : this.$q.when([]); return id ? this.backendSrv.get(`api/dashboards/db/${id}/versions`, options) : this.$q.when([]);
} }
...@@ -29,4 +27,4 @@ export class AuditSrv { ...@@ -29,4 +27,4 @@ export class AuditSrv {
} }
} }
coreModule.service('auditSrv', AuditSrv); coreModule.service('historySrv', HistorySrv);
export interface AuditLogOpts { export interface HistoryListOpts {
limit: number; limit: number;
start: number; start: number;
orderBy: string; orderBy: string;
......
<gf-dashboard-history dashboard="dashboard"></gf-dashboard-history>
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import _ from 'lodash'; import _ from 'lodash';
import {AuditLogCtrl} from 'app/features/dashboard/audit/audit_ctrl'; import {HistoryListCtrl} from 'app/features/dashboard/history/history';
import { versions, compare, restore } from 'test/mocks/audit-mocks'; import { versions, compare, restore } from 'test/mocks/history-mocks';
import config from 'app/core/config'; import config from 'app/core/config';
describe('AuditLogCtrl', function() { describe('HistoryListCtrl', function() {
var RESTORE_ID = 4; var RESTORE_ID = 4;
var ctx: any = {}; var ctx: any = {};
...@@ -18,11 +18,11 @@ describe('AuditLogCtrl', function() { ...@@ -18,11 +18,11 @@ describe('AuditLogCtrl', function() {
ctx.scope = $rootScope.$new(); ctx.scope = $rootScope.$new();
})); }));
var auditSrv; var historySrv;
var $rootScope; var $rootScope;
beforeEach(function() { beforeEach(function() {
auditSrv = { historySrv = {
getAuditLog: sinon.stub(), getHistoryList: sinon.stub(),
compareVersions: sinon.stub(), compareVersions: sinon.stub(),
restoreDashboard: sinon.stub(), restoreDashboard: sinon.stub(),
}; };
...@@ -32,24 +32,24 @@ describe('AuditLogCtrl', function() { ...@@ -32,24 +32,24 @@ describe('AuditLogCtrl', function() {
}; };
}); });
describe('when the audit log component is loaded', function() { describe('when the history list component is loaded', function() {
var deferred; var deferred;
beforeEach(angularMocks.inject(($controller, $q) => { beforeEach(angularMocks.inject(($controller, $q) => {
deferred = $q.defer(); deferred = $q.defer();
auditSrv.getAuditLog.returns(deferred.promise); historySrv.getHistoryList.returns(deferred.promise);
ctx.ctrl = $controller(AuditLogCtrl, { ctx.ctrl = $controller(HistoryListCtrl, {
auditSrv, historySrv,
$rootScope, $rootScope,
$scope: ctx.scope, $scope: ctx.scope,
}); });
})); }));
it('should immediately attempt to fetch the audit log', function() { it('should immediately attempt to fetch the history list', function() {
expect(auditSrv.getAuditLog.calledOnce).to.be(true); expect(historySrv.getHistoryList.calledOnce).to.be(true);
}); });
describe('and the audit log is successfully fetched', function() { describe('and the history list is successfully fetched', function() {
beforeEach(function() { beforeEach(function() {
deferred.resolve(versionsResponse); deferred.resolve(versionsResponse);
ctx.ctrl.$scope.$apply(); ctx.ctrl.$scope.$apply();
...@@ -106,9 +106,9 @@ describe('AuditLogCtrl', function() { ...@@ -106,9 +106,9 @@ describe('AuditLogCtrl', function() {
}); });
}); });
describe('and fetching the audit log fails', function() { describe('and fetching the history list fails', function() {
beforeEach(function() { beforeEach(function() {
deferred.reject(new Error('AuditLogError')); deferred.reject(new Error('HistoryListError'));
ctx.ctrl.$scope.$apply(); ctx.ctrl.$scope.$apply();
}); });
...@@ -134,7 +134,7 @@ describe('AuditLogCtrl', function() { ...@@ -134,7 +134,7 @@ describe('AuditLogCtrl', function() {
}); });
}); });
describe('should update the audit log when the dashboard is saved', function() { describe('should update the history list when the dashboard is saved', function() {
beforeEach(function() { beforeEach(function() {
ctx.ctrl.dashboard = { version: 3 }; ctx.ctrl.dashboard = { version: 3 };
ctx.ctrl.resetFromSource = sinon.spy(); ctx.ctrl.resetFromSource = sinon.spy();
...@@ -163,10 +163,10 @@ describe('AuditLogCtrl', function() { ...@@ -163,10 +163,10 @@ describe('AuditLogCtrl', function() {
beforeEach(angularMocks.inject(($controller, $q) => { beforeEach(angularMocks.inject(($controller, $q) => {
deferred = $q.defer(); deferred = $q.defer();
auditSrv.getAuditLog.returns($q.when(versionsResponse)); historySrv.getHistoryList.returns($q.when(versionsResponse));
auditSrv.compareVersions.returns(deferred.promise); historySrv.compareVersions.returns(deferred.promise);
ctx.ctrl = $controller(AuditLogCtrl, { ctx.ctrl = $controller(HistoryListCtrl, {
auditSrv, historySrv,
$rootScope, $rootScope,
$scope: ctx.scope, $scope: ctx.scope,
}); });
...@@ -174,8 +174,8 @@ describe('AuditLogCtrl', function() { ...@@ -174,8 +174,8 @@ describe('AuditLogCtrl', function() {
ctx.ctrl.$scope.$apply(); ctx.ctrl.$scope.$apply();
})); }));
it('should have already fetched the audit log', function() { it('should have already fetched the history list', function() {
expect(auditSrv.getAuditLog.calledOnce).to.be(true); expect(historySrv.getHistoryList.calledOnce).to.be(true);
expect(ctx.ctrl.revisions.length).to.be.above(0); expect(ctx.ctrl.revisions.length).to.be.above(0);
}); });
...@@ -205,7 +205,7 @@ describe('AuditLogCtrl', function() { ...@@ -205,7 +205,7 @@ describe('AuditLogCtrl', function() {
}); });
it('should fetch the basic diff if two valid versions are selected', function() { it('should fetch the basic diff if two valid versions are selected', function() {
expect(auditSrv.compareVersions.calledOnce).to.be(true); expect(historySrv.compareVersions.calledOnce).to.be(true);
expect(ctx.ctrl.delta.basic).to.be('<div></div>'); expect(ctx.ctrl.delta.basic).to.be('<div></div>');
expect(ctx.ctrl.delta.html).to.be(''); expect(ctx.ctrl.delta.html).to.be('');
}); });
...@@ -229,7 +229,7 @@ describe('AuditLogCtrl', function() { ...@@ -229,7 +229,7 @@ describe('AuditLogCtrl', function() {
}); });
it('should fetch the json diff if two valid versions are selected', function() { it('should fetch the json diff if two valid versions are selected', function() {
expect(auditSrv.compareVersions.calledOnce).to.be(true); expect(historySrv.compareVersions.calledOnce).to.be(true);
expect(ctx.ctrl.delta.basic).to.be(''); expect(ctx.ctrl.delta.basic).to.be('');
expect(ctx.ctrl.delta.html).to.be('<pre><code></code></pre>'); expect(ctx.ctrl.delta.html).to.be('<pre><code></code></pre>');
}); });
...@@ -254,7 +254,7 @@ describe('AuditLogCtrl', function() { ...@@ -254,7 +254,7 @@ describe('AuditLogCtrl', function() {
}); });
it('should use the cached diffs instead of fetching', function() { it('should use the cached diffs instead of fetching', function() {
expect(auditSrv.compareVersions.calledOnce).to.be(false); expect(historySrv.compareVersions.calledOnce).to.be(false);
expect(ctx.ctrl.delta.basic).to.be('cached basic'); expect(ctx.ctrl.delta.basic).to.be('cached basic');
}); });
...@@ -272,10 +272,10 @@ describe('AuditLogCtrl', function() { ...@@ -272,10 +272,10 @@ describe('AuditLogCtrl', function() {
}); });
it('should fetch the diff if two valid versions are selected', function() { it('should fetch the diff if two valid versions are selected', function() {
expect(auditSrv.compareVersions.calledOnce).to.be(true); expect(historySrv.compareVersions.calledOnce).to.be(true);
}); });
it('should return to the audit log view', function() { it('should return to the history list view', function() {
expect(ctx.ctrl.mode).to.be('list'); expect(ctx.ctrl.mode).to.be('list');
}); });
...@@ -299,10 +299,10 @@ describe('AuditLogCtrl', function() { ...@@ -299,10 +299,10 @@ describe('AuditLogCtrl', function() {
beforeEach(angularMocks.inject(($controller, $q) => { beforeEach(angularMocks.inject(($controller, $q) => {
deferred = $q.defer(); deferred = $q.defer();
auditSrv.getAuditLog.returns($q.when(versionsResponse)); historySrv.getHistoryList.returns($q.when(versionsResponse));
auditSrv.restoreDashboard.returns(deferred.promise); historySrv.restoreDashboard.returns(deferred.promise);
ctx.ctrl = $controller(AuditLogCtrl, { ctx.ctrl = $controller(HistoryListCtrl, {
auditSrv, historySrv,
contextSrv: { user: { name: 'Carlos' }}, contextSrv: { user: { name: 'Carlos' }},
$rootScope, $rootScope,
$scope: ctx.scope, $scope: ctx.scope,
...@@ -339,7 +339,7 @@ describe('AuditLogCtrl', function() { ...@@ -339,7 +339,7 @@ describe('AuditLogCtrl', function() {
expect(ctx.ctrl.loading).to.be(false); expect(ctx.ctrl.loading).to.be(false);
}); });
it('should add an entry for the restored revision to the audit log', function() { it('should add an entry for the restored revision to the history list', function() {
expect(ctx.ctrl.revisions.length).to.be(5); expect(ctx.ctrl.revisions.length).to.be(5);
}); });
......
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import helpers from 'test/specs/helpers'; import helpers from 'test/specs/helpers';
import AuditSrv from '../audit/audit_srv'; import HistorySrv from '../history/history_srv';
import { versions, compare, restore } from 'test/mocks/audit-mocks'; import { versions, compare, restore } from 'test/mocks/history-mocks';
describe('auditSrv', function() { describe('historySrv', function() {
var ctx = new helpers.ServiceTestContext(); var ctx = new helpers.ServiceTestContext();
var versionsResponse = versions(); var versionsResponse = versions();
...@@ -23,11 +23,11 @@ describe('auditSrv', function() { ...@@ -23,11 +23,11 @@ describe('auditSrv', function() {
return [200, restoreResponse(parsedData.version)]; return [200, restoreResponse(parsedData.version)];
}); });
})); }));
beforeEach(ctx.createService('auditSrv')); beforeEach(ctx.createService('historySrv'));
describe('getAuditLog', function() { describe('getHistoryList', function() {
it('should return a versions array for the given dashboard id', function(done) { it('should return a versions array for the given dashboard id', function(done) {
ctx.service.getAuditLog({ id: 1 }).then(function(versions) { ctx.service.getHistoryList({ id: 1 }).then(function(versions) {
expect(versions).to.eql(versionsResponse); expect(versions).to.eql(versionsResponse);
done(); done();
}); });
...@@ -35,7 +35,7 @@ describe('auditSrv', function() { ...@@ -35,7 +35,7 @@ describe('auditSrv', function() {
}); });
it('should return an empty array when not given an id', function(done) { it('should return an empty array when not given an id', function(done) {
ctx.service.getAuditLog({ }).then(function(versions) { ctx.service.getHistoryList({ }).then(function(versions) {
expect(versions).to.eql([]); expect(versions).to.eql([]);
done(); done();
}); });
...@@ -43,7 +43,7 @@ describe('auditSrv', function() { ...@@ -43,7 +43,7 @@ describe('auditSrv', function() {
}); });
it('should return an empty array when not given a dashboard', function(done) { it('should return an empty array when not given a dashboard', function(done) {
ctx.service.getAuditLog().then(function(versions) { ctx.service.getHistoryList().then(function(versions) {
expect(versions).to.eql([]); expect(versions).to.eql([]);
done(); done();
}); });
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
@import "pages/playlist"; @import "pages/playlist";
@import "pages/admin"; @import "pages/admin";
@import "pages/alerting"; @import "pages/alerting";
@import "pages/audit"; @import "pages/history";
@import "pages/plugins"; @import "pages/plugins";
@import "pages/signup"; @import "pages/signup";
@import "pages/styleguide"; @import "pages/styleguide";
......
// Audit Table // History Table
.audit-table { .history-table {
// .gf-form overrides // .gf-form overrides
.gf-form-label { display: none; } .gf-form-label { display: none; }
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
} }
// Diff View // Diff View
.audit-log { .history-list {
h4 { h4 {
margin-bottom: 0.75em; margin-bottom: 0.75em;
} }
......
...@@ -39,7 +39,7 @@ define([], ...@@ -39,7 +39,7 @@ define([],
dashboardId: 1, dashboardId: 1,
parentVersion: 0, parentVersion: 0,
restoredFrom: -1, restoredFrom: -1,
slug: 'audit-dashboard', slug: 'history-dashboard',
version: 1, version: 1,
created: '2017-02-22T17:06:37-08:00', created: '2017-02-22T17:06:37-08:00',
createdBy: 'admin', createdBy: 'admin',
...@@ -57,7 +57,7 @@ define([], ...@@ -57,7 +57,7 @@ define([],
canSave: true, canSave: true,
canEdit: true, canEdit: true,
canStar: true, canStar: true,
slug: 'audit-dashboard', slug: 'history-dashboard',
expires: '0001-01-01T00:00:00Z', expires: '0001-01-01T00:00:00Z',
created: '2017-02-21T18:40:45-08:00', created: '2017-02-21T18:40:45-08:00',
updated: '2017-04-11T21:31:22.59219665-07:00', updated: '2017-04-11T21:31:22.59219665-07:00',
...@@ -69,7 +69,7 @@ define([], ...@@ -69,7 +69,7 @@ define([],
annotations: { annotations: {
list: [] list: []
}, },
description: 'A random dashboard for implementing the audit log', description: 'A random dashboard for implementing the history list',
editable: true, editable: true,
gnetId: null, gnetId: null,
graphTooltip: 0, graphTooltip: 0,
...@@ -185,7 +185,7 @@ define([], ...@@ -185,7 +185,7 @@ define([],
] ]
}, },
timezone: 'utc', timezone: 'utc',
title: 'Audit Dashboard', title: 'History Dashboard',
version: version, version: version,
} }
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment