diff --git a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js index 169a9d6b7a..c1567200d2 100644 --- a/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js +++ b/awx/ui/client/src/inventories-hosts/hosts/related/groups/hosts-related-groups-associate.route.js @@ -13,7 +13,7 @@ export default { controller: function($scope, $q, GroupsService, $state){ $scope.associateGroups = function(selectedItems){ var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) ) + return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) ) .then( () =>{ deferred.resolve(); }, (error) => { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js index 6125e02da7..294dcf031c 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-groups/group-nested-groups-associate.route.js @@ -13,7 +13,7 @@ export default { controller: function($scope, $q, GroupsService, $state){ $scope.associateGroups = function(selectedItems){ var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (id) => GroupsService.associateGroup({id: id}, $state.params.group_id)) ) + return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateGroup({id: selectedItem.id}, $state.params.group_id)) ) .then( () =>{ deferred.resolve(); }, (error) => { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js index df09d30d80..959055ad02 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/groups/related/nested-hosts/group-nested-hosts-associate.route.js @@ -13,7 +13,7 @@ export default { controller: function($scope, $q, GroupsService, $state){ $scope.associateHosts = function(selectedItems){ var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: id}, $state.params.group_id)) ) + return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: selectedItem.id}, $state.params.group_id)) ) .then( () =>{ deferred.resolve(); }, (error) => { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js index 2b9a865b18..d17a181687 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/hosts/related/nested-groups/host-nested-groups-associate.route.js @@ -13,7 +13,7 @@ export default { controller: function($scope, $q, GroupsService, $state){ $scope.associateGroups = function(selectedItems){ var deferred = $q.defer(); - return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) ) + return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) ) .then( () =>{ deferred.resolve(); }, (error) => { diff --git a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js index ec06428d96..f6f4fc4bed 100644 --- a/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js +++ b/awx/ui/client/src/inventories-hosts/shared/associate-groups/associate-groups.controller.js @@ -35,6 +35,10 @@ list.multiSelect = true; list.fields.name.ngClick = 'linkoutGroup(associate_group.id)'; list.trackBy = 'associate_group.id'; + list.multiSelectPreview = { + selectedRows: 'selectedItems', + availableRows: 'associate_groups' + }; delete list.actions; delete list.fieldActions; delete list.fields.failed_hosts; @@ -58,9 +62,11 @@ $scope.$watchCollection('associate_groups', function () { if($scope.selectedItems) { $scope.associate_groups.forEach(function(row, i) { - if (_.includes($scope.selectedItems, row.id)) { - $scope.associate_groups[i].isSelected = true; - } + $scope.selectedItems.forEach(function(selectedItem) { + if(selectedItem.id === row.id) { + $scope.associate_groups[i].isSelected = true; + } + }); }); } }); @@ -72,14 +78,14 @@ let item = value.value; if (value.isSelected) { - $scope.selectedItems.push(item.id); + $scope.selectedItems.push(item); } else { // _.remove() Returns the new array of removed elements. // This will pull all the values out of the array that don't // match the deselected item effectively removing it $scope.selectedItems = _.remove($scope.selectedItems, function(selectedItem) { - return selectedItem !== item.id; + return selectedItem.id !== item.id; }); } }); diff --git a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js index 9f3ef11658..271ed97901 100644 --- a/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js +++ b/awx/ui/client/src/shared/instance-groups-multiselect/instance-groups-modal/instance-groups-modal.directive.js @@ -46,7 +46,10 @@ export default ['templateUrl', function(templateUrl) { instanceGroupList.listTitle = false; instanceGroupList.well = false; instanceGroupList.multiSelect = true; - instanceGroupList.multiSelectExtended = true; + instanceGroupList.multiSelectPreview = { + selectedRows: 'igTags', + availableRows: 'instance_groups' + }; delete instanceGroupList.fields.percent_capacity_remaining; delete instanceGroupList.fields.jobs_running; @@ -104,4 +107,4 @@ export default ['templateUrl', function(templateUrl) { }; }] }; -}]; \ No newline at end of file +}]; diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js index a735c16ff7..e4ac25273e 100644 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ b/awx/ui/client/src/shared/list-generator/list-generator.factory.js @@ -163,6 +163,10 @@ export default ['$compile', 'Attr', 'Icon', html += "\n"; } + if (list.multiSelectPreview) { + html += ""; + } + if (options.instructions) { html += "
" + options.instructions + "
\n"; } else if (list.instructions) { diff --git a/awx/ui/client/src/shared/main.js b/awx/ui/client/src/shared/main.js index 3fdf3bdf95..1f4d57cfc5 100644 --- a/awx/ui/client/src/shared/main.js +++ b/awx/ui/client/src/shared/main.js @@ -32,6 +32,7 @@ import directives from './directives'; import features from './features/main'; import orgAdminLookup from './org-admin-lookup/main'; import limitPanels from './limit-panels/main'; +import multiSelectPreview from './multi-select-preview/main'; import 'angular-duration-format'; export default @@ -61,6 +62,7 @@ angular.module('shared', [listGenerator.name, features.name, orgAdminLookup.name, limitPanels.name, + multiSelectPreview.name, require('angular-cookies'), 'angular-duration-format' ]) diff --git a/awx/ui/client/src/shared/multi-select-preview/main.js b/awx/ui/client/src/shared/multi-select-preview/main.js new file mode 100644 index 0000000000..1f50c494c0 --- /dev/null +++ b/awx/ui/client/src/shared/multi-select-preview/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import multiSelectPreview from './multi-select-preview.directive'; + +export default + angular.module('multiSelectPreview', []) + .directive('multiSelectPreview', multiSelectPreview); diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less new file mode 100644 index 0000000000..e0cdc87bcf --- /dev/null +++ b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.block.less @@ -0,0 +1,99 @@ +@import '../branding/colors.default.less'; + +.MultiSelectPreview { + display: flex; + flex: 1 0 auto; + margin-bottom: 15px; + align-items: baseline; +} + +.MultiSelectPreview-selectedItems { + display: flex; + flex: 0 0 100%; + background-color: @default-no-items-bord; + border: 1px solid @default-border; + padding: 10px; + border-radius: 5px; +} + +.MultiSelectPreview-selectedItemsLabel, .MultiSelectPreview-label { + color: @default-interface-txt; + margin-right: 10px; +} + +.MultiSelectPreview-selectedItemsLabel { + flex: 0 0 80px; + line-height: 29px; +} + +.MultiSelectPreview-previewTags--outer { + flex: 1 0 auto; + max-width: ~"calc(100% - 140px)"; +} + +.MultiSelectPreview-previewTags--inner { + display: flex; + flex-wrap: wrap; + align-items: flex-start; +} + +.MultiSelectPreview-previewTagContainer { + display: flex; +} + +.MultiSelectPreview-previewTagRevert { + flex: 0 0 60px; + line-height: 29px; +} + +.MultiSelectPreview-revertLink { + font-size: 12px; +} + +.MultiSelectPreview-previewTagContainerDelete { + background-color: @default-link; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + color: @default-bg; + padding: 0 5px; + margin: 4px 0px; + align-items: center; + display: flex; + cursor: pointer; +} + +.MultiSelectPreview-previewTagContainerDelete:hover { + border-color: @default-err; + background-color: @default-err; +} + +.MultiSelectPreview-previewTagContainerDelete:hover > .MultiSelectPreview-previewTagContainerTagDelete { + color: @default-bg; +} + +.MultiSelectPreview-previewTag { + border-radius: 5px; + padding: 2px 10px; + margin: 4px 0px; + font-size: 12px; + color: @default-interface-txt; + background-color: @default-list-header-bg; + margin-right: 5px; + max-width: 100%; + display: inline-block; +} + +.MultiSelectPreview-previewTagLabel { + color: @default-list-header-bg; +} + +.MultiSelectPreview-previewTag--deletable { + color: @default-bg; + background-color: @default-link; + margin-right: 0px; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; + border-right: 0; + max-width: ~"calc(100% - 23px)"; + margin-right: 5px; +} diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js new file mode 100644 index 0000000000..be166234c7 --- /dev/null +++ b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.controller.js @@ -0,0 +1,21 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default ['$scope', + function ($scope) { + $scope.unselectSelectedRow = function(index) { + + angular.forEach($scope.availableRows, function(value) { + if(value.id === $scope.selectedRows[index].id) { + value.isSelected = false; + } + }); + + $scope.selectedRows.splice(index, 1); + + }; + } +]; diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js new file mode 100644 index 0000000000..6805840f19 --- /dev/null +++ b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.directive.js @@ -0,0 +1,20 @@ +/************************************************* + * Copyright (c) 2017 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + import MultiSelectPreviewController from './multi-select-preview.controller'; + + export default ['templateUrl', function(templateUrl) { + return { + restrict: 'E', + replace: true, + scope: { + selectedRows: '=', + availableRows: '=' + }, + controller: MultiSelectPreviewController, + templateUrl: templateUrl('shared/multi-select-preview/multi-select-preview') + }; + }]; diff --git a/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html new file mode 100644 index 0000000000..ba96157381 --- /dev/null +++ b/awx/ui/client/src/shared/multi-select-preview/multi-select-preview.partial.html @@ -0,0 +1,19 @@ +
+
+
+ SELECTED: +
+
+
+
+
+ +
+
+ {{selectedRow.name}} +
+
+
+
+
+