More work on templating, added an embry of a dashboard json edit view
This commit is contained in:
@@ -111,8 +111,6 @@ function (angular, _, moment, config, store) {
|
||||
window.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime());
|
||||
};
|
||||
|
||||
// function $scope.zoom
|
||||
// factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
|
||||
$scope.zoom = function(factor) {
|
||||
var _range = timeSrv.timeRange();
|
||||
var _timespan = (_range.to.valueOf() - _range.from.valueOf());
|
||||
@@ -138,6 +136,12 @@ function (angular, _, moment, config, store) {
|
||||
$scope.grafana.style = $scope.dashboard.style;
|
||||
};
|
||||
|
||||
$scope.editJson = function() {
|
||||
var editScope = $rootScope.$new();
|
||||
editScope.json = angular.toJson($scope.dashboard, true);
|
||||
$scope.emitAppEvent('show-dash-editor', { src: 'app/partials/edit_json.html', scope: editScope });
|
||||
};
|
||||
|
||||
$scope.openSaveDropdown = function() {
|
||||
$scope.isFavorite = playlistSrv.isCurrentFavorite($scope.dashboard);
|
||||
$scope.saveDropdownOpened = true;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash'
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('JsonEditorCtrl', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -18,7 +18,7 @@ function (angular, app, _) {
|
||||
$scope.init = function() {
|
||||
$scope.panel = $scope.pulldown;
|
||||
$scope.row = $scope.pulldown;
|
||||
$scope.templateParameters = $scope.dashboard.templating.list;
|
||||
$scope.variables = $scope.dashboard.templating.list;
|
||||
};
|
||||
|
||||
$scope.disableAnnotation = function (annotation) {
|
||||
@@ -26,8 +26,8 @@ function (angular, app, _) {
|
||||
$rootScope.$broadcast('refresh');
|
||||
};
|
||||
|
||||
$scope.filterOptionSelected = function(param, option) {
|
||||
templateValuesSrv.filterOptionSelected(param, option);
|
||||
$scope.setVariableValue = function(param, option) {
|
||||
templateValuesSrv.setVariableValue(param, option);
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
|
||||
@@ -21,13 +21,13 @@ function (angular, _) {
|
||||
$scope.editor = { index: 0 };
|
||||
$scope.datasources = datasourceSrv.getMetricSources();
|
||||
$scope.currentDatasource = _.findWhere($scope.datasources, { default: true });
|
||||
$scope.templateParameters = templateSrv.templateParameters;
|
||||
$scope.variables = templateSrv.variables;
|
||||
$scope.reset();
|
||||
|
||||
_.each($scope.templateParameters, function(param) {
|
||||
if (param.datasource === void 0) {
|
||||
param.datasource = null;
|
||||
param.type = 'query';
|
||||
_.each($scope.variables, function(variable) {
|
||||
if (variable.datasource === void 0) {
|
||||
variable.datasource = null;
|
||||
variable.type = 'query';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -40,19 +40,19 @@ function (angular, _) {
|
||||
|
||||
$scope.add = function() {
|
||||
$scope.current.datasource = $scope.currentDatasource.name;
|
||||
$scope.templateParameters.push($scope.current);
|
||||
$scope.variables.push($scope.current);
|
||||
$scope.reset();
|
||||
$scope.editor.index = 0;
|
||||
};
|
||||
|
||||
$scope.runQuery = function() {
|
||||
templateValuesSrv.updateValuesFor($scope.current);
|
||||
templateValuesSrv.updateOptions($scope.current);
|
||||
};
|
||||
|
||||
$scope.edit = function(param) {
|
||||
$scope.current = param;
|
||||
$scope.edit = function(variable) {
|
||||
$scope.current = variable;
|
||||
$scope.currentIsNew = false;
|
||||
$scope.currentDatasource = _.findWhere($scope.datasources, { name: param.datasource });
|
||||
$scope.currentDatasource = _.findWhere($scope.datasources, { name: variable.datasource });
|
||||
|
||||
if (!$scope.currentDatasource) {
|
||||
$scope.currentDatasource = $scope.datasources[0];
|
||||
@@ -62,6 +62,7 @@ function (angular, _) {
|
||||
};
|
||||
|
||||
$scope.update = function() {
|
||||
templateValuesSrv.updateOptions($scope.current);
|
||||
$scope.reset();
|
||||
$scope.editor.index = 0;
|
||||
};
|
||||
@@ -73,14 +74,14 @@ function (angular, _) {
|
||||
|
||||
$scope.typeChanged = function () {
|
||||
if ($scope.current.type === 'time period') {
|
||||
$scope.current.options = ['auto', '1m', '10m', '30m', '1h', '6h', '12h', '1d', '7d', '14d', '30d'];
|
||||
$scope.current.query = 'auto,1m,10m,30m,1h,6h,12h,1d,7d,14d,30d';
|
||||
$scope.current.auto_count = 10;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeTemplateParam = function(templateParam) {
|
||||
var index = _.indexOf($scope.templateParameters, templateParam);
|
||||
$scope.templateParameters.splice(index, 1);
|
||||
$scope.removeVariable = function(variable) {
|
||||
var index = _.indexOf($scope.variables, variable);
|
||||
$scope.variables.splice(index, 1);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ define([
|
||||
'./bodyClass',
|
||||
'./addGraphiteFunc',
|
||||
'./graphiteFuncEditor',
|
||||
'./templateParamSelector',
|
||||
'./grafanaVersionCheck',
|
||||
'./influxdbFuncEditor'
|
||||
], function () {});
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
define([
|
||||
'angular',
|
||||
'app',
|
||||
'lodash',
|
||||
'jquery',
|
||||
],
|
||||
function (angular, app, _, $) {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('grafana.directives')
|
||||
.directive('templateParamSelector', function($compile) {
|
||||
var inputTemplate = '<input type="text" data-provide="typeahead" ' +
|
||||
' class="grafana-target-segment-input input-medium"' +
|
||||
' spellcheck="false" style="display:none"></input>';
|
||||
|
||||
var buttonTemplate = '<a class="grafana-target-segment tabindex="1">{{variable.current.text}}</a>';
|
||||
|
||||
return {
|
||||
link: function($scope, elem) {
|
||||
var $input = $(inputTemplate);
|
||||
var $button = $(buttonTemplate);
|
||||
var variable = $scope.variable;
|
||||
var options = _.map(variable.options, function(option) {
|
||||
return option.text;
|
||||
});
|
||||
|
||||
$input.appendTo(elem);
|
||||
$button.appendTo(elem);
|
||||
|
||||
function updateVariableValue(value) {
|
||||
$scope.$apply(function() {
|
||||
var selected = _.findWhere(variable.options, { text: value });
|
||||
if (!selected) {
|
||||
selected = { text: value, value: value };
|
||||
}
|
||||
$scope.setVariableValue($scope.variable, selected);
|
||||
});
|
||||
}
|
||||
|
||||
$input.attr('data-provide', 'typeahead');
|
||||
$input.typeahead({
|
||||
source: options,
|
||||
minLength: 0,
|
||||
items: 10,
|
||||
updater: function(value) {
|
||||
updateVariableValue(value);
|
||||
$input.trigger('blur');
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
var typeahead = $input.data('typeahead');
|
||||
typeahead.lookup = function () {
|
||||
this.query = this.$element.val() || '';
|
||||
return this.process(this.source);
|
||||
};
|
||||
|
||||
$button.click(function() {
|
||||
$input.css('width', ($button.width() + 16) + 'px');
|
||||
|
||||
$button.hide();
|
||||
$input.show();
|
||||
$input.focus();
|
||||
|
||||
var typeahead = $input.data('typeahead');
|
||||
if (typeahead) {
|
||||
$input.val('');
|
||||
typeahead.lookup();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$input.blur(function() {
|
||||
if ($input.val() !== '') { updateVariableValue($input.val()); }
|
||||
$input.hide();
|
||||
$button.show();
|
||||
$button.focus();
|
||||
});
|
||||
|
||||
$compile(elem.contents())($scope);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -46,6 +46,9 @@
|
||||
<li ng-show="isFavorite">
|
||||
<a class="link" ng-click="removeAsFavorite()">Remove as favorite</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="link" ng-click="editJson()">Edit Json</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="link" ng-click="exportDashboard()">Export dashboard</a>
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<div>
|
||||
|
||||
<div class="dashboard-editor-header">
|
||||
<div class="dashboard-editor-title">
|
||||
<i class="icon icon-edit"></i>
|
||||
Edit / View JSON
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-editor-body" style="height: 500px">
|
||||
<textarea ng-model="json" rows="20" spellcheck="false" style="width: 90%; color: white"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-editor-footer">
|
||||
<button type="button" class="btn btn-success pull-right" ng-click="dismiss();">Close</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -18,21 +18,18 @@
|
||||
</ul>
|
||||
|
||||
<ul class="grafana-segment-list">
|
||||
<li ng-repeat-start="param in templateParameters" class="grafana-target-segment template-param-name">
|
||||
{{param.name}}:
|
||||
<li class="small grafana-target-segment">
|
||||
<strong>VARIABLES</strong>
|
||||
</li>
|
||||
<li ng-repeat-start="variable in variables" class="grafana-target-segment template-param-name">
|
||||
{{variable.name}}:
|
||||
</li>
|
||||
|
||||
<li ng-repeat-end>
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle grafana-target-segment" data-toggle="dropdown">
|
||||
{{param.current.text}}
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="option in param.options">
|
||||
<a ng-click="filterOptionSelected(param, option)">{{option.text}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<li ng-repeat-end template-param-selector>
|
||||
</li>
|
||||
|
||||
<li class="small grafana-target-segment">
|
||||
<strong>ANNOTATIONS</strong>
|
||||
</li>
|
||||
|
||||
<li ng-repeat="annotation in dashboard.annotations.list" class="grafana-target-segment annotation-segment" ng-class="{'annotation-disabled': !annotation.enable}">
|
||||
|
||||
@@ -17,25 +17,25 @@
|
||||
|
||||
<div class="editor-row row">
|
||||
<div class="span8">
|
||||
<div ng-if="templateParameters.length === 0">
|
||||
<div ng-if="variables.length === 0">
|
||||
<em>No replacements defined</em>
|
||||
</div>
|
||||
<table class="grafana-options-table">
|
||||
<tr ng-repeat="templateParam in templateParameters">
|
||||
<tr ng-repeat="variable in variables">
|
||||
<td style="width: 1%">
|
||||
[[{{templateParam.name}}]]
|
||||
[[{{variable.name}}]]
|
||||
</td>
|
||||
<td class="max-width" style="max-width: 200px;">
|
||||
{{templateParam.query}}
|
||||
{{variable.query}}
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="edit(templateParam)" class="btn btn-success btn-mini">
|
||||
<a ng-click="edit(variable)" class="btn btn-success btn-mini">
|
||||
<i class="icon-edit"></i>
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="removeTemplateParam(templateParam)" class="btn btn-danger btn-mini">
|
||||
<a ng-click="removeVariable(variable)" class="btn btn-danger btn-mini">
|
||||
<i class="icon-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
@@ -49,7 +49,7 @@
|
||||
<div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)">
|
||||
<div class="editor-row">
|
||||
<div class="editor-option">
|
||||
<label class="small">Replacement name</label>
|
||||
<label class="small">Variable name</label>
|
||||
<input type="text" class="input-medium" ng-model='current.name' placeholder="name"></input>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
@@ -69,7 +69,7 @@
|
||||
<div ng-show="current.type === 'time period'">
|
||||
<div class="editor-option">
|
||||
<label class="small">Values</label>
|
||||
<input type="text" class="input-xxlarge" array-join ng-model='current.options' ng-change="csvValuesChanged()" ng-model-onblur placeholder="name"></input>
|
||||
<input type="text" class="input-xxlarge" ng-model='current.query' placeholder="name"></input>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Auto period count <tip>The number you want to divide the time range in</tip></label>
|
||||
@@ -86,7 +86,7 @@
|
||||
<div ng-show="current.type === 'query'">
|
||||
<div class="editor-row">
|
||||
<div class="editor-option form-inline">
|
||||
<label class="small">Metric name query</label>
|
||||
<label class="small">Variable values query</label>
|
||||
<input type="text" class="input-xxlarge" ng-model='current.query' placeholder="apps.servers.*"></input>
|
||||
<button class="btn btn-small btn-success" ng-click="runQuery()" bs-tooltip="'Execute query'" data-placement="right"><i class="icon-play"></i></button>
|
||||
</div>
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
<div class="editor-row" style="margin-top: 10px;">
|
||||
<div class="editor-option form-inline">
|
||||
<label class="small">Current replacement values</label>
|
||||
<label class="small">Variable values</label>
|
||||
<ul>
|
||||
<li ng-repeat="option in current.options">
|
||||
{{option.text}}
|
||||
|
||||
@@ -11,25 +11,25 @@ function (angular, _) {
|
||||
|
||||
module.service('templateSrv', function($q, $routeParams) {
|
||||
|
||||
this.init = function(templateParameters) {
|
||||
this.init = function(variables) {
|
||||
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
|
||||
this.templateParameters = templateParameters;
|
||||
this.variables = variables;
|
||||
this.updateTemplateData(true);
|
||||
};
|
||||
|
||||
this.updateTemplateData = function(initial) {
|
||||
var _templateData = {};
|
||||
_.each(this.templateParameters, function(templateParameter) {
|
||||
_.each(this.variables, function(variable) {
|
||||
if (initial) {
|
||||
var urlValue = $routeParams[ templateParameter.name ];
|
||||
var urlValue = $routeParams[ variable.name ];
|
||||
if (urlValue) {
|
||||
templateParameter.current = { text: urlValue, value: urlValue };
|
||||
variable.current = { text: urlValue, value: urlValue };
|
||||
}
|
||||
}
|
||||
if (!templateParameter.current || !templateParameter.current.value) {
|
||||
if (!variable.current || !variable.current.value) {
|
||||
return;
|
||||
}
|
||||
_templateData[templateParameter.name] = templateParameter.current.value;
|
||||
_templateData[variable.name] = variable.current.value;
|
||||
});
|
||||
this._templateData = _templateData;
|
||||
};
|
||||
|
||||
@@ -13,24 +13,24 @@ function (angular, _) {
|
||||
var self = this;
|
||||
|
||||
this.init = function(dashboard) {
|
||||
this.templateParameters = dashboard.templating.list;
|
||||
this.variables = dashboard.templating.list;
|
||||
|
||||
templateSrv.init(this.templateParameters);
|
||||
templateSrv.init(this.variables);
|
||||
|
||||
for (var i = 0; i < this.templateParameters.length; i++) {
|
||||
var param = this.templateParameters[i];
|
||||
for (var i = 0; i < this.variables.length; i++) {
|
||||
var param = this.variables[i];
|
||||
if (param.refresh) {
|
||||
this.updateValuesFor(param);
|
||||
this.updateOptions(param);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.filterOptionSelected = function(templateParameter, option, recursive) {
|
||||
templateParameter.current = option;
|
||||
this.setVariableValue = function(variable, option, recursive) {
|
||||
variable.current = option;
|
||||
|
||||
templateSrv.updateTemplateData();
|
||||
|
||||
return this.applyFilterToOtherFilters(templateParameter)
|
||||
return this.applyFilterToOtherFilters(variable)
|
||||
.then(function() {
|
||||
if (!recursive) {
|
||||
$rootScope.$broadcast('refresh');
|
||||
@@ -38,46 +38,54 @@ function (angular, _) {
|
||||
});
|
||||
};
|
||||
|
||||
this.applyFilterToOtherFilters = function(updatedTemplatedParam) {
|
||||
var promises = _.map(self.templateParameters, function(templateParam) {
|
||||
if (templateParam === updatedTemplatedParam) {
|
||||
this.applyFilterToOtherFilters = function(updatedVariable) {
|
||||
var promises = _.map(self.variables, function(otherVariable) {
|
||||
if (otherVariable === updatedVariable) {
|
||||
return;
|
||||
}
|
||||
if (templateParam.query.indexOf('[[' + updatedTemplatedParam.name + ']]') !== -1) {
|
||||
return self.applyFilter(templateParam);
|
||||
if (otherVariable.query.indexOf('[[' + updatedVariable.name + ']]') !== -1) {
|
||||
return self.updateOptions(otherVariable);
|
||||
}
|
||||
});
|
||||
|
||||
return $q.all(promises);
|
||||
};
|
||||
|
||||
this.updateValuesFor = function(templateParam) {
|
||||
var datasource = datasourceSrv.get(templateParam.datasource);
|
||||
return datasource.metricFindQuery(templateParam.query)
|
||||
this.updateOptions = function(variable) {
|
||||
if (variable.type === 'time period') {
|
||||
variable.options = _.map(variable.query.split(','), function(text) {
|
||||
return { text: text, value: text };
|
||||
});
|
||||
self.setVariableValue(variable, variable.options[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var datasource = datasourceSrv.get(variable.datasource);
|
||||
return datasource.metricFindQuery(variable.query)
|
||||
.then(function (results) {
|
||||
templateParam.options = _.map(results, function(node) {
|
||||
variable.options = _.map(results, function(node) {
|
||||
return { text: node.text, value: node.text };
|
||||
});
|
||||
|
||||
if (templateParam.includeAll) {
|
||||
if (variable.includeAll) {
|
||||
var allExpr = '{';
|
||||
_.each(templateParam.options, function(option) {
|
||||
_.each(variable.options, function(option) {
|
||||
allExpr += option.text + ',';
|
||||
});
|
||||
allExpr = allExpr.substring(0, allExpr.length - 1) + '}';
|
||||
templateParam.options.unshift({text: 'All', value: allExpr});
|
||||
variable.options.unshift({text: 'All', value: allExpr});
|
||||
}
|
||||
|
||||
// if parameter has current value
|
||||
// if it exists in options array keep value
|
||||
if (templateParam.current) {
|
||||
var currentExists = _.findWhere(templateParam.options, { value: templateParam.current.value });
|
||||
if (variable.current) {
|
||||
var currentExists = _.findWhere(variable.options, { value: variable.current.value });
|
||||
if (currentExists) {
|
||||
return self.filterOptionSelected(templateParam, templateParam.current, true);
|
||||
return self.setVariableValue(variable, variable.current, true);
|
||||
}
|
||||
}
|
||||
|
||||
return self.filterOptionSelected(templateParam, templateParam.options[0], true);
|
||||
return self.setVariableValue(variable, variable.options[0], true);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
define([
|
||||
'mocks/dashboard-mock',
|
||||
'lodash',
|
||||
'services/templateValuesSrv'
|
||||
], function(dashboardMock) {
|
||||
'use strict';
|
||||
|
||||
describe('templateValuesSrv', function() {
|
||||
var _templateValuesSrv;
|
||||
var _dashboard;
|
||||
|
||||
beforeEach(module('grafana.services'));
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('datasourceSrv', {});
|
||||
$provide.value('templateSrv', {
|
||||
updateTemplateData: function() {}
|
||||
});
|
||||
_dashboard = dashboardMock.create();
|
||||
}));
|
||||
|
||||
beforeEach(inject(function(templateValuesSrv) {
|
||||
_templateValuesSrv = templateValuesSrv;
|
||||
}));
|
||||
|
||||
describe('update time period variable options', function() {
|
||||
var variable = {
|
||||
type: 'time period',
|
||||
query: 'auto,1s,2h,5h,1d',
|
||||
name: 'test'
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
_templateValuesSrv.updateOptions(variable);
|
||||
});
|
||||
|
||||
it('should update options array', function() {
|
||||
expect(variable.options.length).to.be(5);
|
||||
expect(variable.options[1].text).to.be('1s');
|
||||
expect(variable.options[1].value).to.be('1s');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -127,6 +127,7 @@ require([
|
||||
'specs/seriesOverridesCtrl-specs',
|
||||
'specs/timeSrv-specs',
|
||||
'specs/templateSrv-specs',
|
||||
'specs/templateValuesSrv-specs',
|
||||
'specs/kbn-format-specs',
|
||||
'specs/dashboardSrv-specs',
|
||||
'specs/dashboardViewStateSrv-specs',
|
||||
|
||||
Reference in New Issue
Block a user