Commit f9cd4a44 by Torkel Ödegaard

More work on templating, added an embry of a dashboard json edit view

parent b761aad9
......@@ -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;
......
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 () {});
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);
}
};
});
});
......@@ -47,6 +47,9 @@
<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>
<li ng-show="db.saveTemp">
......
<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);
});
};
......
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',
......
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