Merge lp:~blake-rouse/maas/fix-1509417 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4431
Proposed branch: lp:~blake-rouse/maas/fix-1509417
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 396 lines (+179/-111)
3 files modified
src/maasserver/static/js/angular/controllers/node_details_storage.js (+43/-31)
src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js (+125/-77)
src/maasserver/static/partials/node-details.html (+11/-3)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1509417
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Lee Trager (community) Approve
Review via email: mp+276041@code.launchpad.net

Commit message

Enable modification of storage tags on physical and virtual block devices in the available section.

Description of the change

This does not fully fix the bug. Has Rich still needs to fix the styling, so landing this branch will not mark the bug "Fix Committed".

To post a comment you must log in.
Revision history for this message
Lee Trager (ltrager) wrote :

LGTM!

My only thought is that we should allow viewing and editing tags in either the filesystem or used disks and partitions section. Its a bit of a pain to have to make a disk available just to be able to view and edit its tags.

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

Thanks for the review.

Yeah I agree. I will be enabling that, just in a different branch.

Revision history for this message
Mike Pontillo (mpontillo) wrote :

Looks pretty good to me; I may have spotted an issue or two that you might want to look at. Take a look below and let me know what you think.

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

Thanks for the review. I will add the request comment.

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1003.7 KiB)

