diff --git a/awx/ui/client/src/instance-groups/instance-groups.service.js b/awx/ui/client/src/instance-groups/instance-groups.service.js index cf809932c2..f8657fd36b 100644 --- a/awx/ui/client/src/instance-groups/instance-groups.service.js +++ b/awx/ui/client/src/instance-groups/instance-groups.service.js @@ -1,5 +1,5 @@ export default - ['$q', 'Rest', function($q, Rest) { + ['Rest', function(Rest) { return { addInstanceGroups: function(url, instance_groups) { let groups = (instance_groups || []); @@ -7,6 +7,24 @@ export default let defers = groups.map((group) => Rest.post(group)); return Promise.all(defers); }, + /** + * This function compares the currently saved ids and the selected ids - as soon as + * we encounter a difference between the two arrays, we mark all remaining currently + * saved ids in the array for disassociation. + * + * Example Scenario + * ----------------- + * page is loaded with [1,2,3,4,5,6] as the currently selected tags + * user removes tag 3 from the middle + * user adds a new tag 7 to the end + * user appends tag 3 to the end + * + * _______ all ids here and to the right are disassociated + * | + * current: [1,2,3,4,5,6] + * selected: [1,2,4,5,6,7,3] + * |_______ all ids here and to the right are (re)associated + */ editInstanceGroups: function(url, instance_groups) { Rest.setUrl(url); return Rest.get() @@ -49,7 +67,7 @@ export default // make the disassociate request sequence - we need to do these requests // sequentially to make sure they get processed in the right order so we // build a promise chain here instead of using .all() - let disassociationPromise = $q.resolve(); + let disassociationPromise = Promise.resolve(); groupsToDisassociate.forEach(data => { disassociationPromise = disassociationPromise.then(() => { Rest.setUrl(url); @@ -63,7 +81,7 @@ export default // we need to do these requests sequentially to make sure they get // processed in the right order so we build a promise chain here // instead of using .all() - let associationPromise = $q.resolve(); + let associationPromise = Promise.resolve(); groupsToAssociate.forEach(data => { associationPromise = associationPromise.then(() => { Rest.setUrl(url); diff --git a/awx/ui/test/spec/instance-groups/instance-groups.service-test.js b/awx/ui/test/spec/instance-groups/instance-groups.service-test.js new file mode 100644 index 0000000000..082cd782a2 --- /dev/null +++ b/awx/ui/test/spec/instance-groups/instance-groups.service-test.js @@ -0,0 +1,73 @@ +'use strict'; + +const mockUrl = ''; +const mockSavedInstanceGroups = { + data: { + results: [ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, + { id: 6 }, + ] + } +}; + +const _postData = []; +function MockRest() { + return { + setUrl (){}, + get () { + return Promise.resolve(mockSavedInstanceGroups); + }, + post (data) { + _postData.push(data); + return Promise.resolve({}); + }, + } +} + +describe('instanceGroupsService', () => { + let instanceGroupsService; + + beforeEach(() => { + angular.mock.module('awApp'); + angular.mock.module($provide => { + $provide.service('Rest', MockRest); + }); + angular.mock.module('instanceGroups'); + angular.mock.inject($injector => { + instanceGroupsService = $injector.get('InstanceGroupsService'); + }); + }); + + describe('editInstanceGroups', () => { + it('makes the expected requests', (done) => { + const selectedInstanceGroups = [ + { id: 1 }, + { id: 2 }, + { id: 4 }, + { id: 5 }, + { id: 6 }, + { id: 7 }, + { id: 3 }, + ]; + instanceGroupsService.editInstanceGroups(mockUrl, selectedInstanceGroups) + .then(() => { + expect(_postData).toEqual([ + { id: 3, disassociate: true }, + { id: 4, disassociate: true }, + { id: 5, disassociate: true }, + { id: 6, disassociate: true }, + { id: 4, associate: true }, + { id: 5, associate: true }, + { id: 6, associate: true }, + { id: 7, associate: true }, + { id: 3, associate: true }, + ]); + }) + .finally(() => done()); + }); + }); +});