mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
more work on multi select
This commit is contained in:
parent
0d817e0664
commit
35888c814c
@ -91,25 +91,84 @@ function (angular, app, _, $) {
|
|||||||
return {
|
return {
|
||||||
scope: {
|
scope: {
|
||||||
variable: "=",
|
variable: "=",
|
||||||
|
onUpdated: "&"
|
||||||
},
|
},
|
||||||
templateUrl: 'app/features/dashboard/partials/variableValueSelect.html',
|
templateUrl: 'app/features/dashboard/partials/variableValueSelect.html',
|
||||||
link: function(scope, elem) {
|
link: function(scope, elem) {
|
||||||
var bodyEl = angular.element($window.document.body);
|
var bodyEl = angular.element($window.document.body);
|
||||||
|
var variable = scope.variable;
|
||||||
|
|
||||||
scope.show = function() {
|
scope.show = function() {
|
||||||
scope.selectorOpen = true;
|
scope.selectorOpen = true;
|
||||||
scope.giveFocus = 1;
|
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() {
|
$timeout(function() {
|
||||||
bodyEl.on('click', scope.bodyOnClick);
|
bodyEl.on('click', scope.bodyOnClick);
|
||||||
}, 0, false);
|
}, 0, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.hide = function() {
|
scope.optionSelected = function(option) {
|
||||||
scope.selectorOpen = false;
|
if (!variable.multi) {
|
||||||
bodyEl.off('click', scope.bodyOnClick);
|
_.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) {
|
scope.bodyOnClick = function(e) {
|
||||||
var dropdown = elem.find('.variable-value-dropdown');
|
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();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<a ng-click="show()" class="variable-value-link">
|
<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>
|
</a>
|
||||||
|
|
||||||
<div ng-if="selectorOpen" class="variable-value-dropdown">
|
<div ng-if="selectorOpen" class="variable-value-dropdown">
|
||||||
@ -11,9 +12,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="variable-options-container" ng-if="!query.tagcloud">
|
<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}}">
|
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="cr1"></label>
|
||||||
<label for="var.option.{{$id}}" class="checkbox-label">{{option.text}}</label>
|
<label for="var.option.{{$id}}" class="checkbox-label">{{option.text}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,8 +26,10 @@ function (angular, _) {
|
|||||||
$rootScope.$broadcast('refresh');
|
$rootScope.$broadcast('refresh');
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.setVariableValue = function(param, option) {
|
$scope.variableUpdated = function(variable) {
|
||||||
templateValuesSrv.setVariableValue(param, option);
|
templateValuesSrv.variableUpdated(variable).then(function() {
|
||||||
|
$rootScope.$broadcast('refresh');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
@ -17,6 +17,8 @@ function (angular, _) {
|
|||||||
options: [],
|
options: [],
|
||||||
includeAll: false,
|
includeAll: false,
|
||||||
allFormat: 'glob',
|
allFormat: 'glob',
|
||||||
|
multi: false,
|
||||||
|
multiFormat: 'glob',
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
@ -75,7 +77,7 @@ function (angular, _) {
|
|||||||
if ($scope.current.datasource === void 0) {
|
if ($scope.current.datasource === void 0) {
|
||||||
$scope.current.datasource = null;
|
$scope.current.datasource = null;
|
||||||
$scope.current.type = 'query';
|
$scope.current.type = 'query';
|
||||||
$scope.current.allFormat = 'Glob';
|
$scope.current.allFormat = 'glob';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,11 +29,23 @@ function (angular, _) {
|
|||||||
_.each(this.variables, function(variable) {
|
_.each(this.variables, function(variable) {
|
||||||
if (!variable.current || !variable.current.value) { return; }
|
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._texts[variable.name] = variable.current.text;
|
||||||
}, this);
|
}, 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.setGrafanaVariable = function (name, value) {
|
||||||
this._grafanaVariables[name] = value;
|
this._grafanaVariables[name] = value;
|
||||||
};
|
};
|
||||||
|
@ -73,6 +73,11 @@ function (angular, _, kbn) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.variableUpdated = function(variable) {
|
||||||
|
templateSrv.updateTemplateData();
|
||||||
|
return this.updateOptionsInChildVariables(variable);
|
||||||
|
};
|
||||||
|
|
||||||
this.updateOptionsInChildVariables = function(updatedVariable) {
|
this.updateOptionsInChildVariables = function(updatedVariable) {
|
||||||
var promises = _.map(self.variables, function(otherVariable) {
|
var promises = _.map(self.variables, function(otherVariable) {
|
||||||
if (otherVariable === updatedVariable) {
|
if (otherVariable === updatedVariable) {
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<div class="submenu-controls" ng-controller="SubmenuCtrl">
|
<div class="submenu-controls" ng-controller="SubmenuCtrl">
|
||||||
<div class="tight-form borderless">
|
<div class="tight-form borderless">
|
||||||
|
|
||||||
|
|
||||||
<ul class="tight-form-list" ng-if="dashboard.templating.list.length > 0">
|
<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">
|
<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>
|
||||||
|
|
||||||
<!-- <li class="dropdown" ng-repeat-end> -->
|
<!-- <li class="dropdown" ng-repeat-end> -->
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
{{variable.query}}
|
{{variable.query}}
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1%">
|
<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>
|
<i class="fa fa-edit"></i>
|
||||||
Edit
|
Edit
|
||||||
</a>
|
</a>
|
||||||
@ -56,7 +56,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)">
|
<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-row">
|
||||||
<div class="editor-option">
|
<div class="editor-option">
|
||||||
<label class="small">Variable name</label>
|
<label class="small">Variable name</label>
|
||||||
@ -64,26 +66,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="editor-option">
|
<div class="editor-option">
|
||||||
<label class="small">Type</label>
|
<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>
|
||||||
<div class="editor-option" ng-show="current.type === 'query'">
|
<div class="editor-option" ng-show="current.type === 'query'">
|
||||||
<label class="small">Datasource</label>
|
<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>
|
<select class="input input-medium" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div ng-show="current.type === 'interval'">
|
<div ng-show="current.type === 'interval'">
|
||||||
<div class="editor-row">
|
<div class="editor-row">
|
||||||
<div class="editor-option">
|
<div class="editor-option">
|
||||||
<label class="small">Values</label>
|
<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>
|
|
||||||
<div class="editor-row">
|
|
||||||
<editor-opt-bool text="Include auto interval" model="current.auto" change="runQuery()"></editor-opt-bool>
|
<editor-opt-bool text="Include auto interval" model="current.auto" change="runQuery()"></editor-opt-bool>
|
||||||
<div class="editor-option" ng-show="current.auto">
|
<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>
|
<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>
|
||||||
|
|
||||||
<div ng-show="current.type === 'query'">
|
<div ng-show="current.type === 'query'">
|
||||||
|
<h5>Values Query</h5>
|
||||||
<div class="editor-row">
|
<div class="editor-row">
|
||||||
<div class="editor-option form-inline">
|
<div class="editor-option form-inline">
|
||||||
<label class="small">Variable values query</label>
|
<label class="small">Variable values query</label>
|
||||||
@ -119,6 +116,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-row" style="margin: 15px 0">
|
<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>
|
<editor-opt-bool text="All option" model="current.includeAll" change="runQuery()"></editor-opt-bool>
|
||||||
<div class="editor-option" ng-show="current.includeAll">
|
<div class="editor-option" ng-show="current.includeAll">
|
||||||
<label class="small">All format</label>
|
<label class="small">All format</label>
|
||||||
@ -131,10 +132,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section">
|
||||||
|
<h5>Display options</h5>
|
||||||
<div class="editor-option">
|
<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" >
|
<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">
|
<ul class="grafana-options-list">
|
||||||
<li ng-repeat="option in current.options | limitTo: 20">
|
<li ng-repeat="option in current.options | limitTo: 20">
|
||||||
{{option.text}}
|
{{option.text}}
|
||||||
@ -145,8 +165,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 pull-right" 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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -11,6 +11,11 @@ input[type="checkbox"].cr1 {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-option label.cr1 {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 5px 0 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
label.cr1 {
|
label.cr1 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.submenu-controls {
|
.submenu-controls {
|
||||||
margin: 20px 0px 15px 20px;
|
margin: 15px 0px 10px 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotation-disabled, .annotation-disabled a {
|
.annotation-disabled, .annotation-disabled a {
|
||||||
@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
.variable-value-dropdown {
|
.variable-value-dropdown {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 30px;
|
top: 43px;
|
||||||
width: 300px;
|
min-width: 200px;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
background: @grafanaPanelBackground;
|
background: @grafanaPanelBackground;
|
||||||
box-shadow: 0px 0px 55px 0px black;
|
box-shadow: 0px 0px 55px 0px black;
|
||||||
|
@ -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() {
|
describe('can check if variable exists', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
_templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);
|
_templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);
|
||||||
|
Loading…
Reference in New Issue
Block a user