diff --git a/awx/ui/client/src/inventories/related-hosts/main.js b/awx/ui/client/src/inventories/related-hosts/main.js index 2f892270b3..023d0c3dab 100644 --- a/awx/ui/client/src/inventories/related-hosts/main.js +++ b/awx/ui/client/src/inventories/related-hosts/main.js @@ -9,12 +9,14 @@ import relatedHostList from './list/main'; import relatedHostsListDefinition from './related-host.list'; import relatedHostsFormDefinition from './related-host.form'; + import relatedGroupsLabels from './related-groups-labels/main'; export default angular.module('relatedHost', [ relatedHostAdd.name, relatedHostEdit.name, - relatedHostList.name + relatedHostList.name, + relatedGroupsLabels.name ]) .factory('RelatedHostsFormDefinition', relatedHostsFormDefinition) - .value('RelatedHostsListDefinition', relatedHostsListDefinition); + .factory('RelatedHostsListDefinition', relatedHostsListDefinition); diff --git a/awx/ui/client/src/inventories/related-hosts/related-groups-labels/main.js b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/main.js new file mode 100644 index 0000000000..a3be739b8a --- /dev/null +++ b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import relatedGroupsabelsList from './relatedGroupsLabelsList.directive'; + +export default + angular.module('relatedGroupsLabels', []) + .directive('relatedGroupsLabelsList', relatedGroupsabelsList); diff --git a/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.block.less b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.block.less new file mode 100644 index 0000000000..7261b6f762 --- /dev/null +++ b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.block.less @@ -0,0 +1,3 @@ +.RelatedGroupsLabelsCell{ + width:100%; +} diff --git a/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.directive.js b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.directive.js new file mode 100644 index 0000000000..f8638403d9 --- /dev/null +++ b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.directive.js @@ -0,0 +1,103 @@ +/* jshint unused: vars */ +export default + [ 'templateUrl', + 'Wait', + 'Rest', + 'GetBasePath', + 'ProcessErrors', + 'Prompt', + '$q', + '$filter', + '$state', + function(templateUrl, Wait, Rest, GetBasePath, ProcessErrors, Prompt, $q, $filter, $state) { + return { + restrict: 'E', + scope: false, + templateUrl: templateUrl('inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList'), + link: function(scope, element, attrs) { + scope.showDelete = attrs.showDelete === 'true'; + scope.seeMoreInactive = true; + + var getNext = function(data, arr, resolve) { + Rest.setUrl(data.next); + Rest.get() + .success(function (data) { + if (data.next) { + getNext(data, arr.concat(data.results), resolve); + } else { + resolve.resolve(arr.concat(data.results)); + } + }); + }; + + scope.seeMore = function () { + var seeMoreResolve = $q.defer(); + Rest.setUrl(scope[scope.$parent.list.iterator].related.groups); + Rest.get() + .success(function(data) { + if (data.next) { + getNext(data, data.results, seeMoreResolve); + } else { + seeMoreResolve.resolve(data.results); + } + }); + + seeMoreResolve.promise.then(function (groups) { + scope.related_groups = groups; + scope.seeMoreInactive = false; + }); + }; + + scope.seeLess = function() { + // Trim the groups array back down to 10 items + scope.related_groups = scope.related_groups.slice(0, 5); + // Re-set the seeMoreInteractive flag so that the "See More" will be displayed + scope.seeMoreInactive = true; + }; + + scope.deleteLabel = function(host, group) { + var action = function () { + $('#prompt-modal').modal('hide'); + scope.seeMoreInactive = true; + Wait('start'); + let url = `${GetBasePath('groups')}${group.id}/hosts`; + if(url) { + Rest.setUrl(url); + Rest.post({"disassociate": true, "id": host.id}) + .success(function () { + Wait('stop'); + $state.go('.', null, {reload: true}); + }) + .error(function (data, status) { + Wait('stop'); + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Could not disassociate host from group. Call to ' + url + ' failed. DELETE returned status: ' + status }); + }); + } + }; + + Prompt({ + hdr: 'Remove host from ' + group.name , + body: '
Confirm the removal of the ' + $filter('sanitize')(host.name) + ' from the ' + $filter('sanitize')(group.name) + ' group.
', + action: action, + actionText: 'REMOVE' + }); + }; + + scope.$watchCollection(scope.$parent.list.iterator, function() { + // To keep the array of groups fresh, we need to set up a watcher - otherwise, the + // array will get set initially and then never be updated as groups are removed + if (scope[scope.$parent.list.iterator].summary_fields.groups){ + scope.related_groups = scope[scope.$parent.list.iterator].summary_fields.groups.results; + scope.count = scope[scope.$parent.list.iterator].summary_fields.groups.count; + } + else{ + scope.related_groups = null; + scope.count = null; + } + }); + + } + }; + } + ]; diff --git a/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.partial.html b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.partial.html new file mode 100644 index 0000000000..ae6448212b --- /dev/null +++ b/awx/ui/client/src/inventories/related-hosts/related-groups-labels/relatedGroupsLabelsList.partial.html @@ -0,0 +1,14 @@ +
+
+ +
+
+ {{ related_group.name }} +
+
+
View More
+
View Less
diff --git a/awx/ui/client/src/inventories/related-hosts/related-host.list.js b/awx/ui/client/src/inventories/related-hosts/related-host.list.js index 698d1cd853..3222aed824 100644 --- a/awx/ui/client/src/inventories/related-hosts/related-host.list.js +++ b/awx/ui/client/src/inventories/related-hosts/related-host.list.js @@ -4,127 +4,158 @@ * All Rights Reserved *************************************************/ -export default { - name: 'hosts', - iterator: 'host', - editTitle: '{{ selected_group }}', - showTitle: false, - well: true, - wellOverride: true, - index: false, - hover: true, - // hasChildren: true, - multiSelect: true, - trackBy: 'host.id', - basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/hosts/', +export default ['i18n', function(i18n) { + return { + name: 'hosts', + iterator: 'host', + editTitle: '{{ selected_group }}', + showTitle: false, + well: true, + wellOverride: true, + index: false, + hover: true, + // hasChildren: true, + multiSelect: true, + trackBy: 'host.id', + basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/hosts/', - fields: { - active_failures: { - label: '', - iconOnly: true, - nosort: true, - // do not remove this ng-click directive - // the list generator case to handle fields without ng-click - // cannot handle the aw-* directives - ngClick: 'noop()', - awPopOver: "{{ host.job_status_html }}", - dataTitle: "{{ host.job_status_title }}", - awToolTip: "{{ host.badgeToolTip }}", - dataPlacement: 'top', - icon: "{{ 'fa icon-job-' + host.active_failures }}", - id: 'active-failures-action', - columnClass: 'status-column List-staticColumn--smallStatus' + fields: { + toggleHost: { + ngDisabled: 'host.has_inventory_sources', + label: '', + columnClass: 'List-staticColumn--toggle', + type: "toggle", + ngClick: "toggleHost($event, host)", + awToolTip: "

" + + i18n._("Indicates if a host is available and should be included in running jobs.") + + "

" + + i18n._("For hosts that are part of an external" + + " inventory, this flag cannot be changed. It will be" + + " set by the inventory sync process.") + + "

", + dataPlacement: "right", + nosort: true, + }, + active_failures: { + label: '', + iconOnly: true, + nosort: true, + // do not remove this ng-click directive + // the list generator case to handle fields without ng-click + // cannot handle the aw-* directives + ngClick: 'noop()', + awPopOver: "{{ host.job_status_html }}", + dataTitle: "{{ host.job_status_title }}", + awToolTip: "{{ host.badgeToolTip }}", + dataPlacement: 'top', + icon: "{{ 'fa icon-job-' + host.active_failures }}", + id: 'active-failures-action', + columnClass: 'status-column List-staticColumn--smallStatus' + }, + name: { + key: true, + label: 'Hosts', + ngClick: "editHost(host)", + ngClass: "{ 'host-disabled-label': !host.enabled }", + columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', + dataHostId: "{{ host.id }}", + dataType: "host", + class: 'InventoryManage-breakWord' + }, + groups: { + label: "Related Groups", + type: 'related_groups', + nosort: true, + showDelete: true, + columnClass: 'RelatedGroupsLabelsCell List-tableCell col-lg-2 col-md-3 hidden-sm hidden-xs' + // ngBind: 'host.summary_fields.groups', + // ngClass: "{ 'host-disabled-label': !host.enabled }", + // columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', + // dataHostId: "{{ host.id }}", + // dataType: "host", + // class: 'InventoryManage-breakWord' + + } }, - name: { - key: true, - label: 'Hosts', - ngClick: "editHost(host)", - ngClass: "{ 'host-disabled-label': !host.enabled }", - columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', - dataHostId: "{{ host.id }}", - dataType: "host", - class: 'InventoryManage-breakWord' + + fieldActions: { + + columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', + insights: { + ngClick: "goToInsights(host)", + icon: 'fa-info', + awToolTip: 'View Insights Data', + dataPlacement: 'top', + ngShow: 'host.insights_system_id' + }, + copy: { + mode: 'all', + ngClick: "copyMoveHost(host.id)", + awToolTip: 'Copy or move host to another group', + dataPlacement: "top", + ngShow: 'host.summary_fields.user_capabilities.edit' + }, + edit: { + //label: 'Edit', + ngClick: "editHost(host)", + icon: 'icon-edit', + awToolTip: 'Edit host', + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.edit' + }, + view: { + //label: 'Edit', + ngClick: "editHost(host)", + awToolTip: 'View host', + dataPlacement: 'top', + ngShow: '!host.summary_fields.user_capabilities.edit' + }, + "delete": { + //label: 'Delete', + ngClick: "deleteHost(host.id, host.name)", + icon: 'icon-trash', + awToolTip: 'Delete host', + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.delete' + } + }, + + actions: { + launch: { + mode: 'all', + ngDisabled: '!hostsSelected', + ngClick: 'setAdhocPattern()', + awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single host or a selection of multiple hosts.", + dataPlacement: 'top', + actionClass: 'btn List-buttonDefault', + buttonContent: 'RUN COMMANDS', + showTipWhenDisabled: true, + tooltipInnerClass: "Tooltip-wide", + // TODO: we don't always want to show this + ngShow: true + }, + system_tracking: { + buttonContent: 'System Tracking', + ngClick: 'systemTracking()', + awToolTip: "Select one or two hosts by clicking the checkbox beside the host. System tracking offers the ability to compare the results of two scan runs from different dates on one host or the same date on two hosts.", + dataTipWatch: "systemTrackingTooltip", + dataPlacement: 'top', + awFeature: 'system_tracking', + actionClass: 'btn List-buttonDefault system-tracking', + ngDisabled: 'systemTrackingDisabled || !hostsSelected', + showTipWhenDisabled: true, + tooltipInnerClass: "Tooltip-wide", + ngShow: true + }, + create: { + mode: 'all', + ngClick: "createHost()", + awToolTip: "Create a new host", + actionClass: 'btn List-buttonSubmit', + buttonContent: '+ ADD HOST', + ngShow: 'canAdd', + dataPlacement: "top", + } } - }, - - fieldActions: { - - columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', - insights: { - ngClick: "goToInsights(host)", - icon: 'fa-info', - awToolTip: 'View Insights Data', - dataPlacement: 'top', - ngShow: 'host.insights_system_id' - }, - copy: { - mode: 'all', - ngClick: "copyMoveHost(host.id)", - awToolTip: 'Copy or move host to another group', - dataPlacement: "top", - ngShow: 'host.summary_fields.user_capabilities.edit' - }, - edit: { - //label: 'Edit', - ngClick: "editHost(host)", - icon: 'icon-edit', - awToolTip: 'Edit host', - dataPlacement: 'top', - ngShow: 'host.summary_fields.user_capabilities.edit' - }, - view: { - //label: 'Edit', - ngClick: "editHost(host)", - awToolTip: 'View host', - dataPlacement: 'top', - ngShow: '!host.summary_fields.user_capabilities.edit' - }, - "delete": { - //label: 'Delete', - ngClick: "deleteHost(host.id, host.name)", - icon: 'icon-trash', - awToolTip: 'Delete host', - dataPlacement: 'top', - ngShow: 'host.summary_fields.user_capabilities.delete' - } - }, - - actions: { - launch: { - mode: 'all', - ngDisabled: '!hostsSelected', - ngClick: 'setAdhocPattern()', - awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single host or a selection of multiple hosts.", - dataPlacement: 'top', - actionClass: 'btn List-buttonDefault', - buttonContent: 'RUN COMMANDS', - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - // TODO: we don't always want to show this - ngShow: true - }, - system_tracking: { - buttonContent: 'System Tracking', - ngClick: 'systemTracking()', - awToolTip: "Select one or two hosts by clicking the checkbox beside the host. System tracking offers the ability to compare the results of two scan runs from different dates on one host or the same date on two hosts.", - dataTipWatch: "systemTrackingTooltip", - dataPlacement: 'top', - awFeature: 'system_tracking', - actionClass: 'btn List-buttonDefault system-tracking', - ngDisabled: 'systemTrackingDisabled || !hostsSelected', - showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide", - ngShow: true - }, - create: { - mode: 'all', - ngClick: "createHost()", - awToolTip: "Create a new host", - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD HOST', - ngShow: 'canAdd', - dataPlacement: "top", - } - } - -}; + }; +}]; diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js index 25186a2e5e..a30f847d76 100644 --- a/awx/ui/client/src/shared/generator-helpers.js +++ b/awx/ui/client/src/shared/generator-helpers.js @@ -491,13 +491,23 @@ angular.module('GeneratorHelpers', [systemStatus.name]) `; } else if (field.type === 'labels') { - var showDelete = field.showDelete === undefined ? true : field.showDelete; + let showDelete = field.showDelete === undefined ? true : field.showDelete; classList = (field.columnClass) ? Attr(field, 'columnClass') : ""; html += ` + + `; + } else if (field.type === 'related_groups') { + let showDelete = field.showDelete === undefined ? true : field.showDelete; + classList = (field.columnClass) ? + Attr(field, 'columnClass') : ""; + html += ` + + + `; } else if (field.type === 'owners') {