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: '
" + + 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 += `