Skip to content

Commit 91a3acb

Browse files
author
Sebastian Florek
committed
Add kd-warn-threshold directive to show warning on input field when threshold is reached
1 parent 5128fbb commit 91a3acb

File tree

8 files changed

+384
-3
lines changed

8 files changed

+384
-3
lines changed

src/app/frontend/common/components/components_module.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import filtersModule from '../filters/filters_module';
1616
import labelsDirective from './labels/labels_directive';
1717
import middleEllipsisDirective from './middleellipsis/middleellipsis_directive';
1818
import sparklineDirective from './sparkline/sparkline_directive';
19+
import warnThresholdDirective from './warnthreshold/warnthreshold_directive';
1920

2021
/**
2122
* Module containing common components for the application.
@@ -29,4 +30,5 @@ export default angular
2930
])
3031
.directive('kdLabels', labelsDirective)
3132
.directive('kdMiddleEllipsis', middleEllipsisDirective)
32-
.directive('kdSparkline', sparklineDirective);
33+
.directive('kdSparkline', sparklineDirective)
34+
.directive('kdWarnThreshold', warnThresholdDirective);
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
const kdWarnThresholdAttr = 'kdWarnThreshold';
16+
export const hasWarningAttr = 'kdWarnThresholdBind';
17+
// CSS class that is added to input container when field value meets warning condition
18+
const kdWarningClass = 'kd-warning';
19+
20+
/**
21+
* Returns true if input number is larger than max allowed number provided as attribute and
22+
* there is no warning already set, false otherwise.
23+
*
24+
* @param {!angular.NgModelController} inputCtrl
25+
* @param {!angular.Attributes} attributes - directive attributes (have to contain kdWarnThreshold)
26+
* @return {boolean}
27+
*/
28+
export function shouldSetWarning(inputCtrl, attributes) {
29+
/** @type {number} */
30+
let number = parseInt(inputCtrl.$viewValue, 10);
31+
32+
return number > attributes[kdWarnThresholdAttr];
33+
}
34+
35+
/**
36+
* Returns true if input number is lower or equal to max allowed number provided as attribute
37+
* and there is still a warning set, false otherwise.
38+
*
39+
* @param {!angular.NgModelController} inputCtrl
40+
* @param {!angular.Attributes} attributes - directive attributes (have to contain kdWarnThreshold)
41+
* @param {!angular.Scope} scope
42+
* @return {boolean}
43+
*/
44+
export function shouldRemoveWarning(inputCtrl, attributes, scope) {
45+
return hasWarning(scope) && !shouldSetWarning(inputCtrl, attributes);
46+
}
47+
48+
/**
49+
* Sets warning attribute on input controller and adds kd-warning css class to input container.
50+
*
51+
* @param {!angular.JQLite} inputContainer
52+
* @param {!angular.Scope} scope
53+
*/
54+
export function setWarning(inputContainer, scope) {
55+
scope[hasWarningAttr] = true;
56+
inputContainer.addClass(kdWarningClass);
57+
}
58+
59+
/**
60+
* Removes warning attribute from input controller and removes kd-warning class from input
61+
* container.
62+
*
63+
* @param {!angular.JQLite} inputContainer
64+
* @param {!angular.Scope} scope
65+
*/
66+
export function removeWarning(inputContainer, scope) {
67+
scope[hasWarningAttr] = false;
68+
inputContainer.removeClass(kdWarningClass);
69+
}
70+
71+
/**
72+
* Returns true if kdWarnThreshold attribute is set to true on input controller, false otherwise.
73+
*
74+
* @param {!angular.Scope} scope
75+
* @return {boolean}
76+
*/
77+
function hasWarning(scope) {
78+
return scope[hasWarningAttr];
79+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@import '../../../variables';
16+
17+
input {
18+
// When there is other error on field hide warning
19+
&.ng-invalid {
20+
~ span {
21+
&.kd-warn-threshold {
22+
display: none;
23+
}
24+
}
25+
}
26+
27+
//When there are no errors on field show warning
28+
&.ng-valid {
29+
~ span {
30+
&.kd-warn-threshold {
31+
color: $warning;
32+
display: inherit;
33+
font-size: $caption-font-size-base;
34+
}
35+
}
36+
}
37+
}
38+
39+
md-input-container {
40+
&.kd-warning {
41+
// Color input container label when there are no errors
42+
&:not(.md-input-invalid) {
43+
label {
44+
color: $warning;
45+
}
46+
}
47+
48+
> input {
49+
// Color input bottom line when it's dirty and there are no errors
50+
&.ng-dirty {
51+
&:not(.ng-invalid) {
52+
border-color: $warning;
53+
}
54+
}
55+
}
56+
}
57+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import {shouldSetWarning, setWarning, shouldRemoveWarning, removeWarning} from './warnthreshold';
16+
import {hasWarningAttr} from './warnthreshold';
17+
18+
/**
19+
* Description:
20+
* Directive can be used to warn user that some number may be too big for given input field
21+
* but not block the actual form submit.
22+
*
23+
* Params:
24+
* - kdWarnThreshold - Max number that is allowed before input field will be marked with
25+
* a warning.
26+
* - kdWarnThresholdBind - boolean page scope variable that should be bound to directive. Warning
27+
* state change will be populated to this variable.
28+
*
29+
* Usage:
30+
* <md-input-container>
31+
* <input type="number" name="maxInput" kd-warn-threshold="100"
32+
* kd-warn-threshold-bind="showWarning">
33+
* <span class="kd-warn-threshold" ng-show="showWarning">Warning message</span>
34+
* </md-input-container>
35+
*
36+
* @return {!angular.Directive}
37+
*/
38+
export default function warnThresholdDirective() {
39+
return {
40+
restrict: 'A',
41+
require: ['^mdInputContainer', 'ngModel'],
42+
scope: {
43+
[hasWarningAttr]: '=',
44+
},
45+
/**
46+
* @param {!angular.Scope} scope
47+
* @param {!angular.JQLite} element
48+
* @param {!angular.Attributes} attrs
49+
* @param {!Array<!angular.NgModelController>} ctrl
50+
*/
51+
link: (scope, element, attrs, ctrl) => {
52+
/** @type {!angular.JQLite} - MdInputContainer element */
53+
let inputContainer = element.parent();
54+
/** @type {!angular.NgModelController} */
55+
let inputCtrl = ctrl[1];
56+
57+
inputCtrl.$viewChangeListeners.push(() => {
58+
if (shouldSetWarning(inputCtrl, attrs)) {
59+
setWarning(inputContainer, scope);
60+
}
61+
62+
if (shouldRemoveWarning(inputCtrl, attrs, scope)) {
63+
removeWarning(inputContainer, scope);
64+
}
65+
});
66+
},
67+
};
68+
}

src/app/frontend/deploy/deployfromsettings.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,15 @@
7777
<md-input-container class="md-block">
7878
<label>Number of pods</label>
7979
<input ng-model="ctrl.replicas" type="number" required min="1" name="replicas"
80-
kd-validate="integer">
80+
kd-validate="integer" kd-warn-threshold="100" kd-warn-threshold-bind="showWarning">
8181
<ng-messages for="ctrl.form.replicas.$error" role="alert" multiple>
8282
<ng-message when="required">Number of pods is required.</ng-message>
8383
<ng-message when="number, kdValid">Number of pods must be a positive integer.</ng-message>
8484
<ng-message when="min">Number of pods must be at least 1.</ng-message>
8585
</ng-messages>
86+
<span class="kd-warn-threshold" ng-show="showWarning">
87+
Setting high number of pods may cause performance issues of the cluster and Dashboard UI.
88+
</span>
8689
</md-input-container>
8790
<kd-user-help>
8891
A Replication Controller will be created to maintain the desired number of pods across your

src/app/frontend/replicationcontrollerdetail/updatereplicas.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ <h4 class="md-title">Set desired number of pods</h4>
2828
<md-input-container class="md-block">
2929
<label>Number of pods</label>
3030
<input name="podCount" type="number" kd-validate="integer" min="1" ng-model="ctrl.replicas"
31-
required>
31+
required kd-warn-threshold="100" kd-warn-threshold-bind="showWarning">
3232
<ng-messages for="ctrl.updateReplicasForm.podCount.$error" role="alert">
3333
<ng-message when="required">Number of pods is required.</ng-message>
3434
<ng-message when="number,kdValid">Must be a positive integer.</ng-message>
3535
</ng-messages>
36+
<span class="kd-warn-threshold" ng-show="showWarning">
37+
Setting high number of pods may cause performance issues of the cluster and Dashboard UI.
38+
</span>
3639
</md-input-container>
3740
<md-dialog-actions layout="row">
3841
<md-button class="md-primary" ng-click="ctrl.cancel()">Cancel</md-button>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import componentsModule from 'common/components/components_module';
16+
17+
describe('Warn threshold directive', () => {
18+
/** @type {!angular.Scope} */
19+
let scope;
20+
/** @type {function(!angular.Scope):!angular.JQLite} */
21+
let compileFn;
22+
23+
beforeEach(() => {
24+
angular.mock.module(componentsModule.name);
25+
26+
angular.mock.inject(($rootScope, $compile) => {
27+
scope = $rootScope.$new();
28+
compileFn = $compile(
29+
'<form name="inputForm">' +
30+
'<md-input-container>' +
31+
'<input type="number" ng-model="maxInput" name="inputField" kd-warn-threshold="100"' +
32+
'kd-warn-threshold-bind="showWarning">' +
33+
'<span class="kd-warn-threshold" ng-show="showWarning">Error</span>' +
34+
'</md-input-container>' +
35+
'</form>');
36+
});
37+
});
38+
39+
it('should show warning when threshold is breached', () => {
40+
// given
41+
let element = compileFn(scope);
42+
let inputContainer = element.find('md-input-container')[0];
43+
let errMessageElement = element.find('span')[0];
44+
let inputValue = 101;
45+
46+
// when
47+
scope.inputForm.inputField.$setViewValue(inputValue);
48+
scope.$digest();
49+
50+
// then
51+
expect(inputContainer.classList).toContain('kd-warning');
52+
expect(errMessageElement.classList).not.toContain('ng-hide');
53+
});
54+
55+
it('should remove warning when value has been changed to lower than threshold', () => {
56+
let element = compileFn(scope);
57+
let inputContainer = element.find('md-input-container')[0];
58+
let errMessageElement = element.find('span')[0];
59+
60+
scope.inputForm.inputField.$setViewValue(105);
61+
scope.$digest();
62+
63+
expect(inputContainer.classList).toContain('kd-warning');
64+
expect(errMessageElement.classList).not.toContain('ng-hide');
65+
66+
scope.inputForm.inputField.$setViewValue(100);
67+
scope.$digest();
68+
69+
expect(inputContainer.classList).not.toContain('kd-warning');
70+
expect(errMessageElement.classList).toContain('ng-hide');
71+
});
72+
});

0 commit comments

Comments
 (0)