Allow negative values for custom ranges in metric and gauge visualizations (#33814)
* Fix inequality directives to handle negative values * Fix test
This commit is contained in:
parent
9d60ad3831
commit
b4bafa5ff6
|
@ -173,7 +173,7 @@
|
|||
type="number"
|
||||
class="form-control"
|
||||
name="range.from"
|
||||
greater-or-equal-than="{{getGreaterThan($index)}}"
|
||||
greater-or-equal-than="getGreaterThan($index)"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
|
@ -184,7 +184,7 @@
|
|||
type="number"
|
||||
class="form-control"
|
||||
name="range.to"
|
||||
greater-or-equal-than="{{range.from}}"
|
||||
greater-or-equal-than="range.from"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
|
|
|
@ -81,7 +81,7 @@ module.directive('gaugeOptions', function (i18n) {
|
|||
};
|
||||
|
||||
$scope.getGreaterThan = function (index) {
|
||||
if (index === 0) return 0;
|
||||
if (index === 0) return -Infinity;
|
||||
return $scope.editorState.params.gauge.colorsRange[index - 1].to;
|
||||
};
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
type="number"
|
||||
class="form-control"
|
||||
name="range.from"
|
||||
greater-or-equal-than="{{getGreaterThan($index)}}"
|
||||
greater-or-equal-than="getGreaterThan($index)"
|
||||
step="any" />
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -64,7 +64,7 @@ module.directive('heatmapOptions', function (i18n) {
|
|||
};
|
||||
|
||||
$scope.getGreaterThan = function (index) {
|
||||
if (index === 0) return;
|
||||
if (index === 0) return -Infinity;
|
||||
return $scope.editorState.params.colorsRange[index - 1].to;
|
||||
};
|
||||
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
class="kuiInput visEditorSidebar__input"
|
||||
type="number"
|
||||
step="0.1"
|
||||
greater-than="axis.scale.min"
|
||||
ng-model="axis.scale.max"
|
||||
>
|
||||
</div>
|
||||
|
@ -301,7 +302,8 @@
|
|||
class="kuiInput visEditorSidebar__input"
|
||||
type="number"
|
||||
step="0.1"
|
||||
greater-than="{{axis.scale.type === 'log' ? 0 : ''}}"
|
||||
greater-than="axis.scale.type === 'log' ? 0 : undefined"
|
||||
less-than="axis.scale.max"
|
||||
ng-model="axis.scale.min"
|
||||
>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
class="form-control"
|
||||
type="number"
|
||||
step="0.1"
|
||||
greater-than="{{editorState.params.yAxis.min}}"
|
||||
greater-than="editorState.params.yAxis.min"
|
||||
ng-model="editorState.params.yAxis.max"
|
||||
ng-required="editorState.params.setYExtents">
|
||||
</label>
|
||||
|
@ -30,8 +30,8 @@
|
|||
class="form-control"
|
||||
type="number"
|
||||
step="0.1"
|
||||
less-than="{{editorState.params.yAxis.max}}"
|
||||
greater-than="{{editorState.params.scale === 'log' ? 0 : ''}}"
|
||||
less-than="editorState.params.yAxis.max"
|
||||
greater-than="editorState.params.scale === 'log' ? 0 : undefined"
|
||||
ng-model="editorState.params.yAxis.min"
|
||||
ng-required="editorState.params.setYExtents">
|
||||
</label>
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
type="number"
|
||||
class="form-control"
|
||||
name="range.from"
|
||||
greater-or-equal-than="{{getGreaterThan($index)}}"
|
||||
greater-or-equal-than="getGreaterThan($index)"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
|
@ -89,7 +89,7 @@
|
|||
type="number"
|
||||
class="form-control"
|
||||
name="range.to"
|
||||
greater-or-equal-than="{{range.from}}"
|
||||
greater-or-equal-than="range.from"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
|
|
|
@ -55,7 +55,7 @@ module.directive('metricVisParams', function (i18n) {
|
|||
};
|
||||
|
||||
$scope.getGreaterThan = function (index) {
|
||||
if (index === 0) return 0;
|
||||
if (index === 0) return -Infinity;
|
||||
return $scope.editorState.params.metric.colorsRange[index - 1].to;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ describe('greater_than model validator directive', function () {
|
|||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
|
||||
// no value is the same as 0
|
||||
describe('without value', function () {
|
||||
let element;
|
||||
beforeEach(function () {
|
||||
|
@ -60,6 +59,33 @@ describe('greater_than model validator directive', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with string values', function () {
|
||||
let element;
|
||||
beforeEach(function () {
|
||||
html = `<input type="text" ng-model="value" greater-than="'10'" />`;
|
||||
element = $compile(html)($rootScope);
|
||||
});
|
||||
|
||||
it('should be valid for greater than 10', function () {
|
||||
$rootScope.value = '15';
|
||||
$rootScope.$digest();
|
||||
expect(element.hasClass('ng-valid')).to.be.ok();
|
||||
});
|
||||
|
||||
it('should be invalid for 10', function () {
|
||||
$rootScope.value = '10';
|
||||
$rootScope.$digest();
|
||||
expect(element.hasClass('ng-invalid')).to.be.ok();
|
||||
});
|
||||
|
||||
// Edge case because '5' > '10' as strings
|
||||
it('should be invalid less than 10', function () {
|
||||
$rootScope.value = '5';
|
||||
$rootScope.$digest();
|
||||
expect(element.hasClass('ng-invalid')).to.be.ok();
|
||||
});
|
||||
});
|
||||
|
||||
[0, 1, 10, 42, -12].forEach(function (num) {
|
||||
describe('with value ' + num, function () {
|
||||
let element;
|
||||
|
@ -85,7 +111,14 @@ describe('greater_than model validator directive', function () {
|
|||
$rootScope.$digest();
|
||||
expect(element.hasClass('ng-invalid')).to.be.ok();
|
||||
});
|
||||
|
||||
it('should be valid for empty model values', () => {
|
||||
[undefined, null, ''].forEach(val => {
|
||||
$rootScope.value = val;
|
||||
$rootScope.$digest();
|
||||
expect(element.hasClass('ng-valid')).to.be.ok();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -24,12 +24,7 @@ function makeDirectiveDef(id, compare) {
|
|||
return {
|
||||
require: 'ngModel',
|
||||
link: function ($scope, $el, $attr, ngModel) {
|
||||
const getBound = function () { return $parse($attr[id])(); };
|
||||
const defaultVal = {
|
||||
'greaterThan': -Infinity,
|
||||
'greaterOrEqualThan': -Infinity,
|
||||
'lessThan': Infinity
|
||||
}[id];
|
||||
const getBound = function () { return $parse($attr[id])($scope); };
|
||||
|
||||
ngModel.$parsers.push(validate);
|
||||
ngModel.$formatters.push(validate);
|
||||
|
@ -38,12 +33,20 @@ function makeDirectiveDef(id, compare) {
|
|||
validate(ngModel.$viewValue);
|
||||
});
|
||||
|
||||
// We only set it to invalid when both the model value and the value to compare against are
|
||||
// provided, and the values do not meet the condition.
|
||||
function validate(val) {
|
||||
const bound = !isNaN(getBound()) ? +getBound() : defaultVal;
|
||||
const valid = !isNaN(bound) && !isNaN(val) && compare(val, bound);
|
||||
ngModel.$setValidity(id, valid);
|
||||
const bound = getBound();
|
||||
const left = parseFloat(val);
|
||||
const right = parseFloat(bound);
|
||||
const isValid = isEmpty(val) || isEmpty(bound) || compare(left, right);
|
||||
ngModel.$setValidity(id, isValid);
|
||||
return val;
|
||||
}
|
||||
|
||||
function isEmpty(val) {
|
||||
return typeof val === 'undefined' || val === null || val === '';
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue