mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard schema simplifications, moved schema updates to dashboard model creation, removes irritating 'unsaved changes' dialogs that show for dashboard schema changes, Closes #532
This commit is contained in:
parent
0a677449dc
commit
60f68abd31
@ -22,6 +22,7 @@
|
||||
**Changes**
|
||||
- [Issue #536](https://github.com/grafana/grafana/issues/536). Graphite: Use unix epoch for Graphite from/to for absolute time ranges
|
||||
- [Issue #641](https://github.com/grafana/grafana/issues/536). General: Dashboard save temp copy feature settings moved from dashboard to config.js, default is enabled, and ttl to 30 days
|
||||
- [Issue #532](https://github.com/grafana/grafana/issues/532). Schema: Dashboard schema changes, "Unsaved changes" should not appear for schema changes. All changes are backward compatible with old schema.
|
||||
|
||||
**Fixes**
|
||||
- [Issue #545](https://github.com/grafana/grafana/issues/545). Chart: Fix formatting negative values (axis formats, legend values)
|
||||
|
56
sample/start_dashboard_html.html
Normal file
56
sample/start_dashboard_html.html
Normal file
@ -0,0 +1,56 @@
|
||||
<br/>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs#configuration" target="_blank">Configuration</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/troubleshooting" target="_blank">Troubleshooting</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/support" target="_blank">Support</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/intro" target="_blank">Getting started</a> (Must read!)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/charts" target="_blank">Charts</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/annotations" target="_blank">Annotations</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/graphite" target="_blank">Graphite</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/influxdb" target="_blank">InfluxDB</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://localhost:4567/docs/features/opentsdb" target="_blank">OpenTSDB</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<ul>
|
||||
<li>Ctrl+S saves the current dashboard</li>
|
||||
<li>Ctrl+F Opens the dashboard finder (searches elastic search)</li>
|
||||
<li>Ctrl+H Hide/show row controls</li>
|
||||
<li>Click and drag graph title to move panel</li>
|
||||
<li>Hit Escape to exit graph when in fullscreen or edit mode</li>
|
||||
<li>Click the colored icon in the legend to change series color</li>
|
||||
<li>Ctrl or Shift + Click legend name to hide other series</li>
|
||||
<li>Click the Save icon in the menu to save the dashboard with a new name</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@ -188,6 +188,10 @@ function (angular, _, config, gfunc, Parser) {
|
||||
$scope.segments[segmentIndex].val = $scope.altSegments[altIndex].val;
|
||||
$scope.segments[segmentIndex].html = $scope.altSegments[altIndex].html;
|
||||
|
||||
if ($scope.functions.length > 0 && $scope.functions[0].def.fake) {
|
||||
$scope.functions = [];
|
||||
}
|
||||
|
||||
if ($scope.altSegments[altIndex].expandable) {
|
||||
return checkOtherSegments(segmentIndex + 1)
|
||||
.then(function () {
|
||||
|
@ -13,10 +13,8 @@ function (angular, app, _) {
|
||||
title: "Row",
|
||||
height: "150px",
|
||||
collapse: false,
|
||||
collapsable: true,
|
||||
editable: true,
|
||||
panels: [],
|
||||
notice: false
|
||||
};
|
||||
|
||||
_.defaults($scope.row,_d);
|
||||
@ -26,16 +24,11 @@ function (angular, app, _) {
|
||||
};
|
||||
|
||||
$scope.toggle_row = function(row) {
|
||||
if(!row.collapsable) {
|
||||
return;
|
||||
}
|
||||
row.collapse = row.collapse ? false : true;
|
||||
if (!row.collapse) {
|
||||
$timeout(function() {
|
||||
$scope.$broadcast('render');
|
||||
});
|
||||
} else {
|
||||
row.notice = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
{
|
||||
"title": "Welcome to Grafana!",
|
||||
"services": {
|
||||
"filter": {
|
||||
"list": [],
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
}
|
||||
}
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"rows": [
|
||||
{
|
||||
@ -15,7 +13,6 @@
|
||||
"height": "150px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"error": false,
|
||||
@ -28,15 +25,13 @@
|
||||
"style": {},
|
||||
"title": "Welcome to Grafana"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "test",
|
||||
"height": "250px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [
|
||||
{
|
||||
"span": 12,
|
||||
@ -86,8 +81,7 @@
|
||||
"aliasYAxis": {},
|
||||
"title": "Graphite test"
|
||||
}
|
||||
],
|
||||
"notice": false
|
||||
]
|
||||
}
|
||||
],
|
||||
"editable": true,
|
||||
|
@ -1,13 +1,11 @@
|
||||
{
|
||||
"title": "New Dashboard",
|
||||
"services": {
|
||||
"filter": {
|
||||
"list": [],
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
}
|
||||
}
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"rows": [
|
||||
{
|
||||
@ -15,9 +13,7 @@
|
||||
"height": "250px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"collapsable": true,
|
||||
"panels": [],
|
||||
"notice": false
|
||||
"panels": []
|
||||
}
|
||||
],
|
||||
"editable": true,
|
||||
|
@ -28,16 +28,13 @@ timspan = '1d';
|
||||
// Intialize a skeleton with nothing but a rows array and service object
|
||||
dashboard = {
|
||||
rows : [],
|
||||
services : {}
|
||||
};
|
||||
|
||||
// Set a title
|
||||
dashboard.title = 'Scripted dash';
|
||||
dashboard.services.filter = {
|
||||
time: {
|
||||
from: "now-" + (ARGS.from || timspan),
|
||||
to: "now"
|
||||
}
|
||||
dashboard.time = {
|
||||
from: "now-" + (ARGS.from || timspan),
|
||||
to: "now"
|
||||
};
|
||||
|
||||
var rows = 1;
|
||||
@ -59,7 +56,7 @@ for (var i = 0; i < rows; i++) {
|
||||
panels: [
|
||||
{
|
||||
title: 'Events',
|
||||
type: 'graphite',
|
||||
type: 'graph',
|
||||
span: 12,
|
||||
fill: 1,
|
||||
linewidth: 2,
|
||||
@ -77,4 +74,4 @@ for (var i = 0; i < rows; i++) {
|
||||
}
|
||||
|
||||
|
||||
return dashboard;
|
||||
return dashboard;
|
||||
|
@ -185,32 +185,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
_.defaults($scope.panel.tooltip, _d.tooltip);
|
||||
_.defaults($scope.panel.annotate, _d.annotate);
|
||||
_.defaults($scope.panel.grid, _d.grid);
|
||||
|
||||
// backward compatible stuff
|
||||
if (_.isBoolean($scope.panel.legend)) {
|
||||
$scope.panel.legend = { show: $scope.panel.legend };
|
||||
_.defaults($scope.panel.legend, _d.legend);
|
||||
}
|
||||
|
||||
if ($scope.panel.grid.min) {
|
||||
$scope.panel.grid.leftMin = $scope.panel.grid.min;
|
||||
delete $scope.panel.grid.min;
|
||||
}
|
||||
|
||||
if ($scope.panel.grid.max) {
|
||||
$scope.panel.grid.leftMax = $scope.panel.grid.max;
|
||||
delete $scope.panel.grid.max;
|
||||
}
|
||||
|
||||
if ($scope.panel.y_format) {
|
||||
$scope.panel.y_formats[0] = $scope.panel.y_format;
|
||||
delete $scope.panel.y_format;
|
||||
}
|
||||
|
||||
if ($scope.panel.y2_format) {
|
||||
$scope.panel.y_formats[1] = $scope.panel.y2_format;
|
||||
delete $scope.panel.y2_format;
|
||||
}
|
||||
_.defaults($scope.panel.legend, _d.legend);
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.initBaseController(this, $scope);
|
||||
|
@ -36,7 +36,7 @@ function (angular, app, _, require) {
|
||||
style: {},
|
||||
};
|
||||
|
||||
_.defaults($scope.panel,_d);
|
||||
_.defaults($scope.panel, _d);
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.initBaseController(this, $scope);
|
||||
|
@ -34,13 +34,13 @@
|
||||
<span class="row-button bgWarning" config-modal="app/partials/roweditor.html" class="pointer">
|
||||
<i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
|
||||
</span>
|
||||
<span class="row-button bgPrimary" ng-click="toggle_row(row)" ng-show="row.collapsable">
|
||||
<span class="row-button bgPrimary" ng-click="toggle_row(row)">
|
||||
<i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i>
|
||||
</span>
|
||||
<span class="row-button row-text" ng-click="toggle_row(row)" ng-class="{'pointer':row.collapsable}">{{row.title || 'Row '+$index}}</span>
|
||||
<span class="row-button row-text" ng-click="toggle_row(row)">{{row.title || 'Row '+$index}}</span>
|
||||
</div>
|
||||
<div class="row-open" ng-show="!row.collapse">
|
||||
<div ng-show="row.collapsable" class='row-tab bgPrimary' ng-click="toggle_row(row)">
|
||||
<div class='row-tab bgPrimary' ng-click="toggle_row(row)">
|
||||
<span class="row-tab-button">
|
||||
<i class="icon-caret-right"></i>
|
||||
</span>
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
<h3 class="text-center"><i class="icon-warning-sign"></i> Unsaved changes</h3>
|
||||
<div class="row-fluid">
|
||||
<span class="span3"></span>
|
||||
<span class="span3">
|
||||
{{changes}}
|
||||
|
||||
</span>
|
||||
<button type="button" class="btn btn-success span2" ng-click="dismiss()">Cancel</button>
|
||||
<button type="button" class="btn btn-success span2" ng-click="save();dismiss();">Save</button>
|
||||
<button type="button" class="btn btn-warning span2" ng-click="ignore();dismiss();">Ignore</button>
|
||||
@ -13,4 +16,4 @@
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,8 @@ define([
|
||||
'angular',
|
||||
'jquery',
|
||||
'kbn',
|
||||
'underscore'
|
||||
'underscore',
|
||||
'../timer',
|
||||
],
|
||||
function (angular, $, kbn, _) {
|
||||
'use strict';
|
||||
@ -17,7 +18,7 @@ function (angular, $, kbn, _) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
this.title = data.title;
|
||||
this.title = data.title || 'No Title';
|
||||
this.tags = data.tags || [];
|
||||
this.style = data.style || "dark";
|
||||
this.timezone = data.timezone || 'browser';
|
||||
@ -25,7 +26,8 @@ function (angular, $, kbn, _) {
|
||||
this.rows = data.rows || [];
|
||||
this.pulldowns = data.pulldowns || [];
|
||||
this.nav = data.nav || [];
|
||||
this.services = data.services || {};
|
||||
this.time = data.time || { from: 'now-6h', to: 'now' };
|
||||
this.templating = data.templating || { list: [] };
|
||||
|
||||
if (this.nav.length === 0) {
|
||||
this.nav.push({ type: 'timepicker' });
|
||||
@ -39,13 +41,7 @@ function (angular, $, kbn, _) {
|
||||
this.pulldowns.push({ type: 'annotations', enable: false });
|
||||
}
|
||||
|
||||
_.each(this.rows, function(row) {
|
||||
_.each(row.panels, function(panel) {
|
||||
if (panel.type === 'graphite') {
|
||||
panel.type = 'graph';
|
||||
}
|
||||
});
|
||||
});
|
||||
this.updateSchema(data);
|
||||
}
|
||||
|
||||
var p = DashboardModel.prototype;
|
||||
@ -76,6 +72,64 @@ function (angular, $, kbn, _) {
|
||||
}
|
||||
};
|
||||
|
||||
p.updateSchema = function(old) {
|
||||
var i, j, row, panel;
|
||||
var isChanged = false;
|
||||
|
||||
if (this.version === 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (old.services) {
|
||||
if (old.services.filter) {
|
||||
this.time = old.services.filter.time;
|
||||
this.templating.list = old.services.filter.list;
|
||||
}
|
||||
delete this.services;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.rows.length; i++) {
|
||||
row = this.rows[i];
|
||||
for (j = 0; j < row.panels.length; j++) {
|
||||
panel = row.panels[j];
|
||||
if (panel.type === 'graphite') {
|
||||
panel.type = 'graph';
|
||||
isChanged = true;
|
||||
}
|
||||
|
||||
if (panel.type === 'graph') {
|
||||
if (_.isBoolean(panel.legend)) {
|
||||
panel.legend = { show: panel.legend };
|
||||
}
|
||||
|
||||
if (panel.grid) {
|
||||
if (panel.grid.min) {
|
||||
panel.grid.leftMin = panel.grid.min;
|
||||
delete panel.grid.min;
|
||||
}
|
||||
|
||||
if (panel.grid.max) {
|
||||
panel.grid.leftMax = panel.grid.max;
|
||||
delete panel.grid.max;
|
||||
}
|
||||
}
|
||||
|
||||
if (panel.y_format) {
|
||||
panel.y_formats[0] = panel.y_format;
|
||||
delete panel.y_format;
|
||||
}
|
||||
|
||||
if (panel.y2_format) {
|
||||
panel.y_formats[1] = panel.y2_format;
|
||||
delete panel.y2_format;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.version = 2;
|
||||
};
|
||||
|
||||
return {
|
||||
create: function(dashboard) {
|
||||
return new DashboardModel(dashboard);
|
||||
|
@ -9,12 +9,6 @@ define([
|
||||
var module = angular.module('grafana.services');
|
||||
|
||||
module.factory('filterSrv', function($rootScope, $timeout, $routeParams) {
|
||||
// defaults
|
||||
var _d = {
|
||||
templateParameters: [],
|
||||
time: {}
|
||||
};
|
||||
|
||||
var result = {
|
||||
|
||||
updateTemplateData: function(initial) {
|
||||
@ -86,26 +80,14 @@ define([
|
||||
|
||||
removeTemplateParameter: function(templateParameter) {
|
||||
this.templateParameters = _.without(this.templateParameters, templateParameter);
|
||||
this.dashboard.services.filter.list = this.templateParameters;
|
||||
this.dashboard.templating.list = this.templateParameters;
|
||||
},
|
||||
|
||||
init: function(dashboard) {
|
||||
_.defaults(this, _d);
|
||||
this.dashboard = dashboard;
|
||||
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
|
||||
|
||||
if (!this.dashboard.services.filter) {
|
||||
this.dashboard.services.filter = {
|
||||
list: [],
|
||||
time: {
|
||||
from: '1h',
|
||||
to: 'now'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.time = dashboard.services.filter.time;
|
||||
this.templateParameters = dashboard.services.filter.list || [];
|
||||
this.time = dashboard.time;
|
||||
this.templateParameters = dashboard.templating.list;
|
||||
this.updateTemplateData(true);
|
||||
}
|
||||
};
|
||||
|
@ -216,6 +216,7 @@ function (_) {
|
||||
|
||||
addFuncDef({
|
||||
name: 'randomWalk',
|
||||
fake: true,
|
||||
category: categories.Special,
|
||||
params: [{ name: "name", type: "string", }],
|
||||
defaultParams: ['randomWalk']
|
||||
|
@ -74,7 +74,7 @@ function(angular, _, config) {
|
||||
var original = self.original;
|
||||
|
||||
// ignore timespan changes
|
||||
current.services.filter.time = original.services.filter.time = {};
|
||||
current.time = original.time = {};
|
||||
|
||||
current.refresh = original.refresh;
|
||||
|
||||
|
@ -18,11 +18,9 @@ define([],
|
||||
rows: [],
|
||||
pulldowns: [ { type: 'templating' }, { type: 'annotations' } ],
|
||||
nav: [ { type: 'timepicker' } ],
|
||||
services: {
|
||||
filter: {
|
||||
time: {},
|
||||
list: []
|
||||
}
|
||||
time: {},
|
||||
templating: {
|
||||
list: []
|
||||
},
|
||||
refresh: true
|
||||
};
|
||||
|
82
src/test/specs/dashboardModel-specs.js
Normal file
82
src/test/specs/dashboardModel-specs.js
Normal file
@ -0,0 +1,82 @@
|
||||
define([
|
||||
'services/dashboard/dashboardModel'
|
||||
], function() {
|
||||
'use strict';
|
||||
|
||||
describe('when creating new dashboard with defaults only', function() {
|
||||
var model;
|
||||
|
||||
beforeEach(module('grafana.services'));
|
||||
|
||||
beforeEach(inject(function(dashboard) {
|
||||
model = dashboard.create({});
|
||||
}));
|
||||
|
||||
it('should have title', function() {
|
||||
expect(model.title).to.be('No Title');
|
||||
});
|
||||
|
||||
it('should have default properties', function() {
|
||||
expect(model.rows.length).to.be(0);
|
||||
expect(model.nav.length).to.be(1);
|
||||
expect(model.pulldowns.length).to.be(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when creating dashboard with old schema', function() {
|
||||
var model;
|
||||
var graph;
|
||||
|
||||
beforeEach(module('grafana.services'));
|
||||
|
||||
beforeEach(inject(function(dashboard) {
|
||||
model = dashboard.create({
|
||||
services: { filter: { time: { from: 'now-1d', to: 'now'}, list: [1] }},
|
||||
rows: [
|
||||
{
|
||||
panels: [
|
||||
{
|
||||
type: 'graphite',
|
||||
legend: true,
|
||||
grid: { min: 1, max: 10 }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
graph = model.rows[0].panels[0];
|
||||
|
||||
}));
|
||||
|
||||
it('should have title', function() {
|
||||
expect(model.title).to.be('No Title');
|
||||
});
|
||||
|
||||
it('should move time and filtering list', function() {
|
||||
expect(model.time.from).to.be('now-1d');
|
||||
expect(model.templating.list[0]).to.be(1);
|
||||
});
|
||||
|
||||
it('graphite panel should change name too graph', function() {
|
||||
expect(graph.type).to.be('graph');
|
||||
});
|
||||
|
||||
it('update legend setting', function() {
|
||||
expect(graph.legend.show).to.be(true);
|
||||
});
|
||||
|
||||
it('update grid options', function() {
|
||||
expect(graph.grid.leftMin).to.be(1);
|
||||
expect(graph.grid.leftMax).to.be(10);
|
||||
});
|
||||
|
||||
it('dashboard schema version should be set to latest', function() {
|
||||
expect(model.version).to.be(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
@ -124,6 +124,7 @@ require([
|
||||
'specs/gfunc-specs',
|
||||
'specs/filterSrv-specs',
|
||||
'specs/kbn-format-specs',
|
||||
'specs/dashboardModel-specs',
|
||||
'specs/influxSeries-specs'
|
||||
], function () {
|
||||
window.__karma__.start();
|
||||
|
Loading…
Reference in New Issue
Block a user