Merge ~ya-bo-ng/maas:error-requesting-more-storage into maas:master

Proposed by Anthony Dillon
Status: Merged
Approved by: Anthony Dillon
Approved revision: 40e385f8b6d0eedf76f66444b3a22ef210db2385
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ya-bo-ng/maas:error-requesting-more-storage
Merge into: maas:master
Diff against target: 230 lines (+99/-13)
6 files modified
src/maasserver/static/js/angular/controllers/pod_details.js (+31/-2)
src/maasserver/static/js/angular/controllers/tests/test_pod_details.js (+24/-0)
src/maasserver/static/partials/pod-details.html (+21/-7)
src/maasserver/static/scss/_patterns_charts.scss (+3/-3)
src/maasserver/static/scss/_patterns_forms.scss (+6/-0)
src/maasserver/static/scss/_patterns_option-selector.scss (+14/-1)
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Kit Randel (community) Approve
Caleb Ellis (community) Needs Information
Review via email: mp+355743@code.launchpad.net

Commit message

Highlight storage pools in the compose selection that cannot fulfil the request

Description of the change

Updated the styling of storage pools in the compose machine panel of the pod section. If the requested storage is over the free storage available it is clear with a notification.

To post a comment you must log in.
Revision history for this message
Caleb Ellis (caleb-ellis) wrote :

Does it make sense for storage pools without enough space to still be clickable?

review: Needs Information
Revision history for this message
Kit Randel (blr) wrote :

Seems a little odd to have so much logic in a template, can these expressions be moved to functions on the controller?

Revision history for this message
Blake Rouse (blake-rouse) :
review: Needs Fixing
Revision history for this message
Kit Randel (blr) wrote :

That looks much better, thanks for the tests and moving some of that logic out of the template. A few comments inline for your consideration.

review: Approve
Revision history for this message
Anthony Dillon (ya-bo-ng) wrote :

Kit, thanks for the comments. Good points. I have actioned them.

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good, thanks for the fixes. Just a typo comment below.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :
40e385f... by Anthony Dillon

Fix lint

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/static/js/angular/controllers/pod_details.js b/src/maasserver/static/js/angular/controllers/pod_details.js
2index b347b5a..82220ef 100644
3--- a/src/maasserver/static/js/angular/controllers/pod_details.js
4+++ b/src/maasserver/static/js/angular/controllers/pod_details.js
5@@ -226,6 +226,33 @@ angular.module('MAAS').controller('PodDetailsController', [
6 iface.showOptions = true;
7 }
8
9+ $scope.validateMachineCompose = function() {
10+ var pools = $scope.compose.obj.storage;
11+ var valid = true;
12+ pools.forEach(function(pool) {
13+ var requested = pool.size * 1000000000;
14+ if (requested > pool.pool.available || pool.size === '') {
15+ valid = false;
16+ }
17+ });
18+ return valid;
19+ };
20+
21+ $scope.totalStoragePercentage = function(storage_pool, storage) {
22+ var used = storage_pool.used / storage_pool.total * 100;
23+ var requested = storage / storage_pool.total * 100;
24+ var percent = used + requested;
25+ return percent;
26+ };
27+
28+ // Prevents key input if input is not a number key code.
29+ $scope.numberOnly = function(evt) {
30+ var charCode = (evt.which) ? evt.which : event.keyCode;
31+ if (charCode > 31 && (charCode < 48 || charCode > 57)) {
32+ evt.preventDefault();
33+ }
34+ };
35+
36 $scope.openOptions = function(storage) {
37 angular.forEach($scope.compose.obj.storage, function(disk) {
38 disk.showOptions = false;
39@@ -244,8 +271,10 @@ angular.module('MAAS').controller('PodDetailsController', [
40 };
41
42
43- $scope.selectStoragePool = function(storagePool, storage) {
44- storage.pool = storagePool;
45+ $scope.selectStoragePool = function(storagePool, storage, isDisabled) {
46+ if (!isDisabled) {
47+ storage.pool = storagePool;
48+ }
49 };
50
51 // Return the title of the pod type.
52diff --git a/src/maasserver/static/js/angular/controllers/tests/test_pod_details.js b/src/maasserver/static/js/angular/controllers/tests/test_pod_details.js
53index 028db4c..62c1edc 100644
54--- a/src/maasserver/static/js/angular/controllers/tests/test_pod_details.js
55+++ b/src/maasserver/static/js/angular/controllers/tests/test_pod_details.js
56@@ -566,6 +566,30 @@ describe("PodDetailsController", function() {
57 });
58 });
59
60+ describe("totalStoragePercentage", function() {
61+ it("returns the correct percentage", function() {
62+ var controller = makeController();
63+ var storage_pool = {
64+ 'used': 40,
65+ 'total': 100
66+ }
67+ var storage = 10;
68+ expect($scope.totalStoragePercentage(
69+ storage_pool, storage)).toBe(50);
70+ });
71+
72+ it("returns the over committed percentage", function() {
73+ var controller = makeController();
74+ var storage_pool = {
75+ 'used': 90,
76+ 'total': 100
77+ }
78+ var storage = 60;
79+ expect($scope.totalStoragePercentage(
80+ storage_pool, storage)).toBe(150);
81+ });
82+ });
83+
84 describe("canCompose", function() {
85
86 it("returns false when no pod", function() {
87diff --git a/src/maasserver/static/partials/pod-details.html b/src/maasserver/static/partials/pod-details.html
88index b3a2d51..e7bd7f3 100644
89--- a/src/maasserver/static/partials/pod-details.html
90+++ b/src/maasserver/static/partials/pod-details.html
91@@ -209,7 +209,9 @@
92 </td>
93 <td>
94 <div class="form__group-input">
95- <input type="text" class="u-no-margin--bottom" placeholder="Enter capacity" data-ng-model="storage.size">
96+ <input type="text" class="u-no-margin--bottom" placeholder="Enter capacity" ng-keypress="numberOnly($event)"
97+ data-ng-model="storage.size"
98+ ng-class="{'in-warning': storage.size == ''}">
99 </div>
100 </td>
101 <td style="overflow: visible">
102@@ -221,7 +223,12 @@
103 </select>
104 <div class="form__group-input" ng-if="pod.type === 'virsh'">
105 <div class="p-option-selector" tabindex="0">
106- <input class="p-option-selector__input u-no-margin--bottom" type="text" data-ng-model="storage.pool.name" ng-focus="openOptions(storage)">
107+ <input class="p-option-selector__input u-no-margin--bottom" readonly type="text" data-ng-model="storage.pool.name" ng-focus="openOptions(storage)"
108+ ng-class="{'in-warning': (storage.size | convertGigabyteToBytes) > storage.pool.available}">
109+
110+ <p class="u-no-margin--bottom" ng-if="(storage.size | convertGigabyteToBytes) > storage.pool.available">
111+ <small class-"u-no-margin--bottom"><strong>Warning</strong>: Not enough space in {$ storage.pool.name $}, only {$ storage.pool.available | formatBytes $} free.</small>
112+ </p>
113 <div class="p-option-selector__options" ng-if="storage.showOptions" ng-keyup="$event.keyCode == 27 ? closeOptions(storage) : null">
114 <button class="p-button--base u-float--left" ng-click="closeOptions(storage)">
115 <i class="p-icon--close">Close</i>
116@@ -240,7 +247,10 @@
117 <hr class="u-no-margin--bottom">
118 <div class="p-option-selector__option"
119 tabindex="0"
120- ng-repeat="storage_pool in pod.storage_pools" ng-click="selectStoragePool(storage_pool, storage)" ng-keyup="$event.keyCode == 13 ? selectStoragePool(storage_pool, storage) : null" ng-class="{'is-selected': storage.pool === storage_pool}">
121+ ng-repeat="storage_pool in pod.storage_pools"
122+ ng-click="selectStoragePool(storage_pool, storage, totalStoragePercentage(storage_pool, storage.size | convertGigabyteToBytes) >= 100)"
123+ ng-keyup="$event.keyCode == 13 ? selectStoragePool(storage_pool, storage) : null"
124+ ng-class="{'is-selected': storage.pool === storage_pool, 'is-over': totalStoragePercentage(storage_pool, storage.size | convertGigabyteToBytes) >= 100}">
125 <div class="p-option-selector__option-cell">
126 <div><strong>{$ storage_pool.name $} <span data-ng-if="pod.default_storage_pool == storage_pool.id">(default)</span></strong></div>
127 <div class="u-text--light">{$ storage_pool.path $}</div>
128@@ -251,12 +261,12 @@
129 </div>
130 <div class="p-option-selector__option-cell">
131 <div class="p-chart">
132- <div class="p-chart__bar--requests" style="width: {$ (storage_pool.used / storage_pool.total * 100) + ((storage.size | convertGigabyteToBytes) / storage_pool.total * 100) $}%"
133- ng-class="{'is-over': (storage_pool.used / storage_pool.total * 100) + ((storage.size | convertGigabyteToBytes) / storage_pool.total * 100) >= 100}"></div>
134+ <div class="p-chart__bar--requests" style="width: {$ totalStoragePercentage(storage_pool, storage.size | convertGigabyteToBytes) $}%"></div>
135 <div class="p-chart__bar--used" style="width: {$ storage_pool.used / storage_pool.total * 100 $}%"></div>
136 </div>
137
138- <ul class="p-inline-list u-no-margin--bottom p-space-between">
139+ <ul class="p-inline-list u-no-margin--bottom p-space-between"
140+ ng-if="totalStoragePercentage(storage_pool, storage.size | convertGigabyteToBytes) < 100">
141 <li class="p-inline-list__item">
142 <span class="p-key-icon--used"></span>
143 {$ storage_pool.used | formatBytes $}
144@@ -270,6 +280,10 @@
145 {$ storage_pool.available | formatBytes $}
146 </li>
147 </ul>
148+
149+ <small class="u-no-margin--bottom" ng-if="totalStoragePercentage(storage_pool, storage.size | convertGigabyteToBytes) >= 100">
150+ <i class="p-icon--warning">Warning</i> Not enough space. {$ storage_pool.available | formatBytes $} free.
151+ </small>
152 </div>
153 </div>
154 </div>
155@@ -309,7 +323,7 @@
156 <p maas-obj-show-saving><maas-obj-saving>Composing machine</maas-obj-saving></p>
157 <div class="u-align--right u-no-margin--top" maas-obj-hide-saving>
158 <button class="p-button--base" type="button" data-ng-click="cancelCompose()">Cancel</button>
159- <button class="p-button--positive u-no-margin--top" maas-obj-save>Compose machine</button>
160+ <button class="p-button--positive u-no-margin--top" maas-obj-save ng-disabled="!validateMachineCompose()">Compose machine</button>
161 </div>
162 </div>
163 </div>
164diff --git a/src/maasserver/static/scss/_patterns_charts.scss b/src/maasserver/static/scss/_patterns_charts.scss
165index 2f391ac..cf86b82 100644
166--- a/src/maasserver/static/scss/_patterns_charts.scss
167+++ b/src/maasserver/static/scss/_patterns_charts.scss
168@@ -32,9 +32,9 @@
169 .p-chart__bar--requests {
170 @extend .p-chart__bar;
171 background-color: #3a77af;
172+ }
173
174- &.is-over {
175- background-color: #ff8936;
176- }
177+ .is-over .p-chart__bar--requests {
178+ background-color: #ff8936;
179 }
180 }
181diff --git a/src/maasserver/static/scss/_patterns_forms.scss b/src/maasserver/static/scss/_patterns_forms.scss
182index bed4c9a..2f39ca2 100644
183--- a/src/maasserver/static/scss/_patterns_forms.scss
184+++ b/src/maasserver/static/scss/_patterns_forms.scss
185@@ -7,6 +7,12 @@
186 .p-form__group {
187 @extend %vf-clearfix;
188 }
189+
190+ .form__group-input {
191+ input.in-warning {
192+ border-color: $color-caution !important;
193+ }
194+ }
195 }
196
197 @mixin maas-p-form-stacked {
198diff --git a/src/maasserver/static/scss/_patterns_option-selector.scss b/src/maasserver/static/scss/_patterns_option-selector.scss
199index 233229a..5d7d789 100644
200--- a/src/maasserver/static/scss/_patterns_option-selector.scss
201+++ b/src/maasserver/static/scss/_patterns_option-selector.scss
202@@ -5,7 +5,16 @@
203
204 .p-option-selector__input {
205 @extend select;
206- color: #111 !important;
207+ cursor: pointer;
208+
209+ &.in-warning {
210+ border-color: $color-caution !important;
211+ }
212+ }
213+
214+ [readonly][type="text"].p-option-selector__input {
215+ color: $color-dark;
216+ border-color: $color-mid-light;
217 }
218
219 .p-option-selector__options {
220@@ -49,6 +58,10 @@
221 background-color: $color-light;
222 }
223
224+ &.is-over {
225+ opacity: .5;
226+ }
227+
228 &.is-selected {
229 background-color: $color-light;
230 background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='17' height='17' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform='translate(1 1)' fill='none' fill-rule='evenodd'%3E%3Ccircle stroke='%230e8420' stroke-width='1.5' fill='%230e8420' cx='7.25' cy='7.25' r='7.25'/%3E%3Cpath fill='%23fff' d='M11.05 4.173l-.066.058L6.25 8.378l-2.776-2.38-.839.948L6.25 10.75l5.5-5.787-.7-.79z'/%3E%3C/g%3E%3C/svg%3E");

Subscribers

People subscribed via source and target branches