Merge lp:~blake-rouse/maas/fix-1566920 into lp:~maas-committers/maas/trunk
- fix-1566920
- Merge into trunk
Proposed by
Blake Rouse
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Blake Rouse | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 4899 | ||||
Proposed branch: | lp:~blake-rouse/maas/fix-1566920 | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
710 lines (+240/-181) 6 files modified
src/maasserver/static/js/angular/controllers/node_details.js (+54/-81) src/maasserver/static/js/angular/controllers/tests/test_node_details.js (+129/-42) src/maasserver/static/js/angular/factories/general.js (+1/-2) src/maasserver/static/js/angular/factories/tests/test_general.js (+3/-2) src/maasserver/static/partials/node-details.html (+50/-51) src/maasserver/static/partials/node-events.html (+3/-3) |
||||
To merge this branch: | bzr merge lp:~blake-rouse/maas/fix-1566920 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andres Rodriguez (community) | Needs Fixing | ||
Mike Pontillo (community) | Approve | ||
Review via email: mp+291416@code.launchpad.net |
Commit message
Fix handling no connected rack controllers on the machine details page. Cleanup error messages on the machine details page. Fix power_type options from being reset mid type.
Description of the change
To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote : | # |
missing changelog entry
review:
Needs Fixing
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/maasserver/static/js/angular/controllers/node_details.js' |
2 | --- src/maasserver/static/js/angular/controllers/node_details.js 2016-03-28 13:54:47 +0000 |
3 | +++ src/maasserver/static/js/angular/controllers/node_details.js 2016-04-08 20:38:44 +0000 |
4 | @@ -40,21 +40,6 @@ |
5 | $scope.checkingPower = false; |
6 | $scope.devices = []; |
7 | |
8 | - // Holds errors that are displayed on the details page. |
9 | - $scope.errors = { |
10 | - invalid_arch: { |
11 | - viewable: false, |
12 | - message: "This node has an invalid architecture. Update the " + |
13 | - "architecture for this node in the summary section below." |
14 | - }, |
15 | - missing_power: { |
16 | - viewable: false, |
17 | - message: "This node does not have a power type set and " + |
18 | - "MAAS will be unable to control it. Update the power " + |
19 | - "information in the power section below." |
20 | - } |
21 | - }; |
22 | - |
23 | // Node header section. |
24 | $scope.header = { |
25 | editing: false, |
26 | @@ -110,51 +95,6 @@ |
27 | summaryType: 'yaml' |
28 | }; |
29 | |
30 | - // Show given error. |
31 | - function showError(name) { |
32 | - $scope.errors[name].viewable = true; |
33 | - } |
34 | - |
35 | - // Hide given error. |
36 | - function hideError(name) { |
37 | - $scope.errors[name].viewable = false; |
38 | - } |
39 | - |
40 | - // Return true if the error is viewable. |
41 | - function isErrorViewable(name) { |
42 | - return $scope.errors[name].viewable; |
43 | - } |
44 | - |
45 | - // Return true if the architecture for the given node is invalid. |
46 | - function hasInvalidArchitecture(node) { |
47 | - return ( |
48 | - node.architecture === "" || |
49 | - $scope.summary.architecture.options.indexOf( |
50 | - node.architecture) === -1); |
51 | - } |
52 | - |
53 | - // Update the shown errors based on the status of the node. |
54 | - function updateErrors() { |
55 | - if('controller' !== $routeParams.type) { |
56 | - // Check if the nodes power type is null, if so then show the |
57 | - // missing_power error. |
58 | - if($scope.node.power_type === "") { |
59 | - showError("missing_power"); |
60 | - } else { |
61 | - hideError("missing_power"); |
62 | - } |
63 | - |
64 | - // Show architecture error if the node has no architecture |
65 | - // or if the current architecture is not in the available |
66 | - // architectures. |
67 | - if(hasInvalidArchitecture($scope.node)) { |
68 | - showError("invalid_arch"); |
69 | - } else { |
70 | - hideError("invalid_arch"); |
71 | - } |
72 | - } |
73 | - } |
74 | - |
75 | // Updates the page title. |
76 | function updateTitle() { |
77 | if($scope.node && $scope.node.fqdn) { |
78 | @@ -206,9 +146,6 @@ |
79 | |
80 | // Updates the currently selected items in the power section. |
81 | function updatePower() { |
82 | - // Update the viewable errors. |
83 | - updateErrors(); |
84 | - |
85 | // Do not update the selected items, when editing this would |
86 | // cause the users selection to change. |
87 | if($scope.power.editing) { |
88 | @@ -242,9 +179,6 @@ |
89 | |
90 | // Updates the currently selected items in the summary section. |
91 | function updateSummary() { |
92 | - // Update the viewable errors. |
93 | - updateErrors(); |
94 | - |
95 | // Do not update the selected items, when editing this would |
96 | // cause the users selection to change. |
97 | if($scope.summary.editing) { |
98 | @@ -260,7 +194,9 @@ |
99 | // Force editing mode on, if the architecture is invalid. This is |
100 | // placed at the bottom because we wanted the selected items to |
101 | // be filled in at least once. |
102 | - if($scope.canEdit() && hasInvalidArchitecture($scope.node)) { |
103 | + if($scope.canEdit() && |
104 | + $scope.hasUsableArchitectures() && |
105 | + $scope.hasInvalidArchitecture()) { |
106 | $scope.summary.editing = true; |
107 | } |
108 | } |
109 | @@ -434,6 +370,7 @@ |
110 | // are updated. |
111 | $scope.$watch("node.power_type", updatePower); |
112 | $scope.$watch("node.power_parameters", updatePower); |
113 | + $scope.$watchCollection("power_types", updatePower); |
114 | |
115 | // Update the services when the services list is updated. |
116 | $scope.$watch("node.service_ids", updateServices); |
117 | @@ -446,18 +383,6 @@ |
118 | $scope.$watch("node.installation_results", updateMachineOutput); |
119 | } |
120 | |
121 | - // Update the node with new data on the region. |
122 | - $scope.updateNode = function(node) { |
123 | - return $scope.nodesManager.updateItem(node).then(function(node) { |
124 | - updateHeader(); |
125 | - updateSummary(); |
126 | - }, function(error) { |
127 | - console.log(error); |
128 | - updateHeader(); |
129 | - updateSummary(); |
130 | - }); |
131 | - }; |
132 | - |
133 | // Called when the node has been loaded. |
134 | function nodeLoaded(node) { |
135 | $scope.node = node; |
136 | @@ -479,6 +404,18 @@ |
137 | } |
138 | } |
139 | |
140 | + // Update the node with new data on the region. |
141 | + $scope.updateNode = function(node) { |
142 | + return $scope.nodesManager.updateItem(node).then(function(node) { |
143 | + updateHeader(); |
144 | + updateSummary(); |
145 | + }, function(error) { |
146 | + console.log(error); |
147 | + updateHeader(); |
148 | + updateSummary(); |
149 | + }); |
150 | + }; |
151 | + |
152 | // Called for autocomplete when the user is typing a tag name. |
153 | $scope.tagsAutocomplete = function(query) { |
154 | return TagsManager.autocomplete(query); |
155 | @@ -681,6 +618,32 @@ |
156 | return UsersManager.isSuperUser(); |
157 | }; |
158 | |
159 | + // Return true if their are usable architectures. |
160 | + $scope.hasUsableArchitectures = function() { |
161 | + return $scope.summary.architecture.options.length > 0; |
162 | + }; |
163 | + |
164 | + // Return the placeholder text for the architecture dropdown. |
165 | + $scope.getArchitecturePlaceholder = function() { |
166 | + if($scope.hasUsableArchitectures()) { |
167 | + return "Choose an architecture"; |
168 | + } else { |
169 | + return "-- No usable architectures --"; |
170 | + } |
171 | + }; |
172 | + |
173 | + // Return true if the saved architecture is invalid. |
174 | + $scope.hasInvalidArchitecture = function() { |
175 | + if(angular.isObject($scope.node)) { |
176 | + return ( |
177 | + $scope.node.architecture === "" || |
178 | + $scope.summary.architecture.options.indexOf( |
179 | + $scope.node.architecture) === -1); |
180 | + } else { |
181 | + return false; |
182 | + } |
183 | + }; |
184 | + |
185 | // Return true if the current architecture selection is invalid. |
186 | $scope.invalidArchitecture = function() { |
187 | return ( |
188 | @@ -689,9 +652,19 @@ |
189 | $scope.summary.architecture.selected) === -1); |
190 | }; |
191 | |
192 | + // Return true if at least a rack controller is connected to the |
193 | + // region controller. |
194 | + $scope.isRackControllerConnected = function() { |
195 | + // If power_types exist then a rack controller is connected. |
196 | + return $scope.power_types.length > 0; |
197 | + }; |
198 | + |
199 | // Return true when the edit buttons can be clicked. |
200 | $scope.canEdit = function() { |
201 | - return $scope.isSuperUser() && !$scope.isController; |
202 | + return ( |
203 | + $scope.isRackControllerConnected() && |
204 | + $scope.isSuperUser() && |
205 | + !$scope.isController); |
206 | }; |
207 | |
208 | // Called to edit the node name. |
209 | @@ -761,7 +734,7 @@ |
210 | // Called to cancel editing in the summary section. |
211 | $scope.cancelEditSummary = function() { |
212 | // Leave edit mode only if node has valid architecture. |
213 | - if(!hasInvalidArchitecture($scope.node)) { |
214 | + if(!$scope.hasInvalidArchitecture()) { |
215 | $scope.summary.editing = false; |
216 | } |
217 | |
218 | |
219 | === modified file 'src/maasserver/static/js/angular/controllers/tests/test_node_details.js' |
220 | --- src/maasserver/static/js/angular/controllers/tests/test_node_details.js 2016-03-28 13:54:47 +0000 |
221 | +++ src/maasserver/static/js/angular/controllers/tests/test_node_details.js 2016-04-08 20:38:44 +0000 |
222 | @@ -328,37 +328,25 @@ |
223 | expect($rootScope.title).toBe(node.fqdn); |
224 | }); |
225 | |
226 | - it("invalid_arch error visible if node architecture empty", function() { |
227 | - node.architecture = ""; |
228 | - |
229 | - var controller = makeControllerResolveSetActiveItem(); |
230 | - expect($scope.errors.invalid_arch.viewable).toBe(true); |
231 | - }); |
232 | - |
233 | - it("invalid_arch error visible if node architecture not present", |
234 | - function() { |
235 | - GeneralManager._data.architectures.data = [makeName("arch")]; |
236 | - |
237 | - var controller = makeControllerResolveSetActiveItem(); |
238 | - expect($scope.errors.invalid_arch.viewable).toBe(true); |
239 | - }); |
240 | - |
241 | - it("invalid_arch error not visible if node architecture present", |
242 | - function() { |
243 | - GeneralManager._data.architectures.data = [node.architecture]; |
244 | - |
245 | - var controller = makeControllerResolveSetActiveItem(); |
246 | - expect($scope.errors.invalid_arch.viewable).toBe(false); |
247 | - }); |
248 | - |
249 | it("summary section placed in edit mode if architecture blank", |
250 | function() { |
251 | node.architecture = ""; |
252 | + GeneralManager._data.power_types.data = [{}]; |
253 | + GeneralManager._data.architectures.data = ["amd64/generic"]; |
254 | |
255 | var controller = makeControllerResolveSetActiveItem(); |
256 | expect($scope.summary.editing).toBe(true); |
257 | }); |
258 | |
259 | + it("summary section not placed in edit mode if no usable architectures", |
260 | + function() { |
261 | + node.architecture = ""; |
262 | + GeneralManager._data.power_types.data = [{}]; |
263 | + |
264 | + var controller = makeControllerResolveSetActiveItem(); |
265 | + expect($scope.summary.editing).toBe(false); |
266 | + }); |
267 | + |
268 | it("summary section not placed in edit mode if architecture present", |
269 | function() { |
270 | GeneralManager._data.architectures.data = [node.architecture]; |
271 | @@ -375,25 +363,21 @@ |
272 | expect($scope.summary.tags).toEqual(node.tags); |
273 | }); |
274 | |
275 | - it("missing_power error visible if node power_type empty", function() { |
276 | - var controller = makeControllerResolveSetActiveItem(); |
277 | - expect($scope.errors.missing_power.viewable).toBe(true); |
278 | - }); |
279 | - |
280 | - it("missing_power error not visible if node power_type empty", function() { |
281 | - node.power_type = makeName("power"); |
282 | - |
283 | - var controller = makeControllerResolveSetActiveItem(); |
284 | - expect($scope.errors.missing_power.viewable).toBe(false); |
285 | - }); |
286 | - |
287 | it("power section placed in edit mode if power_type blank", function() { |
288 | + GeneralManager._data.power_types.data = [{}]; |
289 | + |
290 | var controller = makeControllerResolveSetActiveItem(); |
291 | expect($scope.power.editing).toBe(true); |
292 | }); |
293 | |
294 | + it("power section not placed in edit mode if no power_types", function() { |
295 | + var controller = makeControllerResolveSetActiveItem(); |
296 | + expect($scope.power.editing).toBe(false); |
297 | + }); |
298 | + |
299 | it("power section not placed in edit mode if power_type", function() { |
300 | node.power_type = makeName("power"); |
301 | + GeneralManager._data.power_types.data = [{}]; |
302 | |
303 | var controller = makeControllerResolveSetActiveItem(); |
304 | expect($scope.power.editing).toBe(false); |
305 | @@ -564,7 +548,8 @@ |
306 | expect(watchCollections).toEqual([ |
307 | $scope.summary.architecture.options, |
308 | $scope.summary.min_hwe_kernel.options, |
309 | - $scope.summary.zone.options |
310 | + $scope.summary.zone.options, |
311 | + "power_types" |
312 | ]); |
313 | }); |
314 | |
315 | @@ -1190,6 +1175,75 @@ |
316 | }); |
317 | }); |
318 | |
319 | + describe("hasUsableArchitectures", function() { |
320 | + |
321 | + it("returns true if architecture available", function() { |
322 | + var controller = makeController(); |
323 | + $scope.summary.architecture.options = ["amd64/generic"]; |
324 | + expect($scope.hasUsableArchitectures()).toBe(true); |
325 | + }); |
326 | + |
327 | + it("returns false if no architecture available", function() { |
328 | + var controller = makeController(); |
329 | + $scope.summary.architecture.options = []; |
330 | + expect($scope.hasUsableArchitectures()).toBe(false); |
331 | + }); |
332 | + }); |
333 | + |
334 | + describe("getArchitecturePlaceholder", function() { |
335 | + |
336 | + it("returns choose if architecture available", function() { |
337 | + var controller = makeController(); |
338 | + $scope.summary.architecture.options = ["amd64/generic"]; |
339 | + expect($scope.getArchitecturePlaceholder()).toBe( |
340 | + "Choose an architecture"); |
341 | + }); |
342 | + |
343 | + it("returns error if no architecture available", function() { |
344 | + var controller = makeController(); |
345 | + $scope.summary.architecture.options = []; |
346 | + expect($scope.getArchitecturePlaceholder()).toBe( |
347 | + "-- No usable architectures --"); |
348 | + }); |
349 | + }); |
350 | + |
351 | + describe("hasInvalidArchitecture", function() { |
352 | + |
353 | + it("returns false if node is null", function() { |
354 | + var controller = makeController(); |
355 | + $scope.node = null; |
356 | + $scope.summary.architecture.options = ["amd64/generic"]; |
357 | + expect($scope.hasInvalidArchitecture()).toBe(false); |
358 | + }); |
359 | + |
360 | + it("returns true if node.architecture is blank", function() { |
361 | + var controller = makeController(); |
362 | + $scope.node = { |
363 | + architecture: "" |
364 | + }; |
365 | + $scope.summary.architecture.options = ["amd64/generic"]; |
366 | + expect($scope.hasInvalidArchitecture()).toBe(true); |
367 | + }); |
368 | + |
369 | + it("returns true if node.architecture not in options", function() { |
370 | + var controller = makeController(); |
371 | + $scope.node = { |
372 | + architecture: "i386/generic" |
373 | + }; |
374 | + $scope.summary.architecture.options = ["amd64/generic"]; |
375 | + expect($scope.hasInvalidArchitecture()).toBe(true); |
376 | + }); |
377 | + |
378 | + it("returns false if node.architecture in options", function() { |
379 | + var controller = makeController(); |
380 | + $scope.node = { |
381 | + architecture: "amd64/generic" |
382 | + }; |
383 | + $scope.summary.architecture.options = ["amd64/generic"]; |
384 | + expect($scope.hasInvalidArchitecture()).toBe(false); |
385 | + }); |
386 | + }); |
387 | + |
388 | describe("invalidArchitecture", function() { |
389 | |
390 | it("returns true if selected architecture empty", function() { |
391 | @@ -1214,25 +1268,58 @@ |
392 | }); |
393 | }); |
394 | |
395 | + describe("isRackControllerConnected", function() { |
396 | + |
397 | + it("returns false no power_types", function() { |
398 | + var controller = makeController(); |
399 | + $scope.power_types = []; |
400 | + expect($scope.isRackControllerConnected()).toBe(false); |
401 | + }); |
402 | + |
403 | + it("returns true if power_types", function() { |
404 | + var controller = makeController(); |
405 | + $scope.power_types = [{}]; |
406 | + expect($scope.isRackControllerConnected()).toBe(true); |
407 | + }); |
408 | + }); |
409 | + |
410 | describe("canEdit", function() { |
411 | |
412 | - it("returns false if not super user and not controller", function() { |
413 | + it("returns false if not super user", function() { |
414 | var controller = makeController(); |
415 | $scope.isController = false; |
416 | spyOn($scope, "isSuperUser").and.returnValue(false); |
417 | + spyOn( |
418 | + $scope, |
419 | + "isRackControllerConnected").and.returnValue(true); |
420 | expect($scope.canEdit()).toBe(false); |
421 | }); |
422 | |
423 | - it("returns false if super user and controller", function() { |
424 | + it("returns false if controller", function() { |
425 | var controller = makeController(); |
426 | $scope.isController = true; |
427 | - expect($scope.canEdit()).toBe(false); |
428 | - }); |
429 | - |
430 | - it("returns true if super user and not controller", |
431 | + spyOn( |
432 | + $scope, |
433 | + "isRackControllerConnected").and.returnValue(true); |
434 | + expect($scope.canEdit()).toBe(false); |
435 | + }); |
436 | + |
437 | + it("returns false if rack disconnected", function() { |
438 | + var controller = makeController(); |
439 | + $scope.isController = false; |
440 | + spyOn( |
441 | + $scope, |
442 | + "isRackControllerConnected").and.returnValue(false); |
443 | + expect($scope.canEdit()).toBe(false); |
444 | + }); |
445 | + |
446 | + it("returns true if super user, rack connected, not controller", |
447 | function() { |
448 | var controller = makeController(); |
449 | $scope.isController = false; |
450 | + spyOn( |
451 | + $scope, |
452 | + "isRackControllerConnected").and.returnValue(true); |
453 | expect($scope.canEdit()).toBe(true); |
454 | }); |
455 | }); |
456 | |
457 | === modified file 'src/maasserver/static/js/angular/factories/general.js' |
458 | --- src/maasserver/static/js/angular/factories/general.js 2016-03-28 13:54:47 +0000 |
459 | +++ src/maasserver/static/js/angular/factories/general.js 2016-04-08 20:38:44 +0000 |
460 | @@ -108,7 +108,7 @@ |
461 | polling: false, |
462 | nextPromise: null, |
463 | replaceData: function(oldData, newData) { |
464 | - // Update or add new power types. |
465 | + // Add new power types. |
466 | var i, j, newPowerType, oldPowerType; |
467 | for(i = 0; i < newData.length; i++) { |
468 | newPowerType = newData[i]; |
469 | @@ -116,7 +116,6 @@ |
470 | for(j = 0; j < oldData.length; j++) { |
471 | oldPowerType = oldData[j]; |
472 | if(newPowerType.name === oldPowerType.name) { |
473 | - angular.copy(newPowerType, oldPowerType); |
474 | newItem = false; |
475 | break; |
476 | } |
477 | |
478 | === modified file 'src/maasserver/static/js/angular/factories/tests/test_general.js' |
479 | --- src/maasserver/static/js/angular/factories/tests/test_general.js 2016-03-28 13:54:47 +0000 |
480 | +++ src/maasserver/static/js/angular/factories/tests/test_general.js 2016-04-08 20:38:44 +0000 |
481 | @@ -169,7 +169,7 @@ |
482 | expect(data).toEqual([newPowerType]); |
483 | }); |
484 | |
485 | - it("updates power_type in array to be same object", function() { |
486 | + it("doesnt update power_type in array to be same object", function() { |
487 | var oldPowerType = { |
488 | name: makeName("power"), |
489 | fields: [ |
490 | @@ -188,7 +188,8 @@ |
491 | ] |
492 | }; |
493 | replaceData(data, [newPowerType]); |
494 | - expect(data).toEqual([newPowerType]); |
495 | + expect(data).not.toEqual([newPowerType]); |
496 | + expect(data[0]).toEqual(oldPowerType); |
497 | expect(data[0]).toBe(oldPowerType); |
498 | }); |
499 | |
500 | |
501 | === modified file 'src/maasserver/static/partials/node-details.html' |
502 | --- src/maasserver/static/partials/node-details.html 2016-03-28 13:54:47 +0000 |
503 | +++ src/maasserver/static/partials/node-details.html 2016-04-08 20:38:44 +0000 |
504 | @@ -137,19 +137,24 @@ |
505 | </div> |
506 | </div> |
507 | </header> |
508 | - <div class="inner-wrapper"> |
509 | - <ul class="flash-messages"> |
510 | - <li class="flash-messages__item error ng-hide" |
511 | - data-ng-repeat="(error_type, error) in errors" |
512 | - data-ng-show="error.viewable">{$ error.message $}</li> |
513 | - </ul> |
514 | - </div> |
515 | <div class="row"> |
516 | <div class="inner-wrapper"> |
517 | <form> |
518 | <div class="twelve-col"> |
519 | <h2 class="title" data-ng-hide="isController">Machine summary</h2> |
520 | <h2 class="title" data-ng-show="isController">Controller summary</h2> |
521 | + <ul class="flash-messages" data-ng-if="isSuperUser()"> |
522 | + <li class="flash-messages__item error" |
523 | + data-ng-if="!isController && !isRackControllerConnected()">Editing is currently disabled because no rack controller is currently connected to the region.</li> |
524 | + <li class="flash-messages__item error" |
525 | + data-ng-if="!isController && hasInvalidArchitecture() && isRackControllerConnected() && hasUsableArchitectures()"> |
526 | + This machine currently has an invalid architecture. Update the architecture of this machine to make it deployable. |
527 | + </li> |
528 | + <li class="flash-messages__item error" |
529 | + data-ng-if="!isController && hasInvalidArchitecture() && isRackControllerConnected() && !hasUsableArchitectures()"> |
530 | + No boot images have been imported for a valid architecture to be selected. Visit the <a href="images">images page</a> to start the import process. |
531 | + </li> |
532 | + </ul> |
533 | </div> |
534 | <fieldset class="six-col"> |
535 | <div class="ng-hide" data-ng-show="isSuperUser() && !isController"> |
536 | @@ -167,12 +172,12 @@ |
537 | <div class="inline"> |
538 | <label for="architecture" class="two-col">Architecture</label> |
539 | <div class="three-col"> |
540 | - <select name="architecture" id="architecture" placeholder="Choose an architecture" |
541 | + <select name="architecture" id="architecture" |
542 | data-ng-disabled="!summary.editing" |
543 | data-ng-model="summary.architecture.selected" |
544 | data-ng-options="arch for arch in summary.architecture.options" |
545 | data-ng-class="{ invalid: invalidArchitecture() }"> |
546 | - <option value="" disabled="disabled">Choose an architecture</option> |
547 | + <option value="" disabled="disabled">{$ getArchitecturePlaceholder() $}</option> |
548 | </select> |
549 | </div> |
550 | </div> |
551 | @@ -332,32 +337,41 @@ |
552 | <div class="inner-wrapper"> |
553 | <form class="disabled"> |
554 | <div class="twelve-col"> |
555 | - <h2 class="title">Power</h2> |
556 | - </div> |
557 | - <div class="twelve-col ng-hide info" data-ng-show="power.type.name == 'manual'"> |
558 | - <ul class="flash-messages"> |
559 | - <li class="flash-messages__item info"> |
560 | - Power control for this power type will need to be handled manually. |
561 | - </li> |
562 | - </ul> |
563 | - </div> |
564 | - <div class="twelve-col ng-hide error" data-ng-show="hasPowerError()"> |
565 | - <ul class="flash-messages"> |
566 | - <li class="flash-messages__item error"> |
567 | + <h2 class="title left">Power</h2> |
568 | + </div> |
569 | + <div class="twelve-col"> |
570 | + <ul class="flash-messages"> |
571 | + <li class="flash-messages__item error" data-ng-if="!isRackControllerConnected()"> |
572 | + Editing is currently disabled because no rack controller is current connected to the region. |
573 | + </li> |
574 | + <li class="flash-messages__item error" data-ng-if="isRackControllerConnected() && node.power_type == ''"> |
575 | + This node does not have a power type set and MAAS will be unable to control it. Update the power |
576 | + information below. |
577 | + </li> |
578 | + <li class="flash-messages__item error" data-ng-if="hasPowerError()"> |
579 | Power control software for this power type is missing from the |
580 | rack controller. To proceed, install the {$ getPowerErrors() $} |
581 | on the rack controller. |
582 | </li> |
583 | + <li class="flash-messages__item info" data-ng-if="power.type.name == 'manual'"> |
584 | + Power control for this power type will need to be handled manually. |
585 | + </li> |
586 | + <li class="flash-messages__item info" data-ng-if="power.editing && node.power_bmc_node_count > 1"> |
587 | + This power controller manages {$ node.power_bmc_node_count - 1 $} other |
588 | + {$ node.power_bmc_node_count > 3 ? "nodes" : "node" $}. |
589 | + Changing power parameters will affect these nodes. |
590 | + </li> |
591 | </ul> |
592 | </div> |
593 | - <fieldset class="six-col" |
594 | + <fieldset class="six-col ng-hide" |
595 | + data-ng-show="power_types.length" |
596 | data-ng-disabled="!power.editing" |
597 | data-maas-power-parameters="power_types" |
598 | data-ng-model="power"> |
599 | </fieldset> |
600 | <div class="controls" data-ng-hide="power.editing"> |
601 | <a href="" class="link-cta-ubuntu secondary" |
602 | - data-ng-show="canEdit()" |
603 | + data-ng-show="canEdit() && power_types.length" |
604 | data-ng-click="editPower()">Edit</a> |
605 | </div> |
606 | <div class="controls ng-hide" data-ng-show="power.editing"> |
607 | @@ -367,16 +381,7 @@ |
608 | data-ng-class="{ secondary: invalidPowerType() }" |
609 | data-ng-click="saveEditPower()">Save changes</button> |
610 | </div> |
611 | - <div class="twelve-col ng-hide info" data-ng-show="power.editing && node.power_bmc_node_count > 1"> |
612 | - <ul class="flash-messages"> |
613 | - <li class="flash-messages__item info"> |
614 | - This power controller manages {$ node.power_bmc_node_count - 1 $} other |
615 | - {$ node.power_bmc_node_count > 3 ? "nodes" : "node" $}. |
616 | - Changing power parameters will affect these nodes. If this is not what you want, |
617 | - create a new power controller unique to this node by changing the power type. |
618 | - </li> |
619 | - </ul> |
620 | - </div> |
621 | + |
622 | </form> |
623 | </div> |
624 | </div> |
625 | @@ -495,7 +500,7 @@ |
626 | </div> |
627 | <div class="table__data table-col--30"> |
628 | <span data-ng-repeat="subnet in vlanRow['subnets']"> |
629 | - <div class="margin-bottom--ten"> |
630 | + <div class="margin-bottom--ten"> |
631 | <a href="#/subnet/{$ subnet.id $}">{$ getSubnetText(subnet) $}</a> |
632 | </div> |
633 | </span> |
634 | @@ -515,25 +520,23 @@ |
635 | <div class="row"> |
636 | <div class="inner-wrapper"> |
637 | <div class="twelve-col" data-ng-hide="loaded"> |
638 | - <h2 class="title">Network</h2> |
639 | + <h2 class="title">Interfaces</h2> |
640 | <div class="twelve-col">Loading...</div> |
641 | </div> |
642 | <form class="ng-hide" data-ng-show="loaded"> |
643 | <div class="twelve-col"> |
644 | - <h2 class="title">Network</h2> |
645 | + <h2 class="title">Interfaces</h2> |
646 | <div class="twelve-col error"> |
647 | - <ul class="flash-messages ng-hide" data-ng-show="!isController && isAllNetworkingDisabled() && isSuperUser()"> |
648 | - <li class="flash-messages__item info"> |
649 | - Network configuration cannot be modified unless the node is Ready or Broken. |
650 | - </li> |
651 | - </ul> |
652 | - <ul class="flash-messages ng-hide" data-ng-show="!node.on_network"> |
653 | - <li class="flash-messages__item error"> |
654 | + <ul class="flash-messages" data-ng-if=" |
655 | + (!isController && isAllNetworkingDisabled() && isSuperUser()) || |
656 | + !node.on_network || (!isController && !isUbuntuOS())"> |
657 | + <li class="flash-messages__item error" data-ng-if="!node.on_network"> |
658 | Node must be connected to a network. |
659 | </li> |
660 | - </ul> |
661 | - <ul class="flash-messages ng-hide" data-ng-show="!isController && !isUbuntuOS()"> |
662 | - <li class="flash-messages__item info"> |
663 | + <li class="flash-messages__item info" data-ng-if="!isController && isAllNetworkingDisabled() && isSuperUser()"> |
664 | + Interface configuration cannot be modified unless the node is Ready or Broken. |
665 | + </li> |
666 | + <li class="flash-messages__item info" data-ng-if="!isController && !isUbuntuOS()"> |
667 | Custom network configuration only supported on Ubuntu. Using OS default configuration. |
668 | </li> |
669 | </ul> |
670 | @@ -1105,12 +1108,10 @@ |
671 | |
672 | </main> |
673 | </section> |
674 | - |
675 | <a class="link-cta-ubuntu secondary tooltip" |
676 | data-tooltip="Create a tmpfs or ramfs filesystem" |
677 | ng-disabled="dropdown !== null" |
678 | ng-click="addSpecialFilesystem()">Add special filesystem</a> |
679 | - |
680 | </div> |
681 | <div class="twelve-col padding-bottom" data-ng-show="cachesets.length"> |
682 | <h3>Available cache sets</h3> |
683 | @@ -1869,9 +1870,7 @@ |
684 | <div class="inner-wrapper"> |
685 | <div class="twelve-col"> |
686 | <h2 class="title">Latest machine events</h2> |
687 | - <h2 data-ng-hide="node.events.length"> |
688 | - No events. |
689 | - </h2> |
690 | + <p data-ng-hide="node.events.length">No events.</p> |
691 | <table class="table-listing no-hover" data-ng-show="node.events.length"> |
692 | <thead> |
693 | <tr class="table-listing__row"> |
694 | |
695 | === modified file 'src/maasserver/static/partials/node-events.html' |
696 | --- src/maasserver/static/partials/node-events.html 2016-03-31 22:30:51 +0000 |
697 | +++ src/maasserver/static/partials/node-events.html 2016-04-08 20:38:44 +0000 |
698 | @@ -31,9 +31,9 @@ |
699 | <table class="table-listing " id="events-listing"> |
700 | <thead> |
701 | <tr class="table-listing__row"> |
702 | - <th class="table-listing__header t1"></th> |
703 | - <th class="table-listing__header t79">Event</th> |
704 | - <th class="table-listing__header t20">Time</th> |
705 | + <th class="table-listing__header table-col--1"></th> |
706 | + <th class="table-listing__header table-col--79">Event</th> |
707 | + <th class="table-listing__header table-col--20">Time</th> |
708 | </tr> |
709 | </thead> |
710 | <tbody> |
Looks good to me. One comment/nit below.