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) { ...@@ -111,8 +111,6 @@ function (angular, _, moment, config, store) {
window.saveAs(blob, $scope.dashboard.title + '-' + new Date().getTime()); 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) { $scope.zoom = function(factor) {
var _range = timeSrv.timeRange(); var _range = timeSrv.timeRange();
var _timespan = (_range.to.valueOf() - _range.from.valueOf()); var _timespan = (_range.to.valueOf() - _range.from.valueOf());
...@@ -138,6 +136,12 @@ function (angular, _, moment, config, store) { ...@@ -138,6 +136,12 @@ function (angular, _, moment, config, store) {
$scope.grafana.style = $scope.dashboard.style; $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.openSaveDropdown = function() {
$scope.isFavorite = playlistSrv.isCurrentFavorite($scope.dashboard); $scope.isFavorite = playlistSrv.isCurrentFavorite($scope.dashboard);
$scope.saveDropdownOpened = true; $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, _) { ...@@ -18,7 +18,7 @@ function (angular, app, _) {
$scope.init = function() { $scope.init = function() {
$scope.panel = $scope.pulldown; $scope.panel = $scope.pulldown;
$scope.row = $scope.pulldown; $scope.row = $scope.pulldown;
$scope.templateParameters = $scope.dashboard.templating.list; $scope.variables = $scope.dashboard.templating.list;
}; };
$scope.disableAnnotation = function (annotation) { $scope.disableAnnotation = function (annotation) {
...@@ -26,8 +26,8 @@ function (angular, app, _) { ...@@ -26,8 +26,8 @@ function (angular, app, _) {
$rootScope.$broadcast('refresh'); $rootScope.$broadcast('refresh');
}; };
$scope.filterOptionSelected = function(param, option) { $scope.setVariableValue = function(param, option) {
templateValuesSrv.filterOptionSelected(param, option); templateValuesSrv.setVariableValue(param, option);
}; };
$scope.init(); $scope.init();
......
...@@ -21,13 +21,13 @@ function (angular, _) { ...@@ -21,13 +21,13 @@ function (angular, _) {
$scope.editor = { index: 0 }; $scope.editor = { index: 0 };
$scope.datasources = datasourceSrv.getMetricSources(); $scope.datasources = datasourceSrv.getMetricSources();
$scope.currentDatasource = _.findWhere($scope.datasources, { default: true }); $scope.currentDatasource = _.findWhere($scope.datasources, { default: true });
$scope.templateParameters = templateSrv.templateParameters; $scope.variables = templateSrv.variables;
$scope.reset(); $scope.reset();
_.each($scope.templateParameters, function(param) { _.each($scope.variables, function(variable) {
if (param.datasource === void 0) { if (variable.datasource === void 0) {
param.datasource = null; variable.datasource = null;
param.type = 'query'; variable.type = 'query';
} }
}); });
...@@ -40,19 +40,19 @@ function (angular, _) { ...@@ -40,19 +40,19 @@ function (angular, _) {
$scope.add = function() { $scope.add = function() {
$scope.current.datasource = $scope.currentDatasource.name; $scope.current.datasource = $scope.currentDatasource.name;
$scope.templateParameters.push($scope.current); $scope.variables.push($scope.current);
$scope.reset(); $scope.reset();
$scope.editor.index = 0; $scope.editor.index = 0;
}; };
$scope.runQuery = function() { $scope.runQuery = function() {
templateValuesSrv.updateValuesFor($scope.current); templateValuesSrv.updateOptions($scope.current);
}; };
$scope.edit = function(param) { $scope.edit = function(variable) {
$scope.current = param; $scope.current = variable;
$scope.currentIsNew = false; $scope.currentIsNew = false;
$scope.currentDatasource = _.findWhere($scope.datasources, { name: param.datasource }); $scope.currentDatasource = _.findWhere($scope.datasources, { name: variable.datasource });
if (!$scope.currentDatasource) { if (!$scope.currentDatasource) {
$scope.currentDatasource = $scope.datasources[0]; $scope.currentDatasource = $scope.datasources[0];
...@@ -62,6 +62,7 @@ function (angular, _) { ...@@ -62,6 +62,7 @@ function (angular, _) {
}; };
$scope.update = function() { $scope.update = function() {
templateValuesSrv.updateOptions($scope.current);
$scope.reset(); $scope.reset();
$scope.editor.index = 0; $scope.editor.index = 0;
}; };
...@@ -73,14 +74,14 @@ function (angular, _) { ...@@ -73,14 +74,14 @@ function (angular, _) {
$scope.typeChanged = function () { $scope.typeChanged = function () {
if ($scope.current.type === 'time period') { 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.current.auto_count = 10;
} }
}; };
$scope.removeTemplateParam = function(templateParam) { $scope.removeVariable = function(variable) {
var index = _.indexOf($scope.templateParameters, templateParam); var index = _.indexOf($scope.variables, variable);
$scope.templateParameters.splice(index, 1); $scope.variables.splice(index, 1);
}; };
}); });
......
...@@ -15,6 +15,7 @@ define([ ...@@ -15,6 +15,7 @@ define([
'./bodyClass', './bodyClass',
'./addGraphiteFunc', './addGraphiteFunc',
'./graphiteFuncEditor', './graphiteFuncEditor',
'./templateParamSelector',
'./grafanaVersionCheck', './grafanaVersionCheck',
'./influxdbFuncEditor' './influxdbFuncEditor'
], function () {}); ], 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 @@ ...@@ -47,6 +47,9 @@
<a class="link" ng-click="removeAsFavorite()">Remove as favorite</a> <a class="link" ng-click="removeAsFavorite()">Remove as favorite</a>
</li> </li>
<li> <li>
<a class="link" ng-click="editJson()">Edit Json</a>
</li>
<li>
<a class="link" ng-click="exportDashboard()">Export dashboard</a> <a class="link" ng-click="exportDashboard()">Export dashboard</a>
</li> </li>
<li ng-show="db.saveTemp"> <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 @@ ...@@ -18,21 +18,18 @@
</ul> </ul>
<ul class="grafana-segment-list"> <ul class="grafana-segment-list">
<li ng-repeat-start="param in templateParameters" class="grafana-target-segment template-param-name"> <li class="small grafana-target-segment">
{{param.name}}: <strong>VARIABLES</strong>
</li>
<li ng-repeat-start="variable in variables" class="grafana-target-segment template-param-name">
{{variable.name}}:
</li> </li>
<li ng-repeat-end> <li ng-repeat-end template-param-selector>
<div class="dropdown"> </li>
<a class="dropdown-toggle grafana-target-segment" data-toggle="dropdown">
{{param.current.text}} <li class="small grafana-target-segment">
</a> <strong>ANNOTATIONS</strong>
<ul class="dropdown-menu">
<li ng-repeat="option in param.options">
<a ng-click="filterOptionSelected(param, option)">{{option.text}}</a>
</li>
</ul>
</div>
</li> </li>
<li ng-repeat="annotation in dashboard.annotations.list" class="grafana-target-segment annotation-segment" ng-class="{'annotation-disabled': !annotation.enable}"> <li ng-repeat="annotation in dashboard.annotations.list" class="grafana-target-segment annotation-segment" ng-class="{'annotation-disabled': !annotation.enable}">
......
...@@ -17,25 +17,25 @@ ...@@ -17,25 +17,25 @@
<div class="editor-row row"> <div class="editor-row row">
<div class="span8"> <div class="span8">
<div ng-if="templateParameters.length === 0"> <div ng-if="variables.length === 0">
<em>No replacements defined</em> <em>No replacements defined</em>
</div> </div>
<table class="grafana-options-table"> <table class="grafana-options-table">
<tr ng-repeat="templateParam in templateParameters"> <tr ng-repeat="variable in variables">
<td style="width: 1%"> <td style="width: 1%">
[[{{templateParam.name}}]] [[{{variable.name}}]]
</td> </td>
<td class="max-width" style="max-width: 200px;"> <td class="max-width" style="max-width: 200px;">
{{templateParam.query}} {{variable.query}}
</td> </td>
<td style="width: 1%"> <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> <i class="icon-edit"></i>
Edit Edit
</a> </a>
</td> </td>
<td style="width: 1%"> <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> <i class="icon-remove"></i>
</a> </a>
</td> </td>
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
<div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)"> <div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)">
<div class="editor-row"> <div class="editor-row">
<div class="editor-option"> <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> <input type="text" class="input-medium" ng-model='current.name' placeholder="name"></input>
</div> </div>
<div class="editor-option"> <div class="editor-option">
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
<div ng-show="current.type === 'time period'"> <div ng-show="current.type === 'time period'">
<div class="editor-option"> <div class="editor-option">
<label class="small">Values</label> <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>
<div class="editor-option"> <div class="editor-option">
<label class="small">Auto period count <tip>The number you want to divide the time range in</tip></label> <label class="small">Auto period count <tip>The number you want to divide the time range in</tip></label>
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
<div ng-show="current.type === 'query'"> <div ng-show="current.type === 'query'">
<div class="editor-row"> <div class="editor-row">
<div class="editor-option form-inline"> <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> <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> <button class="btn btn-small btn-success" ng-click="runQuery()" bs-tooltip="'Execute query'" data-placement="right"><i class="icon-play"></i></button>
</div> </div>
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
<div class="editor-row" style="margin-top: 10px;"> <div class="editor-row" style="margin-top: 10px;">
<div class="editor-option form-inline"> <div class="editor-option form-inline">
<label class="small">Current replacement values</label> <label class="small">Variable values</label>
<ul> <ul>
<li ng-repeat="option in current.options"> <li ng-repeat="option in current.options">
{{option.text}} {{option.text}}
......
...@@ -11,25 +11,25 @@ function (angular, _) { ...@@ -11,25 +11,25 @@ function (angular, _) {
module.service('templateSrv', function($q, $routeParams) { module.service('templateSrv', function($q, $routeParams) {
this.init = function(templateParameters) { this.init = function(variables) {
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g }; this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
this.templateParameters = templateParameters; this.variables = variables;
this.updateTemplateData(true); this.updateTemplateData(true);
}; };
this.updateTemplateData = function(initial) { this.updateTemplateData = function(initial) {
var _templateData = {}; var _templateData = {};
_.each(this.templateParameters, function(templateParameter) { _.each(this.variables, function(variable) {
if (initial) { if (initial) {
var urlValue = $routeParams[ templateParameter.name ]; var urlValue = $routeParams[ variable.name ];
if (urlValue) { 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; return;
} }
_templateData[templateParameter.name] = templateParameter.current.value; _templateData[variable.name] = variable.current.value;
}); });
this._templateData = _templateData; this._templateData = _templateData;
}; };
......
...@@ -13,24 +13,24 @@ function (angular, _) { ...@@ -13,24 +13,24 @@ function (angular, _) {
var self = this; var self = this;
this.init = function(dashboard) { 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++) { for (var i = 0; i < this.variables.length; i++) {
var param = this.templateParameters[i]; var param = this.variables[i];
if (param.refresh) { if (param.refresh) {
this.updateValuesFor(param); this.updateOptions(param);
} }
} }
}; };
this.filterOptionSelected = function(templateParameter, option, recursive) { this.setVariableValue = function(variable, option, recursive) {
templateParameter.current = option; variable.current = option;
templateSrv.updateTemplateData(); templateSrv.updateTemplateData();
return this.applyFilterToOtherFilters(templateParameter) return this.applyFilterToOtherFilters(variable)
.then(function() { .then(function() {
if (!recursive) { if (!recursive) {
$rootScope.$broadcast('refresh'); $rootScope.$broadcast('refresh');
...@@ -38,46 +38,54 @@ function (angular, _) { ...@@ -38,46 +38,54 @@ function (angular, _) {
}); });
}; };
this.applyFilterToOtherFilters = function(updatedTemplatedParam) { this.applyFilterToOtherFilters = function(updatedVariable) {
var promises = _.map(self.templateParameters, function(templateParam) { var promises = _.map(self.variables, function(otherVariable) {
if (templateParam === updatedTemplatedParam) { if (otherVariable === updatedVariable) {
return; return;
} }
if (templateParam.query.indexOf('[[' + updatedTemplatedParam.name + ']]') !== -1) { if (otherVariable.query.indexOf('[[' + updatedVariable.name + ']]') !== -1) {
return self.applyFilter(templateParam); return self.updateOptions(otherVariable);
} }
}); });
return $q.all(promises); return $q.all(promises);
}; };
this.updateValuesFor = function(templateParam) { this.updateOptions = function(variable) {
var datasource = datasourceSrv.get(templateParam.datasource); if (variable.type === 'time period') {
return datasource.metricFindQuery(templateParam.query) 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) { .then(function (results) {
templateParam.options = _.map(results, function(node) { variable.options = _.map(results, function(node) {
return { text: node.text, value: node.text }; return { text: node.text, value: node.text };
}); });
if (templateParam.includeAll) { if (variable.includeAll) {
var allExpr = '{'; var allExpr = '{';
_.each(templateParam.options, function(option) { _.each(variable.options, function(option) {
allExpr += option.text + ','; allExpr += option.text + ',';
}); });
allExpr = allExpr.substring(0, allExpr.length - 1) + '}'; 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 parameter has current value
// if it exists in options array keep value // if it exists in options array keep value
if (templateParam.current) { if (variable.current) {
var currentExists = _.findWhere(templateParam.options, { value: templateParam.current.value }); var currentExists = _.findWhere(variable.options, { value: variable.current.value });
if (currentExists) { 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([ ...@@ -127,6 +127,7 @@ require([
'specs/seriesOverridesCtrl-specs', 'specs/seriesOverridesCtrl-specs',
'specs/timeSrv-specs', 'specs/timeSrv-specs',
'specs/templateSrv-specs', 'specs/templateSrv-specs',
'specs/templateValuesSrv-specs',
'specs/kbn-format-specs', 'specs/kbn-format-specs',
'specs/dashboardSrv-specs', 'specs/dashboardSrv-specs',
'specs/dashboardViewStateSrv-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