The attempt to merge lp:~blake-rouse/maas/fix-1509417 into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com trusty-security InRelease [64.4 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://nova.clouds.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:3 http://security.ubuntu.com trusty-security/main Sources [98.0 kB]
Get:4 http://security.ubuntu.com trusty-security/universe Sources [31.0 kB]
Get:5 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [241 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [357 kB]
Get:7 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [143 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [117 kB]
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [637 kB]
Get:10 http://security.ubuntu.com trusty-security/main Translation-en [194 kB]
Get:11 http://security.ubuntu.com trusty-security/universe Translation-en [68.4 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [326 kB]
Get:13 http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en [309 kB]
Get:14 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en [172 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 2,823 kB in 4s (652 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm pep8 phantomjs postgresql pyflakes python-apt python-bson python-bzrlib python-convoy python-coverage python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lxml python-mock python-netaddr python-netifaces python-nose python-oauth python-openssl python-paramiko python-pexpect python-pip python-pocket-lint python-psycopg2 python-pyinotify python-pyparsing python-seamicroclient python-simplejson python-simplestreams python-sphinx python-subunit python-tempita py...

Revision history for this message
Mike Pontillo (mpontillo) wrote :
Download full text (3.3 KiB)

Digging through that log is annoying. But I found this:

maasserver.tests.test_forms_interface.BondInterfaceFormTest.test__creates_bond_interface_with_parent_mac_address ... ERROR
maasserver.tests.test_populate_tags.TestPopulateTags.test__calls_do_populate_tags_with_clusters ... FAIL

======================================================================
ERROR: maasserver.tests.test_forms_interface.BondInterfaceFormTest.test__creates_bond_interface_with_parent_mac_address
----------------------------------------------------------------------
_StringException: Traceback (most recent call last):
  File "/tmp/tarmac/branch.IXGl4c/src/maastesting/runtest.py", line 68, in _run_user
    result = function(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/testtools/testcase.py", line 616, in _run_test_method
    return self._get_test_method()()
  File "/tmp/tarmac/branch.IXGl4c/src/maasserver/tests/test_forms_interface.py", line 516, in test__creates_bond_interface_with_parent_mac_address
    vlan = factory.make_VLAN(vid=10)
  File "/tmp/tarmac/branch.IXGl4c/src/maasserver/testing/factory.py", line 739, in make_VLAN
    vlan.save()
  File "/tmp/tarmac/branch.IXGl4c/src/maasserver/models/cleansave.py", line 37, in save
    self.full_clean()
  File "/usr/lib/python2.7/dist-packages/django/db/models/base.py", line 950, in full_clean
    raise ValidationError(errors)
ValidationError: {'__all__': [u'VLAN with this Vid and Fabric already exists.']}

======================================================================
FAIL: maasserver.tests.test_populate_tags.TestPopulateTags.test__calls_do_populate_tags_with_clusters
----------------------------------------------------------------------
_StringException: Traceback (most recent call last):
  File "/tmp/tarmac/branch.IXGl4c/src/maastesting/runtest.py", line 68, in _run_user
    result = function(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/testtools/testcase.py", line 616, in _run_test_method
    return self._get_test_method()()
  File "/tmp/tarmac/branch.IXGl4c/src/maasserver/tests/test_populate_tags.py", line 244, in test__calls_do_populate_tags_with_clusters
    populate_tags_module.tag_nsmap))
  File "/usr/lib/python2.7/dist-packages/testtools/testcase.py", line 406, in assertThat
    raise mismatch_error
MismatchError: Expected call: mock(((u'd3892b66-7db1-11e5-a501-fa163e312456', u'cluster-kKQCvD', u'nSaYxW5vfF7Ch4hpS6:QyP7Kw8baU347hG7r8:2yWUpBW23SLrmhzta49NND73Rtks5ndm'), (u'd38bb390-7db1-11e5-a501-fa163e312456', u'cluster-GMo8FL', u'N76yENgGPFVjbzXhSE:H3MNtwh824fB9ezxj6:N4XHy6nELjjNC26yZEvBMjdc3RmqeXJu'), (u'd38d73f6-7db1-11e5-a501-fa163e312456', u'cluster-bgk6Vv', u'dReXSBYBrD82JkcCpv:wApPKrTsbp3rsBLAfj:Eu77CdEkfYg8SJ4NZeGWzuk8EUdS8hQR')), u'tag-6TAjrG', u'//node', {u'lldp': u'lldp', u'lshw': u'lshw'})
Actual call: mock(((u'd38d73f6-7db1-11e5-a501-fa163e312456', u'cluster-bgk6Vv', u'dReXSBYBrD82JkcCpv:wApPKrTsbp3rsBLAfj:Eu77CdEkfYg8SJ4NZeGWzuk8EUdS8hQR'), (u'd3892b66-7db1-11e5-a501-fa163e312456', u'cluster-kKQCvD', u'nSaYxW5vfF7Ch4hpS6:QyP7Kw8baU347hG7r8:2yWUpBW23SLrmhzta49NND73Rtks5ndm'), (u'd38bb390-7db1-11e5-a501-fa163e312456', u'cluster-GMo8FL', u'N76yENgGPFVjbzXhSE:H3MN...

Read more...

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1003.7 KiB)

The attempt to merge lp:~blake-rouse/maas/fix-1509417 into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com trusty-security InRelease [64.4 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://nova.clouds.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:3 http://security.ubuntu.com trusty-security/main Sources [98.0 kB]
Get:4 http://security.ubuntu.com trusty-security/universe Sources [31.0 kB]
Get:5 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [241 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [357 kB]
Get:7 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [143 kB]
Get:8 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [637 kB]
Get:9 http://security.ubuntu.com trusty-security/universe amd64 Packages [117 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [326 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 2,080 kB in 3s (527 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm pep8 phantomjs postgresql pyflakes python-apt python-bson python-bzrlib python-convoy python-coverage python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lxml python-mock python-netaddr python-netifaces python-nose python-oauth python-openssl python-paramiko python-pexpect python-pip python-pocket-lint python-psycopg2 python-pyinotify python-pyparsing python-seamicroclient python-simplejson python-simplestreams python-sphinx python-subunit python-tempita python-testresources python-testscenarios python-te...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/static/js/angular/controllers/node_details_storage.js'
--- src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-23 16:34:24 +0000
+++ src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-28 20:03:05 +0000
@@ -105,8 +105,6 @@
105 }105 }
106 ];106 ];
107107
108 $scope.editing = false;
109 $scope.editing_tags = false;
110 $scope.column = 'model';108 $scope.column = 'model';
111 $scope.has_disks = false;109 $scope.has_disks = false;
112 $scope.filesystems = [];110 $scope.filesystems = [];
@@ -492,6 +490,10 @@
492490
493 // Return true if another disk exists with name.491 // Return true if another disk exists with name.
494 function isNameAlreadyInUse(name, exclude_disk) {492 function isNameAlreadyInUse(name, exclude_disk) {
493 if(!angular.isArray($scope.node.disks)) {
494 return false;
495 }
496
495 var i, j;497 var i, j;
496 for(i = 0; i < $scope.node.disks.length; i++) {498 for(i = 0; i < $scope.node.disks.length; i++) {
497 var disk = $scope.node.disks[i];499 var disk = $scope.node.disks[i];
@@ -631,6 +633,7 @@
631 return false;633 return false;
632 };634 };
633635
636 // Return true if the free space label should be shown.
634 $scope.showFreeSpace = function(disk) {637 $scope.showFreeSpace = function(disk) {
635 if(disk.type === "lvm-vg") {638 if(disk.type === "lvm-vg") {
636 return true;639 return true;
@@ -1202,6 +1205,7 @@
1202 var selected = $scope.getSelectedAvailable();1205 var selected = $scope.getSelectedAvailable();
1203 if(selected.length === 1) {1206 if(selected.length === 1) {
1204 return (1207 return (
1208 !selected[0].has_partitions &&
1205 !$scope.hasUnmountedFilesystem(selected[0]) &&1209 !$scope.hasUnmountedFilesystem(selected[0]) &&
1206 selected[0].type !== "lvm-vg");1210 selected[0].type !== "lvm-vg");
1207 }1211 }
@@ -1471,7 +1475,11 @@
1471 $scope.availableNew.spares.length);1475 $scope.availableNew.spares.length);
1472 var minSize = Number.MAX_VALUE;1476 var minSize = Number.MAX_VALUE;
1473 angular.forEach($scope.availableNew.devices, function(device) {1477 angular.forEach($scope.availableNew.devices, function(device) {
1474 minSize = Math.min(minSize, device.original.available_size);1478 // Get the size of the device. For a block device it will be
1479 // at available_size and for a partition it will be at size.
1480 var deviceSize = (
1481 device.original.available_size || device.original.size);
1482 minSize = Math.min(minSize, deviceSize);
1475 });1483 });
14761484
1477 // Calculate the new size.1485 // Calculate the new size.
@@ -1546,7 +1554,9 @@
1546 if(selected.length > 0) {1554 if(selected.length > 0) {
1547 var i;1555 var i;
1548 for(i = 0; i < selected.length; i++) {1556 for(i = 0; i < selected.length; i++) {
1549 if($scope.hasUnmountedFilesystem(selected[i])) {1557 if(selected[i].has_partitions) {
1558 return false;
1559 } else if($scope.hasUnmountedFilesystem(selected[i])) {
1550 return false;1560 return false;
1551 } else if(selected[i].type === "lvm-vg") {1561 } else if(selected[i].type === "lvm-vg") {
1552 return false;1562 return false;
@@ -1573,7 +1583,9 @@
1573 $scope.getNewVolumeGroupSize = function() {1583 $scope.getNewVolumeGroupSize = function() {
1574 var total = 0;1584 var total = 0;
1575 angular.forEach($scope.availableNew.devices, function(device) {1585 angular.forEach($scope.availableNew.devices, function(device) {
1576 total += device.original.available_size;1586 // Add available_size or size if available_size is not set.
1587 total += (
1588 device.original.available_size || device.original.size);
1577 });1589 });
1578 return ConverterService.bytesToUnits(total).string;1590 return ConverterService.bytesToUnits(total).string;
1579 };1591 };
@@ -1703,33 +1715,33 @@
1703 $scope.updateAvailableSelection(true);1715 $scope.updateAvailableSelection(true);
1704 };1716 };
17051717
1718 // Return true when tags can be edited.
1719 $scope.canEditTags = function(disk) {
1720 return disk.type !== "partition" && disk.type !== "lvm-vg";
1721 };
1722
1706 // Called to enter tag editing mode1723 // Called to enter tag editing mode
1707 $scope.editTags = function() {1724 $scope.availableEditTags = function(disk) {
1708 if($scope.$parent.canEdit() && !$scope.editing) {1725 disk.$options = {
1709 $scope.editing = true;1726 editingTags: true,
1710 $scope.editing_tags = true;1727 tags: angular.copy(disk.tags)
1711 }1728 };
1712 };1729 };
17131730
1714 // Called to cancel editing.1731 // Called to cancel editing tags.
1715 $scope.cancelTags = function() {1732 $scope.availableCancelTags = function(disk) {
1716 $scope.editing = false;1733 disk.$options = {};
1717 $scope.editing_tags = false;1734 };
1718 updateDisks();1735
1719 };1736 // Called to save the tag changes.
17201737 $scope.availableSaveTags = function(disk) {
1721 // Called to save the changes.1738 var tags = [];
1722 $scope.saveTags = function() {1739 angular.forEach(disk.$options.tags, function(tag) {
1723 $scope.editing = false;1740 tags.push(tag.text);
1724 $scope.editing_tags = false;
1725
1726 angular.forEach($scope.available, function(disk) {
1727 var tags = [];
1728 angular.forEach(disk.tags, function(tag) {
1729 tags.push(tag.text);
1730 });
1731 NodesManager.updateDiskTags(
1732 $scope.node, disk.block_id, tags);
1733 });1741 });
1742 NodesManager.updateDiskTags(
1743 $scope.node, disk.block_id, tags);
1744 disk.tags = disk.$options.tags;
1745 disk.$options = {};
1734 };1746 };
1735 }]);1747 }]);
17361748
=== modified file 'src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js'
--- src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-23 18:39:01 +0000
+++ src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-28 20:03:05 +0000
@@ -252,7 +252,6 @@
252252
253 it("sets initial values", function() {253 it("sets initial values", function() {
254 var controller = makeController();254 var controller = makeController();
255 expect($scope.editing).toBe(false);
256 expect($scope.column).toBe('model');255 expect($scope.column).toBe('model');
257 expect($scope.has_disks).toBe(false);256 expect($scope.has_disks).toBe(false);
258 expect($scope.filesystems).toEqual([]);257 expect($scope.filesystems).toEqual([]);
@@ -3277,6 +3276,25 @@
3277 expect($scope.getNewRAIDSize()).toBe("2.0 MB");3276 expect($scope.getNewRAIDSize()).toBe("2.0 MB");
3278 });3277 });
32793278
3279 it("gets proper raid-0 size using size", function() {
3280 var controller = makeController();
3281 var disk0 = {
3282 original: {
3283 size: 1000 * 1000
3284 }
3285 };
3286 var disk1 = {
3287 original: {
3288 size: 1000 * 1000
3289 }
3290 };
3291 $scope.availableNew.spares = [];
3292 $scope.availableNew.devices = [disk0, disk1];
3293 $scope.availableNew.mode = $scope.getAvailableRAIDModes()[0];
3294
3295 expect($scope.getNewRAIDSize()).toBe("2.0 MB");
3296 });
3297
3280 it("gets proper raid-1 size", function() {3298 it("gets proper raid-1 size", function() {
3281 var controller = makeController();3299 var controller = makeController();
3282 var disk0 = {3300 var disk0 = {
@@ -3632,6 +3650,29 @@
36323650
3633 expect($scope.getNewVolumeGroupSize()).toBe("3.0 MB");3651 expect($scope.getNewVolumeGroupSize()).toBe("3.0 MB");
3634 });3652 });
3653
3654 it("return the total of all devices using size", function() {
3655 var controller = makeController();
3656 $scope.availableNew.devices = [
3657 {
3658 original: {
3659 size: 1000 * 1000
3660 }
3661 },
3662 {
3663 original: {
3664 size: 1000 * 1000
3665 }
3666 },
3667 {
3668 original: {
3669 size: 1000 * 1000
3670 }
3671 }
3672 ];
3673
3674 expect($scope.getNewVolumeGroupSize()).toBe("3.0 MB");
3675 });
3635 });3676 });
36363677
3637 describe("createVolumeGroupCanSave", function() {3678 describe("createVolumeGroupCanSave", function() {
@@ -3925,83 +3966,90 @@
3925 });3966 });
3926 });3967 });
39273968
3928 describe("editTags", function() {3969 describe("canEditTags", function() {
39293970
3930 it("doesnt sets editing to true if cannot edit", function() {3971 it("returns false for partition", function() {
3931 var controller = makeController();3972 var controller = makeController();
3932 canEditSpy.and.returnValue(false);3973 expect($scope.canEditTags({
3933 $scope.editing = false;3974 type: "partition"
3934 $scope.editing_tags = false;3975 })).toBe(false);
3935 $scope.editTags();3976 });
3936 expect($scope.editing).toBe(false);3977
3937 expect($scope.editing_tags).toBe(false);3978 it("returns false for lvm-vg", function() {
3938 });3979 var controller = makeController();
39393980 expect($scope.canEditTags({
3940 it("sets editing to true", function() {3981 type: "lvm-vg"
3941 var controller = makeController();3982 })).toBe(false);
3942 canEditSpy.and.returnValue(true);3983 });
3943 $scope.editing = false;3984
3944 $scope.editing_tags = false;3985 it("returns true for physical", function() {
3945 $scope.editTags();3986 var controller = makeController();
3946 expect($scope.editing).toBe(true);3987 expect($scope.canEditTags({
3947 expect($scope.editing_tags).toBe(true);3988 type: "physical"
3948 });3989 })).toBe(true);
3949 });3990 });
39503991
3951 describe("cancelTags", function() {3992 it("returns true for virtual", function() {
39523993 var controller = makeController();
3953 it("sets editing to false", function() {3994 expect($scope.canEditTags({
3954 var controller = makeController();3995 type: "virtual"
3955 $scope.editing = true;3996 })).toBe(true);
3956 $scope.editing_tags = true;3997 });
3957 $scope.cancelTags();3998 });
3958 expect($scope.editing).toBe(false);3999
3959 expect($scope.editing_tags).toBe(false);4000 describe("availableEditTags", function() {
3960 });4001
39614002 it("sets $options", function() {
3962 it("calls updateDisks", function() {4003 var controller = makeController();
3963 var controller = makeController();4004 var tags = [{}, {}];
39644005 var disk = {
3965 // Updates disks so we can check that updateStorage4006 tags: tags
3966 // is called.4007 };
3967 node.disks = [4008
3968 {4009 $scope.availableEditTags(disk);
3969 id: 0,4010 expect(disk.$options.editingTags).toBe(true);
3970 model: makeName("model"),4011 expect(disk.$options.tags).toEqual(tags);
3971 tags: [],4012 expect(disk.$options.tags).not.toBe(tags);
3972 available_size: 0,4013 });
3973 filesystem: null,4014 });
3974 partitions: null4015
4016 describe("availableCancelTags", function() {
4017
4018 it("clears $options", function() {
4019 var controller = makeController();
4020 var options = {};
4021 var disk = { $options: options };
4022
4023 $scope.availableCancelTags(disk);
4024 expect(disk.$options).toEqual({});
4025 expect(disk.$options).not.toBe(options);
4026 });
4027 });
4028
4029 describe("availableSaveTags", function() {
4030
4031 it("calls NodesManager.updateDiskTags", function() {
4032 var controller = makeController();
4033 var tags = [
4034 { text: "new" },
4035 { text: "old" }
4036 ];
4037 var disk = {
4038 block_id: makeInteger(0, 100),
4039 tags: [],
4040 $options: {
4041 editingTags:true,
4042 tags: tags
3975 }4043 }
3976 ];4044 };
39774045 spyOn(NodesManager, "updateDiskTags");
3978 $scope.nodeLoaded();4046
3979 $rootScope.$digest();4047 $scope.availableSaveTags(disk);
3980 var filesystems = $scope.filesystems;4048
3981 var available = $scope.available;4049 expect(NodesManager.updateDiskTags).toHaveBeenCalledWith(
3982 var used = $scope.used;4050 node, disk.block_id, ["new", "old"]);
3983 $scope.editing = true;4051 expect(disk.$options).toEqual({});
3984 $scope.editing_tags = true;4052 expect(disk.tags).toEqual(tags);
3985 $scope.cancelTags();
3986
3987 // Verify cancel calls updateStorage but doesn't change any data
3988 expect($scope.filesystems).toEqual(filesystems);
3989 expect($scope.available).toEqual(available);
3990 expect($scope.used).toEqual(used);
3991 });
3992 });
3993
3994 describe("saveTags", function() {
3995
3996 it("sets editing to false", function() {
3997 var controller = makeController();
3998
3999 $scope.editing = true;
4000 $scope.editing_tags = true;
4001 $scope.saveTags();
4002
4003 expect($scope.editing).toBe(false);
4004 expect($scope.editing_tags).toBe(false);
4005 });4053 });
4006 });4054 });
4007});4055});
40084056
=== modified file 'src/maasserver/static/partials/node-details.html'
--- src/maasserver/static/partials/node-details.html 2015-10-28 18:53:35 +0000
+++ src/maasserver/static/partials/node-details.html 2015-10-28 20:03:05 +0000
@@ -828,11 +828,19 @@
828 <div class="table__data table__column--15" colspan="2" data-ng-show="column === 'model'">{$ item.model $}</div>828 <div class="table__data table__column--15" colspan="2" data-ng-show="column === 'model'">{$ item.model $}</div>
829 <div class="table__data table__column--15 ng-hide" colspan="2" data-ng-show="column === 'serial'">{$ item.serial $}</div>829 <div class="table__data table__column--15 ng-hide" colspan="2" data-ng-show="column === 'serial'">{$ item.serial $}</div>
830 <div class="table__data table__tags table__column--15">830 <div class="table__data table__tags table__column--15">
831 <span class="table__tag" data-ng-repeat="tag in item.tags" data-ng-hide="editing_tags">831 <span class="table__tag" data-ng-repeat="tag in item.tags" data-ng-hide="item.$options.editingTags">
832 <a href="#/node/?query=storage_tags:({$ tag.text $})">{$ tag.text $}</a>832 <a href="#/node/?query=storage_tags:({$ tag.text $})">{$ tag.text $}</a>
833 </span>833 </span>
834 <tags-input ng-model="item.tags" data-ng-show="editing_tags" allow-tags-pattern="[\w-]+"></tags-input>834 <tags-input ng-model="item.$options.tags" data-ng-show="item.$options.editingTags" allow-tags-pattern="[\w-]+"></tags-input>
835 <a class="table__controls table__controls--secondary">edit</a>835 <a class="table__controls table__controls--secondary"
836 data-ng-hide="!canEditTags(item) || item.$options.editingTags"
837 data-ng-click="availableEditTags(item)">edit</a>
838 <a class="link-cta-ubuntu text-button"
839 data-ng-show="item.$options.editingTags"
840 data-ng-click="availableCancelTags(item)">Cancel</a>
841 <button class="cta-ubuntu"
842 data-ng-show="item.$options.editingTags"
843 data-ng-click="availableSaveTags(item)">Save</button>
836 </div>844 </div>
837 <div class="table__data table__column--7">845 <div class="table__data table__column--7">
838 <div class="table__controls">846 <div class="table__controls">