diff --git a/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js b/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js
new file mode 100644
index 0000000000..2ebf91cc93
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move-groups.controller.js
@@ -0,0 +1,72 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$scope', '$state', '$stateParams', 'GroupManageService', 'CopyMoveGroupList', 'group', 'Dataset',
+ function($scope, $state, $stateParams, GroupManageService, CopyMoveGroupList, group, Dataset){
+ var list = CopyMoveGroupList;
+
+ $scope.item = group;
+ $scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy';
+ $scope.toggle_row = function(id){
+ // toggle off anything else currently selected
+ _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;});
+ // yoink the currently selected thing
+ $scope.selected = _.find($scope.groups, (item) => {return item.id === id;});
+ };
+ $scope.formCancel = function(){
+ $state.go('^');
+ };
+ $scope.formSave = function(){
+ switch($scope.submitMode) {
+ case 'copy':
+ GroupManageService.associateGroup(group, $scope.selected.id).then(() => $state.go('^', null, {reload: true}));
+ break;
+ case 'move':
+ switch($scope.targetRootGroup){
+ case true:
+ // disassociating group will bubble it to the root group level
+ GroupManageService.disassociateGroup(group.id, _.last($stateParams.group)).then(() => $state.go('^', null, {reload: true}));
+ break;
+ default:
+ // at the root group level, no dissassociation is needed
+ if (!$stateParams.group){
+ GroupManageService.associateGroup(group, $scope.selected.id).then(() => $state.go('^', null, {reload: true}));
+ }
+ else{
+ // unsure if orphaned resources get garbage collected, safe bet is to associate before disassociate
+ GroupManageService.associateGroup(group, $scope.selected.id).then(() => {
+ GroupManageService.disassociateGroup(group.id, _.last($stateParams.group))
+ .then(() => $state.go('^', null, {reload: true}));
+ });
+ }
+ break;
+ }
+ }
+ };
+ $scope.toggleTargetRootGroup = function(){
+ $scope.selected = !$scope.selected;
+ // cannot perform copy operations to root group level
+ $scope.submitMode = 'move';
+ // toggle off anything currently selected in the list, for clarity
+ _.forEach($scope.groups, (item) => {item.checked = null;});
+ // disable list selections
+ $('#copyMove-list :input').each((idx, el) => {
+ $(el).prop('disabled', (idx, value) => !value);
+ });
+ };
+
+ function init(){
+ $scope.atRootLevel = $stateParams.group ? false : true;
+
+ // search init
+ $scope.list = list;
+ $scope[`${list.iterator}_dataset`] = Dataset.data;
+ $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
+ }
+
+ init();
+ }];
diff --git a/awx/ui/client/src/inventories/copy-move/copy-move-groups.list.js b/awx/ui/client/src/inventories/copy-move/copy-move-groups.list.js
new file mode 100644
index 0000000000..a207fd8e06
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move-groups.list.js
@@ -0,0 +1,24 @@
+/*************************************************
+ * Copyright (c) 2015 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+
+
+
+export default {
+ name: 'groups',
+ iterator: 'copy',
+ selectTitle: 'Copy Groups',
+ index: false,
+ well: false,
+ emptyListText: 'PLEASE CREATE ADDITIONAL GROUPS / HOSTS TO PERFORM THIS ACTION',
+ fields: {
+ name: {
+ key: true,
+ label: 'Target Group Name'
+ }
+ },
+ basePath: 'api/v2/inventories/{{$stateParams.inventory_id}}/groups'
+};
diff --git a/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js b/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js
new file mode 100644
index 0000000000..8e347dc2c8
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move-hosts.controller.js
@@ -0,0 +1,50 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$scope', '$state', '$stateParams', 'HostManageService', 'CopyMoveGroupList', 'host', 'Dataset',
+ function($scope, $state, $stateParams, HostManageService, CopyMoveGroupList, host, Dataset){
+ var list = CopyMoveGroupList;
+
+ $scope.item = host;
+ $scope.submitMode = 'copy';
+ $scope.toggle_row = function(id){
+ // toggle off anything else currently selected
+ _.forEach($scope.groups, (item) => {return item.id === id ? item.checked = 1 : item.checked = null;});
+ // yoink the currently selected thing
+ $scope.selected = _.find($scope.groups, (item) => {return item.id === id;});
+ };
+ $scope.formCancel = function(){
+ $state.go('^');
+ };
+ $scope.formSave = function(){
+ switch($scope.submitMode) {
+ case 'copy':
+ HostManageService.associateGroup(host, $scope.selected.id).then(() => $state.go('^'));
+ break;
+ case 'move':
+ // at the root group level, no dissassociation is needed
+ if (!$stateParams.group){
+ HostManageService.associateGroup(host, $scope.selected.id).then(() => $state.go('^', null, {reload: true}));
+ }
+ else{
+ HostManageService.associateGroup(host, $scope.selected.id).then(() => {
+ HostManageService.disassociateGroup(host, _.last($stateParams.group))
+ .then(() => $state.go('^', null, {reload: true}));
+ });
+ }
+ break;
+ }
+ };
+ var init = function(){
+ // search init
+ $scope.list = list;
+ $scope[`${list.iterator}_dataset`] = Dataset.data;
+ $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
+
+ };
+ init();
+ }];
diff --git a/awx/ui/client/src/inventories/copy-move/copy-move.block.less b/awx/ui/client/src/inventories/copy-move/copy-move.block.less
new file mode 100644
index 0000000000..608f59654a
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move.block.less
@@ -0,0 +1,33 @@
+@import "./client/src/shared/branding/colors.default.less";
+
+#Inventory-copyMovePanel {
+ .List-searchRow {
+ width: 50%;
+ }
+ .Form-header {
+ width: 50%;
+ margin-top: -20px;
+ }
+
+ .Form-saveButton {
+ &:disabled {
+ border-color: @default-icon-hov;
+ }
+ }
+}
+.copyMove-choices {
+ float: right;
+ width: 25%;
+ text-align: right;
+}
+.copyMove-buttons{
+ height: 30px;
+ margin-top: 20px;
+
+ button {
+ margin-left: 20px;
+ }
+}
+.copyMove-root{
+ margin-top: 10px;
+}
diff --git a/awx/ui/client/src/inventories/copy-move/copy-move.partial.html b/awx/ui/client/src/inventories/copy-move/copy-move.partial.html
new file mode 100644
index 0000000000..030f0c7e3a
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move.partial.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ Use the inventory root
+
+
+
+
+
+
diff --git a/awx/ui/client/src/inventories/copy-move/copy-move.route.js b/awx/ui/client/src/inventories/copy-move/copy-move.route.js
new file mode 100644
index 0000000000..e68c6de633
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/copy-move.route.js
@@ -0,0 +1,98 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+import {templateUrl} from '../../shared/template-url/template-url.factory';
+import { N_ } from '../../i18n';
+
+import CopyMoveGroupsController from './copy-move-groups.controller';
+import CopyMoveHostsController from './copy-move-hosts.controller';
+
+var copyMoveGroupRoute = {
+ name: 'inventories.edit.groups.copyMoveGroup',
+ url: '/copy-move-group/{group_id:int}',
+ searchPrefix: 'copy',
+ data: {
+ group_id: 'group_id',
+ },
+ params: {
+ copy_search: {
+ value: {
+ not__id__in: null
+ },
+ dynamic: true,
+ squash: ''
+ }
+ },
+ ncyBreadcrumb: {
+ label: N_("COPY OR MOVE") + " {{item.name}}"
+ },
+ resolve: {
+ Dataset: ['CopyMoveGroupList', 'QuerySet', '$stateParams', 'GetBasePath', 'group',
+ function(list, qs, $stateParams, GetBasePath, group) {
+ $stateParams.copy_search.not__id__in = ($stateParams.group && $stateParams.group.length > 0 ? group.id + ',' + _.last($stateParams.group) : group.id.toString());
+ let path = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
+ return qs.search(path, $stateParams.copy_search);
+ }
+ ],
+ group: ['GroupManageService', '$stateParams', function(GroupManageService, $stateParams){
+ return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]);
+ }]
+ },
+ views: {
+ 'copyMove@inventories' : {
+ controller: CopyMoveGroupsController,
+ templateUrl: templateUrl('inventories/copy-move/copy-move'),
+ },
+ 'copyMoveList@inventories.edit.groups.copyMoveGroup': {
+ templateProvider: function(CopyMoveGroupList, generateList) {
+ let html = generateList.build({
+ list: CopyMoveGroupList,
+ mode: 'lookup',
+ input_type: 'radio'
+ });
+ return html;
+ }
+ }
+ }
+};
+var copyMoveHostRoute = {
+ name: 'inventories.edit.hosts.copyMoveHost',
+ url: '/copy-move-host/{host_id}',
+ searchPrefix: 'copy',
+ ncyBreadcrumb: {
+ label: N_("COPY OR MOVE") + " {{item.name}}"
+ },
+ resolve: {
+ Dataset: ['CopyMoveGroupList', 'QuerySet', '$stateParams', 'GetBasePath',
+ function(list, qs, $stateParams, GetBasePath) {
+ let path = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
+ return qs.search(path, $stateParams.copy_search);
+ }
+ ],
+ host: ['HostManageService', '$stateParams', function(HostManageService, $stateParams){
+ return HostManageService.get({id: $stateParams.host_id}).then(res => res.data.results[0]);
+ }]
+ },
+ views: {
+ 'copyMove@inventories': {
+ templateUrl: templateUrl('inventories/copy-move/copy-move'),
+ controller: CopyMoveHostsController,
+ },
+ 'copyMoveList@inventories.edit.hosts.copyMoveHost': {
+ templateProvider: function(CopyMoveGroupList, generateList, $stateParams, GetBasePath) {
+ let list = CopyMoveGroupList;
+ list.basePath = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
+ let html = generateList.build({
+ list: CopyMoveGroupList,
+ mode: 'lookup',
+ input_type: 'radio'
+ });
+ return html;
+ }
+ }
+ }
+};
+
+export {copyMoveGroupRoute, copyMoveHostRoute};
diff --git a/awx/ui/client/src/inventories/copy-move/main.js b/awx/ui/client/src/inventories/copy-move/main.js
new file mode 100644
index 0000000000..a9fbd47660
--- /dev/null
+++ b/awx/ui/client/src/inventories/copy-move/main.js
@@ -0,0 +1,15 @@
+/*************************************************
+ * Copyright (c) 2015 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+import CopyMoveGroupsController from './copy-move-groups.controller';
+import CopyMoveHostsController from './copy-move-hosts.controller';
+import CopyMoveGroupList from './copy-move-groups.list';
+
+export default
+angular.module('manageCopyMove', [])
+ .controller('CopyMoveGroupsController', CopyMoveGroupsController)
+ .controller('CopyMoveHostsController', CopyMoveHostsController)
+ .value('CopyMoveGroupList', CopyMoveGroupList);
diff --git a/awx/ui/client/src/inventories/groups/list/groups-list.controller.js b/awx/ui/client/src/inventories/groups/list/groups-list.controller.js
index ba36eb6d7a..9e66fa5c9d 100644
--- a/awx/ui/client/src/inventories/groups/list/groups-list.controller.js
+++ b/awx/ui/client/src/inventories/groups/list/groups-list.controller.js
@@ -194,7 +194,7 @@
};
$scope.copyMoveGroup = function(id){
- // TODO: implement
+ $state.go('inventories.edit.groups.copyMoveGroup', {group_id: id, groups: $stateParams.groups});
};
var cleanUpStateChangeListener = $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams) {
diff --git a/awx/ui/client/src/inventories/inventories.partial.html b/awx/ui/client/src/inventories/inventories.partial.html
index 767cd197fa..d8fc0b2c60 100644
--- a/awx/ui/client/src/inventories/inventories.partial.html
+++ b/awx/ui/client/src/inventories/inventories.partial.html
@@ -1,4 +1,5 @@
+
diff --git a/awx/ui/client/src/inventories/main.js b/awx/ui/client/src/inventories/main.js
index d753bc8cd5..5df33882a7 100644
--- a/awx/ui/client/src/inventories/main.js
+++ b/awx/ui/client/src/inventories/main.js
@@ -20,6 +20,8 @@ import InventoryForm from './inventory.form';
import InventoryManageService from './inventory-manage.service';
import adHocRoute from './adhoc/adhoc.route';
import ansibleFacts from './ansible_facts/main';
+import { copyMoveGroupRoute, copyMoveHostRoute } from './copy-move/copy-move.route';
+import copyMove from './copy-move/main';
export default
angular.module('inventory', [
adhoc.name,
@@ -31,7 +33,8 @@ angular.module('inventory', [
inventoryAdd.name,
inventoryEdit.name,
inventoryList.name,
- ansibleFacts.name
+ ansibleFacts.name,
+ copyMove.name
])
.factory('InventoryForm', InventoryForm)
.factory('InventoryList', InventoryList)
@@ -41,6 +44,34 @@ angular.module('inventory', [
let stateDefinitions = stateDefinitionsProvider.$get(),
stateExtender = $stateExtenderProvider.$get();
+ function factsConfig(stateName) {
+ return {
+ name: stateName,
+ url: '/ansible_facts',
+ ncyBreadcrumb: {
+ label: N_("FACTS")
+ },
+ views: {
+ 'related': {
+ controller: 'AnsibleFactsController',
+ templateUrl: templateUrl('inventories/ansible_facts/ansible_facts')
+ }
+ },
+ resolve: {
+ Facts: ['$stateParams', 'GetBasePath', 'Rest',
+ function($stateParams, GetBasePath, Rest) {
+ let ansibleFactsUrl = GetBasePath('hosts') + $stateParams.host_id + '/ansible_facts';
+ Rest.setUrl(ansibleFactsUrl);
+ return Rest.get()
+ .success(function(data) {
+ return data;
+ });
+ }
+ ]
+ }
+ };
+ }
+
function generateInventoryStates() {
let basicInventoryAdd = stateDefinitions.generateTree({
@@ -224,31 +255,7 @@ angular.module('inventory', [
}
};
- let relatedHostsAnsibleFacts = {
- name: 'inventories.edit.hosts.edit.ansible_facts',
- url: '/ansible_facts',
- ncyBreadcrumb: {
- label: N_("FACTS")
- },
- views: {
- 'related': {
- controller: 'AnsibleFactsController',
- templateUrl: templateUrl('inventories/ansible_facts/ansible_facts')
- }
- },
- resolve: {
- Facts: ['$stateParams', 'GetBasePath', 'Rest',
- function($stateParams, GetBasePath, Rest) {
- let ansibleFactsUrl = GetBasePath('hosts') + $stateParams.host_id + '/ansible_facts';
- Rest.setUrl(ansibleFactsUrl);
- return Rest.get()
- .success(function(data) {
- return data;
- });
- }
- ]
- }
- };
+ let relatedHostsAnsibleFacts = factsConfig('inventories.edit.hosts.edit.ansible_facts');
return Promise.all([
basicInventoryAdd,
@@ -296,7 +303,9 @@ angular.module('inventory', [
stateExtender.buildDefinition(listSchedules),
stateExtender.buildDefinition(addSchedule),
stateExtender.buildDefinition(editSchedule),
- stateExtender.buildDefinition(relatedHostsAnsibleFacts)
+ stateExtender.buildDefinition(relatedHostsAnsibleFacts),
+ stateExtender.buildDefinition(copyMoveGroupRoute),
+ stateExtender.buildDefinition(copyMoveHostRoute)
])
};
});
@@ -347,31 +356,7 @@ angular.module('inventory', [
}
});
- let hostAnsibleFacts = {
- name: 'hosts.edit.ansible_facts',
- url: '/ansible_facts',
- ncyBreadcrumb: {
- label: N_("FACTS")
- },
- views: {
- 'related': {
- controller: 'AnsibleFactsController',
- templateUrl: templateUrl('inventories/ansible_facts/ansible_facts')
- }
- },
- resolve: {
- Facts: ['$stateParams', 'GetBasePath', 'Rest',
- function($stateParams, GetBasePath, Rest) {
- let ansibleFactsUrl = GetBasePath('hosts') + $stateParams.host_id + '/ansible_facts';
- Rest.setUrl(ansibleFactsUrl);
- return Rest.get()
- .success(function(data) {
- return data;
- });
- }
- ]
- }
- };
+ let hostAnsibleFacts = factsConfig('hosts.edit.ansible_facts');
return Promise.all([
hostTree
diff --git a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
index e9eaea0973..f2f960ceea 100644
--- a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
+++ b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
@@ -156,4 +156,8 @@ export default ['$scope', 'RelatedHostsListDefinition', '$rootScope', 'GetBasePa
$state.go('^.adhoc', {pattern: pattern});
};
+
+ $scope.copyMoveHost = function(id) {
+ $state.go('inventories.edit.hosts.copyMoveHost', {host_id: id});
+ };
}];