Merge branch 'master' of github.com:grafana/grafana
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
* **Admin**: Admin can now have global overview of Grafana setup, closes [#3812](https://github.com/grafana/grafana/issues/3812)
|
||||
* **graph**: Right side legend height is now fixed at row height, closes [#1277](https://github.com/grafana/grafana/issues/1277)
|
||||
* **Table**: All content in table panel is now html escaped, closes [#3673](https://github.com/grafana/grafana/issues/3673)
|
||||
* **graph**: Template variables can now be used in TimeShift and TimeFrom, closes[#1960](https://github.com/grafana/grafana/issues/1960)
|
||||
|
||||
### Bug fixes
|
||||
* **Playlist**: Fix for memory leak when running a playlist, closes [#3794](https://github.com/grafana/grafana/pull/3794)
|
||||
|
||||
+3
-2
@@ -43,8 +43,9 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
|
||||
r.Get("/admin/stats", reqGrafanaAdmin, Index)
|
||||
|
||||
r.Get("/apps", reqSignedIn, Index)
|
||||
r.Get("/apps/edit/*", reqSignedIn, Index)
|
||||
r.Get("/plugins", reqSignedIn, Index)
|
||||
r.Get("/plugins/:id/edit", reqSignedIn, Index)
|
||||
r.Get("/plugins/:id/page/:page", reqSignedIn, Index)
|
||||
|
||||
r.Get("/dashboard/*", reqSignedIn, Index)
|
||||
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
||||
|
||||
+2
-2
@@ -85,13 +85,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
||||
if plugin.Pinned {
|
||||
pageLink := &dtos.NavLink{
|
||||
Text: plugin.Name,
|
||||
Url: setting.AppSubUrl + "/apps/" + plugin.Id + "/edit",
|
||||
Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit",
|
||||
Img: plugin.Info.Logos.Small,
|
||||
}
|
||||
|
||||
for _, page := range plugin.Pages {
|
||||
pageLink.Children = append(pageLink.Children, &dtos.NavLink{
|
||||
Url: setting.AppSubUrl + "/apps/" + plugin.Id + "/page/" + page.Slug,
|
||||
Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/page/" + page.Slug,
|
||||
Text: page.Name,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ function (coreModule, kbn, rangeUtil) {
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
return true;
|
||||
}
|
||||
if (viewValue.indexOf('$') === 0) {
|
||||
return true; // allow template variable
|
||||
}
|
||||
var info = rangeUtil.describeTextRange(viewValue);
|
||||
return info.invalid !== true;
|
||||
};
|
||||
|
||||
@@ -140,7 +140,11 @@ function (angular, $, _, moment) {
|
||||
};
|
||||
|
||||
p.isSubmenuFeaturesEnabled = function() {
|
||||
return this.templating.list.length > 0 || this.annotations.list.length > 0 || this.links.length > 0;
|
||||
var visableTemplates = _.filter(this.templating.list, function(template) {
|
||||
return template.hideVariable === undefined || template.hideVariable === false;
|
||||
});
|
||||
|
||||
return visableTemplates.length > 0 || this.annotations.list.length > 0 || this.links.length > 0;
|
||||
};
|
||||
|
||||
p.getPanelInfoById = function(panelId) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="submenu-controls">
|
||||
<ul ng-if="ctrl.dashboard.templating.list.length > 0">
|
||||
<li ng-repeat="variable in ctrl.variables" class="submenu-item">
|
||||
<li ng-repeat="variable in ctrl.variables" ng-show="!variable.hideVariable" class="submenu-item">
|
||||
<span class="submenu-item-label template-variable " ng-show="!variable.hideLabel">
|
||||
{{variable.label || variable.name}}:
|
||||
</span>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th><strong>name</strong></th>
|
||||
<th><strong>type</strong></th>
|
||||
<th><strong>url</strong></th>
|
||||
<th style="width: 60px;"></th>
|
||||
<th style="width: 85px;"></th>
|
||||
@@ -37,7 +38,10 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="ellipsis">{{ds.url}}</span>
|
||||
<span>{{ds.type}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{ds.url}}</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span ng-if="ds.isDefault">
|
||||
|
||||
@@ -17,6 +17,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
$timeout: any;
|
||||
datasourceSrv: any;
|
||||
timeSrv: any;
|
||||
templateSrv: any;
|
||||
timing: any;
|
||||
range: any;
|
||||
rangeRaw: any;
|
||||
@@ -34,6 +35,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
this.$q = $injector.get('$q');
|
||||
this.datasourceSrv = $injector.get('datasourceSrv');
|
||||
this.timeSrv = $injector.get('timeSrv');
|
||||
this.templateSrv = $injector.get('templateSrv');
|
||||
|
||||
if (!this.panel.targets) {
|
||||
this.panel.targets = [{}];
|
||||
@@ -119,7 +121,8 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
|
||||
// check panel time overrrides
|
||||
if (this.panel.timeFrom) {
|
||||
var timeFromInfo = rangeUtil.describeTextRange(this.panel.timeFrom);
|
||||
var timeFromInterpolated = this.templateSrv.replace(this.panel.timeFrom, this.panel.scopedVars);
|
||||
var timeFromInfo = rangeUtil.describeTextRange(timeFromInterpolated);
|
||||
if (timeFromInfo.invalid) {
|
||||
this.timeInfo = 'invalid time override';
|
||||
return;
|
||||
@@ -136,13 +139,14 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
}
|
||||
|
||||
if (this.panel.timeShift) {
|
||||
var timeShiftInfo = rangeUtil.describeTextRange(this.panel.timeShift);
|
||||
var timeShiftInterpolated = this.templateSrv.replace(this.panel.timeShift, this.panel.scopedVars);
|
||||
var timeShiftInfo = rangeUtil.describeTextRange(timeShiftInterpolated);
|
||||
if (timeShiftInfo.invalid) {
|
||||
this.timeInfo = 'invalid timeshift';
|
||||
return;
|
||||
}
|
||||
|
||||
var timeShift = '-' + this.panel.timeShift;
|
||||
var timeShift = '-' + timeShiftInterpolated;
|
||||
this.timeInfo += ' timeshift ' + timeShift;
|
||||
this.range.from = dateMath.parseDateMath(timeShift, this.range.from, false);
|
||||
this.range.to = dateMath.parseDateMath(timeShift, this.range.to, true);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<navbar icon="icon-gf icon-gf-apps" title="{{ctrl.appModel.name}}" title-url="apps/{{ctrl.pluginId}}/edit">
|
||||
<navbar icon="icon-gf icon-gf-apps" title="{{ctrl.appModel.name}}" title-url="plugins/{{ctrl.pluginId}}/edit">
|
||||
</navbar>
|
||||
|
||||
<div class="page-container">
|
||||
|
||||
@@ -91,11 +91,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Label</span>
|
||||
<input type="text" class="gf-form-input max-width-14" ng-model='current.label' placeholder="optional display name"></input>
|
||||
<editor-checkbox class="width-13" text="Hide label" model="current.hideLabel" change="runQuery()"></editor-checkbox>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-7">Label</span>
|
||||
<input type="text" class="gf-form-input max-width-14" ng-model='current.label' placeholder="optional display name"></input>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<editor-checkbox class="width-10" text="Hide label" model="current.hideLabel" change="runQuery()"></editor-checkbox>
|
||||
<editor-checkbox class="width-11" text="Hide variable" model="current.hideVariable" change="runQuery()"></editor-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h5 class="section-heading">Value Options</h5>
|
||||
|
||||
@@ -167,13 +167,13 @@
|
||||
<i class="fa fa-remove pointer" ng-click="ctrl.removeValueMap(map)"></i>
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" ng-model="ctrl.map.value" placeholder="value" class="input-mini tight-form-input" ng-blur="ctrl.render()">
|
||||
<input type="text" ng-model="map.value" placeholder="value" class="input-mini tight-form-input" ng-blur="ctrl.render()">
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-arrow-right"></i>
|
||||
</li>
|
||||
<li ng-repeat-end>
|
||||
<input type="text" placeholder="text" ng-model="ctrl.map.text" class="input-mini tight-form-input" ng-blur="ctrl.render()">
|
||||
<input type="text" placeholder="text" ng-model="map.text" class="input-mini tight-form-input" ng-blur="ctrl.render()">
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
@@ -50,7 +50,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
unitFormats: any[];
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, $injector, private $location, private linkSrv, private templateSrv) {
|
||||
constructor($scope, $injector, private $location, private linkSrv) {
|
||||
super($scope, $injector);
|
||||
_.defaults(this.panel, panelDefaults);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
||||
|
||||
// value/number to text mapping
|
||||
var value = parseFloat(map.value);
|
||||
if (value === data.value) {
|
||||
if (value === data.valueRounded) {
|
||||
data.valueFormated = map.text;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,14 +69,20 @@ describe('SingleStatCtrl', function() {
|
||||
|
||||
singleStatScenario('When value to text mapping is specified', function(ctx) {
|
||||
ctx.setup(function() {
|
||||
ctx.datapoints = [[10,1]];
|
||||
ctx.datapoints = [[9.9,1]];
|
||||
ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}];
|
||||
});
|
||||
|
||||
it('Should replace value with text', function() {
|
||||
expect(ctx.data.value).to.be(10);
|
||||
expect(ctx.data.valueFormated).to.be('OK');
|
||||
it('value should remain', function() {
|
||||
expect(ctx.data.value).to.be(9.9);
|
||||
});
|
||||
|
||||
it('round should be rounded up', function() {
|
||||
expect(ctx.data.valueRounded).to.be(10);
|
||||
});
|
||||
|
||||
it('Should replace value with text', function() {
|
||||
expect(ctx.data.valueFormated).to.be('OK');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user