more work on multi select

This commit is contained in:
Torkel Ödegaard 2015-03-19 23:09:50 -04:00
parent 0d817e0664
commit 35888c814c
11 changed files with 238 additions and 93 deletions

View File

@ -91,25 +91,84 @@ function (angular, app, _, $) {
return {
scope: {
variable: "=",
onUpdated: "&"
},
templateUrl: 'app/features/dashboard/partials/variableValueSelect.html',
link: function(scope, elem) {
var bodyEl = angular.element($window.document.body);
var variable = scope.variable;
scope.show = function() {
scope.selectorOpen = true;
scope.giveFocus = 1;
scope.oldCurrentText = variable.current.text;
var currentValues = variable.current.value;
if (_.isString(currentValues)) {
currentValues = [currentValues];
}
scope.options = _.map(variable.options, function(option) {
var op = {text: option.text, value: option.value};
if (_.indexOf(currentValues, option.value) >= 0) {
op.selected = true;
}
return op;
});
$timeout(function() {
bodyEl.on('click', scope.bodyOnClick);
}, 0, false);
};
scope.hide = function() {
scope.selectorOpen = false;
bodyEl.off('click', scope.bodyOnClick);
scope.optionSelected = function(option) {
if (!variable.multi) {
_.each(scope.options, function(other) {
if (option !== other) {
other.selected = false;
}
});
}
var selected = _.filter(scope.options, {selected: true});
if (selected.length === 0) {
// encode the first selected if no option is selected
scope.options[0].selected = true;
$timeout(function() {
scope.optionSelected(scope.options[0]);
});
return;
}
if (selected.length > 1) {
if (selected[0].text === 'All') {
selected = selected.slice(1, selected.length);
}
}
variable.current = {
text: _.pluck(selected, 'text').join(', '),
value: _.pluck(selected, 'value'),
};
// only single value
if (variable.current.value.length === 1) {
variable.current.value = selected[0].value;
}
scope.updateLinkText();
};
scope.hide = function() {
scope.selectorOpen = false;
if (scope.oldCurrentText !== variable.current.text) {
scope.onUpdated();
}
bodyEl.off('click', scope.bodyOnClick);
};
scope.bodyOnClick = function(e) {
var dropdown = elem.find('.variable-value-dropdown');
@ -118,7 +177,17 @@ function (angular, app, _, $) {
}
};
scope.$on('$destroy', function() {
scope.updateLinkText = function() {
scope.linkText = "";
if (!variable.hideLabel) {
scope.linkText = (variable.label || variable.name) + ': ';
}
scope.linkText += variable.current.text;
};
scope.$watchGroup(['variable.hideLabel', 'variable.name', 'variable.label'], function() {
scope.updateLinkText();
});
},
};

View File

@ -1,5 +1,6 @@
<a ng-click="show()" class="variable-value-link">
{{variable.name}}: {{variable.current.text}} <i class="fa fa-caret-down"></i>
{{linkText}}
<i class="fa fa-caret-down"></i>
</a>
<div ng-if="selectorOpen" class="variable-value-dropdown">
@ -11,9 +12,9 @@
</div>
<div class="variable-options-container" ng-if="!query.tagcloud">
<div class="variable-option pointer" bindonce ng-repeat="option in variable.options"
<div class="variable-option pointer" bindonce ng-repeat="option in options"
ng-class="{'selected': $index === selectedIndex }" ng-href="{{row.url}}">
<input class="cr1" id="var.option.{{$id}}" type="checkbox" ng-model="option.selected" ng-checked="asd">
<input class="cr1" id="var.option.{{$id}}" type="checkbox" ng-model="option.selected" ng-checked="option.selected" ng-change="optionSelected(option)">
<label for="var.option.{{$id}}" class="cr1"></label>
<label for="var.option.{{$id}}" class="checkbox-label">{{option.text}}</label>
</div>

View File

@ -26,8 +26,10 @@ function (angular, _) {
$rootScope.$broadcast('refresh');
};
$scope.setVariableValue = function(param, option) {
templateValuesSrv.setVariableValue(param, option);
$scope.variableUpdated = function(variable) {
templateValuesSrv.variableUpdated(variable).then(function() {
$rootScope.$broadcast('refresh');
});
};
$scope.init();

View File

@ -17,6 +17,8 @@ function (angular, _) {
options: [],
includeAll: false,
allFormat: 'glob',
multi: false,
multiFormat: 'glob',
};
$scope.init = function() {
@ -75,7 +77,7 @@ function (angular, _) {
if ($scope.current.datasource === void 0) {
$scope.current.datasource = null;
$scope.current.type = 'query';
$scope.current.allFormat = 'Glob';
$scope.current.allFormat = 'glob';
}
};

View File

@ -29,11 +29,23 @@ function (angular, _) {
_.each(this.variables, function(variable) {
if (!variable.current || !variable.current.value) { return; }
this._values[variable.name] = variable.current.value;
this._values[variable.name] = this.renderVariableValue(variable);
this._texts[variable.name] = variable.current.text;
}, this);
};
this.renderVariableValue = function(variable) {
var value = variable.current.value;
if (_.isString(value)) {
return value;
} else {
if (variable.multiFormat === 'regex values') {
return '(' + value.join('|') + ')';
}
return '{' + value.join(',') + '}';
}
};
this.setGrafanaVariable = function (name, value) {
this._grafanaVariables[name] = value;
};

View File

@ -73,6 +73,11 @@ function (angular, _, kbn) {
});
};
this.variableUpdated = function(variable) {
templateSrv.updateTemplateData();
return this.updateOptionsInChildVariables(variable);
};
this.updateOptionsInChildVariables = function(updatedVariable) {
var promises = _.map(self.variables, function(otherVariable) {
if (otherVariable === updatedVariable) {

View File

@ -1,11 +1,10 @@
<div class="submenu-controls" ng-controller="SubmenuCtrl">
<div class="tight-form borderless">
<ul class="tight-form-list" ng-if="dashboard.templating.list.length > 0">
<li ng-repeat="variable in variables" class="tight-form-item template-param-name dropdown">
<variable-value-select variable="variable"></variable-value-select>
<variable-value-select variable="variable" on-updated="variableUpdated(variable)"></variable-value-select>
</li>
<!-- <li class="dropdown" ng&#45;repeat&#45;end> -->

View File

@ -37,7 +37,7 @@
{{variable.query}}
</td>
<td style="width: 1%">
<a ng-click="edit(variable)" class="btn btn-success btn-small">
<a ng-click="edit(variable)" class="btn btn-inverse btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
@ -56,7 +56,9 @@
</div>
<div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)">
<div class="editor-option">
<div class="editor-row">
<div class="section">
<h5>General</h5>
<div class="editor-row">
<div class="editor-option">
<label class="small">Variable name</label>
@ -64,26 +66,20 @@
</div>
<div class="editor-option">
<label class="small">Type</label>
<select class="input-medium" ng-model="current.type" ng-options="f for f in ['query', 'interval', 'custom']" ng-change="typeChanged()"></select>
<select class="input-small" ng-model="current.type" ng-options="f for f in ['query', 'interval', 'custom']" ng-change="typeChanged()"></select>
</div>
<div class="editor-option" ng-show="current.type === 'query'">
<label class="small">Datasource</label>
<select class="input input-medium" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select>
</div>
<editor-opt-bool text="Refresh on load" show-if="current.type === 'query'"
tip="Check if you want values to be updated on dashboard load, will slow down dashboard load time"
model="current.refresh"></editor-opt-bool>
</div>
<div ng-show="current.type === 'interval'">
<div class="editor-row">
<div class="editor-option">
<label class="small">Values</label>
<input type="text" class="input-xxlarge" ng-model='current.query' ng-blur="runQuery()" placeholder="name"></input>
<input type="text" class="input-large" ng-model='current.query' ng-blur="runQuery()" placeholder="name"></input>
</div>
</div>
<div class="editor-row">
<editor-opt-bool text="Include auto interval" model="current.auto" change="runQuery()"></editor-opt-bool>
<div class="editor-option" ng-show="current.auto">
<label class="small">Auto interval steps <tip>How many steps, roughly, the interval is rounded and will not always match this count<tip></label>
@ -102,6 +98,7 @@
</div>
<div ng-show="current.type === 'query'">
<h5>Values Query</h5>
<div class="editor-row">
<div class="editor-option form-inline">
<label class="small">Variable values query</label>
@ -119,6 +116,10 @@
</div>
<div class="editor-row" style="margin: 15px 0">
<editor-opt-bool text="Refresh on load" show-if="current.type === 'query'"
tip="Check if you want values to be updated on dashboard load, will slow down dashboard load time"
model="current.refresh"></editor-opt-bool>
<editor-opt-bool text="All option" model="current.includeAll" change="runQuery()"></editor-opt-bool>
<div class="editor-option" ng-show="current.includeAll">
<label class="small">All format</label>
@ -131,10 +132,29 @@
</div>
</div>
</div>
<div class="section">
<div class="section">
<h5>Display options</h5>
<div class="editor-option">
<div class="editor-row">
<label class="small">Variable label</label>
<input type="text" class="input-medium" ng-model='current.label' placeholder=""></input>
</div>
<editor-opt-bool text="Hide Label" model="current.hideLabel"></editor-opt-bool>
</div>
<div class="section">
<h5>Multi-value selection <tip>Enables multiple values to be selected at the same time</tip></h5>
<editor-opt-bool text="Enable" model="current.multi"></editor-opt-bool>
<div class="editor-option" ng-show="current.multi">
<label class="small">Multi value format</label>
<select class="input-medium" ng-model="current.multiFormat" ng-options="f for f in ['glob', 'regex values']"></select>
</div>
</div>
<div class="editor-row" style="margin: 15px 0">
<div class="editor-option" >
<label class="small">Variable values (showing 20/{{current.options.length}})</label>
<label class="small">Variable values (shows max 20)</label>
<ul class="grafana-options-list">
<li ng-repeat="option in current.options | limitTo: 20">
{{option.text}}
@ -145,8 +165,10 @@
</div>
</div>
<button type="button" class="btn btn-success" ng-show="editor.index === 2" ng-click="update();">Update</button>
<button type="button" class="btn btn-success" ng-show="editor.index === 1" ng-click="add();">Add</button>
</div>
</div>
<button type="button" class="btn btn-success pull-right" ng-show="editor.index === 2" ng-click="update();">Update</button>
<button type="button" class="btn btn-success pull-right" ng-show="editor.index === 1" ng-click="add();">Add</button>
<div class="clearfix"></div>
</div>
</div>

View File

@ -11,6 +11,11 @@ input[type="checkbox"].cr1 {
display: none;
}
.editor-option label.cr1 {
display: inline-block;
margin: 5px 0 1px 0;
}
label.cr1 {
display: inline-block;
height: 19px;

View File

@ -5,7 +5,7 @@
}
.submenu-controls {
margin: 20px 0px 15px 20px;
margin: 15px 0px 10px 13px;
}
.annotation-disabled, .annotation-disabled a {
@ -25,8 +25,8 @@
.variable-value-dropdown {
position: absolute;
top: 30px;
width: 300px;
top: 43px;
min-width: 200px;
height: 400px;
background: @grafanaPanelBackground;
box-shadow: 0px 0px 55px 0px black;

View File

@ -29,6 +29,34 @@ define([
});
});
describe('render variable to string values', function() {
it('single value should return value', function() {
var result = _templateSrv.renderVariableValue({current: {value: 'test'}});
expect(result).to.be('test');
});
it('multi value and glob format should render glob string', function() {
var result = _templateSrv.renderVariableValue({
multiFormat: 'glob',
current: {
value: ['test','test2'],
}
});
expect(result).to.be('{test,test2}');
});
it('multi value and regex format should render regex string', function() {
var result = _templateSrv.renderVariableValue({
multiFormat: 'regex values',
current: {
value: ['test','test2'],
}
});
expect(result).to.be('(test|test2)');
});
});
describe('can check if variable exists', function() {
beforeEach(function() {
_templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);