mirror of
https://github.com/grafana/grafana.git
synced 2025-09-23 18:52:33 +08:00

A simple version control system for dashboards. Closes #1504. Goals 1. To create a new dashboard version every time a dashboard is saved. 2. To allow users to view all versions of a given dashboard. 3. To allow users to rollback to a previous version of a dashboard. 4. To allow users to compare two versions of a dashboard. Usage Navigate to a dashboard, and click the settings cog. From there, click the "Changelog" button to be brought to the Changelog view. In this view, a table containing each version of a dashboard can be seen. Each entry in the table represents a dashboard version. A selectable checkbox, the version number, date created, name of the user who created that version, and commit message is shown in the table, along with a button that allows a user to restore to a previous version of that dashboard. If a user wants to restore to a previous version of their dashboard, they can do so by clicking the previously mentioned button. If a user wants to compare two different versions of a dashboard, they can do so by clicking the checkbox of two different dashboard versions, then clicking the "Compare versions" button located below the dashboard. From there, the user is brought to a view showing a summary of the dashboard differences. Each summarized change contains a link that can be clicked to take the user a JSON diff highlighting the changes line by line. Overview of Changes Backend Changes - A `dashboard_version` table was created to store each dashboard version, along with a dashboard version model and structs to represent the queries and commands necessary for the dashboard version API methods. - API endpoints were created to support working with dashboard versions. - Methods were added to create, update, read, and destroy dashboard versions in the database. - Logic was added to compute the diff between two versions, and display it to the user. - The dashboard migration logic was updated to save a "Version 1" of each existing dashboard in the database. Frontend Changes - New views - Methods to pull JSON and HTML from endpoints New API Endpoints Each endpoint requires the authorization header to be sent in the format, ``` Authorization: Bearer <jwt> ``` where `<jwt>` is a JSON web token obtained from the Grafana admin panel. `GET "/api/dashboards/db/:dashboardId/versions?orderBy=<string>&limit=<int>&start=<int>"` Get all dashboard versions for the given dashboard ID. Accepts three URL parameters: - `orderBy` String to order the results by. Possible values are `version`, `created`, `created_by`, `message`. Default is `versions`. Ordering is always in descending order. - `limit` Maximum number of results to return - `start` Position in results to start from `GET "/api/dashboards/db/:dashboardId/versions/:id"` Get an individual dashboard version by ID, for the given dashboard ID. `POST "/api/dashboards/db/:dashboardId/restore"` Restore to the given dashboard version. Post body is of content-type `application/json`, and must contain. ```json { "dashboardId": <int>, "version": <int> } ``` `GET "/api/dashboards/db/:dashboardId/compare/:versionA...:versionB"` Compare two dashboard versions by ID for the given dashboard ID, returning a JSON delta formatted representation of the diff. The URL format follows what GitHub does. For example, visiting [/api/dashboards/db/18/compare/22...33](http://ec2-54-80-139-44.compute-1.amazonaws.com:3000/api/dashboards/db/18/compare/22...33) will return the diff between versions 22 and 33 for the dashboard ID 18. Dependencies Added - The Go package [gojsondiff](https://github.com/yudai/gojsondiff) was added and vendored.
77 lines
1.6 KiB
TypeScript
77 lines
1.6 KiB
TypeScript
///<reference path="../../headers/common.d.ts" />
|
|
|
|
import angular from 'angular';
|
|
import coreModule from '../core_module';
|
|
|
|
export class DeltaCtrl {
|
|
observer: any;
|
|
|
|
constructor(private $rootScope) {
|
|
const waitForCompile = function(mutations) {
|
|
if (mutations.length === 1) {
|
|
this.$rootScope.appEvent('json-diff-ready');
|
|
}
|
|
};
|
|
|
|
this.observer = new MutationObserver(waitForCompile.bind(this));
|
|
|
|
const observerConfig = {
|
|
attributes: true,
|
|
attributeFilter: ['class'],
|
|
characterData: false,
|
|
childList: true,
|
|
subtree: false,
|
|
};
|
|
|
|
this.observer.observe(angular.element('.delta-html')[0], observerConfig);
|
|
}
|
|
|
|
$onDestroy() {
|
|
this.observer.disconnect();
|
|
}
|
|
}
|
|
|
|
export function delta() {
|
|
return {
|
|
controller: DeltaCtrl,
|
|
replace: false,
|
|
restrict: 'A',
|
|
};
|
|
}
|
|
coreModule.directive('diffDelta', delta);
|
|
|
|
// Link to JSON line number
|
|
export class LinkJSONCtrl {
|
|
/** @ngInject */
|
|
constructor(private $scope, private $rootScope, private $anchorScroll) {}
|
|
|
|
goToLine(line: number) {
|
|
let unbind;
|
|
|
|
const scroll = () => {
|
|
this.$anchorScroll(`l${line}`);
|
|
unbind();
|
|
};
|
|
|
|
this.$scope.switchView().then(() => {
|
|
unbind = this.$rootScope.$on('json-diff-ready', scroll.bind(this));
|
|
});
|
|
}
|
|
}
|
|
|
|
export function linkJson() {
|
|
return {
|
|
controller: LinkJSONCtrl,
|
|
controllerAs: 'ctrl',
|
|
replace: true,
|
|
restrict: 'E',
|
|
scope: {
|
|
line: '@lineDisplay',
|
|
link: '@lineLink',
|
|
switchView: '&',
|
|
},
|
|
templateUrl: 'public/app/features/dashboard/audit/partials/link-json.html',
|
|
};
|
|
}
|
|
coreModule.directive('diffLinkJson', linkJson);
|