elements
- $(this).remove();
- });
- $('.popover').each(function () {
- // remove lingering popover
elements
- $(this).remove();
- });
- $('#status-modal-dialog').dialog('destroy');
- $('#inventory-modal-container').empty();
- },
- open: function () {
- Wait('stop');
- }
- });
-
- function calcRows(content) {
- var n = content.match(/\n/g),
- rows = (n) ? n.length : 1;
- return (rows > maxrows) ? 20 : rows;
- }
-
- Wait('start');
- url = GetBasePath('jobs') + job_id + '/';
- Rest.setUrl(url);
- Rest.get()
- .success(function (data) {
- var cDate;
- scope.id = data.id;
- scope.name = data.name;
- scope.status = data.status;
- scope.result_stdout = data.result_stdout;
- scope.result_traceback = data.result_traceback;
- scope.stdout_rows = calcRows(scope.result_stdout);
- scope.traceback_rows = calcRows(scope.result_traceback);
- cDate = new Date(data.created);
- scope.created = FormatDate(cDate);
- $('#status-modal-dialog').dialog('open');
- })
- .error(function (data, status) {
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Attempt to load job failed. GET returned status: ' + status });
- });
- };
-
- }
- ])
-
-
+
.factory('JobsListUpdate', ['Rest', function(Rest) {
return function(params) {
var scope = params.scope,
diff --git a/awx/ui/client/src/helpers/inventory.js b/awx/ui/client/src/helpers/inventory.js
index 9becb2dbb9..18a8b27883 100644
--- a/awx/ui/client/src/helpers/inventory.js
+++ b/awx/ui/client/src/helpers/inventory.js
@@ -81,217 +81,4 @@ export default
});
};
}
- ])
-
- .factory('EditInventoryProperties', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
- 'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit', 'ParseVariableString', 'CreateDialog', 'TextareaResize',
- function (InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, SaveInventory,
- Wait, Store, SearchInit, ParseVariableString, CreateDialog, TextareaResize) {
- return function (params) {
-
- var parent_scope = params.scope,
- inventory_id = params.inventory_id,
- generator = GenerateForm,
- form = InventoryForm,
- master = {},
- //PreviousSearchParams = Store('CurrentSearchParams'),
- buttons,
- scope = parent_scope.$new();
-
- form.well = false;
-
- var form_scope =
- generator.inject(form, {
- mode: 'edit',
- showButtons: false,
- showActions: false,
- id: 'inventory-edit-modal-dialog',
- related: false,
- scope: scope
- });
-
- /* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */
- form.well = true;
-
- buttons = [{
- label: "Cancel",
- onClick: function() {
- scope.cancelModal();
- },
- icon: "fa-times",
- "class": "btn btn-default",
- "id": "inventory-edit-cancel-button"
- },{
- label: "Save",
- onClick: function() {
- scope.saveModal();
- },
- icon: "fa-check",
- "class": "btn btn-primary",
- "id": "inventory-edit-save-button"
- }];
-
- CreateDialog({
- scope: scope,
- buttons: buttons,
- width: 675,
- height: 750,
- minWidth: 400,
- title: 'Inventory Properties',
- id: 'inventory-edit-modal-dialog',
- closeOnEscape: false,
- form: form_scope.inventory_form,
- onClose: function() {
- Wait('stop');
- scope.codeMirror.destroy();
- $('#inventory-edit-modal-dialog').empty();
- },
- onResizeStop: function() {
- TextareaResize({
- scope: scope,
- textareaId: 'inventory_variables',
- modalId: 'inventory-edit-modal-dialog',
- formId: 'inventory_form'
- });
- },
- beforeDestroy: function() {
- if (scope.codeMirror) {
- scope.codeMirror.destroy();
- }
- $('#inventory-edit-modal-dialog').empty();
- },
- onOpen: function() {
- $('#inventory_name').focus();
- setTimeout(function() {
- TextareaResize({
- scope: scope,
- textareaId: 'inventory_variables',
- modalId: 'inventory-edit-modal-dialog',
- formId: 'inventory_form',
- parse: true
- });
- }, 300);
- },
- callback: 'InventoryEditDialogReady'
- });
-
- scope.parseType = 'yaml';
-
- if (scope.removeInventoryPropertiesLoaded) {
- scope.removeInventoryPropertiesLoaded();
- }
- scope.removeInventoryPropertiesLoaded = scope.$on('inventoryPropertiesLoaded', function() {
- Wait('stop');
- $('#inventory-edit-modal-dialog').dialog('open');
- });
-
- scope.formModalActionLabel = 'Save';
- scope.formModalCancelShow = true;
- scope.formModalInfo = false;
- scope.formModalHeader = 'Inventory Properties';
-
- Wait('start');
- Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
- Rest.get()
- .success(function (data) {
- var fld;
- for (fld in form.fields) {
- if (fld === 'variables') {
- scope.variables = ParseVariableString(data.variables);
- master.variables = scope.variables;
- } else if (fld === 'inventory_name') {
- scope[fld] = data.name;
- master[fld] = scope[fld];
- } else if (fld === 'inventory_description') {
- scope[fld] = data.description;
- master[fld] = scope[fld];
- } else if (data[fld]) {
- scope[fld] = data[fld];
- master[fld] = scope[fld];
- }
- if (form.fields[fld].sourceModel && data.summary_fields &&
- data.summary_fields[form.fields[fld].sourceModel]) {
- scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
- data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
- master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
- data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
- }
- }
-
- LookUpInit({
- scope: scope,
- form: form,
- current_item: scope.organization,
- list: OrganizationList,
- field: 'organization',
- input_type: 'radio'
- });
-
- scope.$emit('inventoryPropertiesLoaded');
-
- })
- .error(function (data, status) {
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status });
- });
-
- if (scope.removeInventorySaved) {
- scope.removeInventorySaved();
- }
- scope.removeInventorySaved = scope.$on('InventorySaved', function () {
- //$('#form-modal').modal('hide');
- // Restore prior search state
- //if (scope.searchCleanp) {
- // scope.searchCleanup();
- //}
- //SearchInit({
- // scope: parent_scope,
- // set: PreviousSearchParams.set,
- // list: PreviousSearchParams.list,
- // url: PreviousSearchParams.defaultUrl,
- // iterator: PreviousSearchParams.iterator,
- // sort_order: PreviousSearchParams.sort_order,
- // setWidgets: false
- //});
- //parent_scope.$emit('RefreshInventories');
- try {
- $('#inventory-edit-modal-dialog').dialog('close');
- }
- catch(err) {
- // ignore
- }
- parent_scope.$emit('RefreshInventories');
- scope.$destroy();
- });
-
- scope.cancelModal = function () {
- // Restore prior search state
- /*if (scope.searchCleanp) {
- scope.searchCleanup();
- }
- SearchInit({
- scope: parent_scope,
- set: PreviousSearchParams.set,
- list: PreviousSearchParams.list,
- url: PreviousSearchParams.defaultUrl,
- iterator: PreviousSearchParams.iterator,
- sort_order: PreviousSearchParams.sort_order,
- setWidgets: false
- });*/
- try {
- $('#inventory-edit-modal-dialog').dialog('close');
- }
- catch(err) {
- // ignore
- }
- scope.$destroy();
- };
-
- scope.saveModal = function () {
- scope.inventory_id = inventory_id;
- SaveInventory({ scope: scope, parent_scope: parent_scope });
- };
-
- };
- }
]);
diff --git a/awx/ui/client/src/inventories/inventories.partial.html b/awx/ui/client/src/inventories/inventories.partial.html
index 46d04b20dd..0284089d54 100644
--- a/awx/ui/client/src/inventories/inventories.partial.html
+++ b/awx/ui/client/src/inventories/inventories.partial.html
@@ -1,13 +1,5 @@
diff --git a/awx/ui/client/src/adhoc/adhoc.controller.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js
similarity index 97%
rename from awx/ui/client/src/adhoc/adhoc.controller.js
rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js
index 4ccf56ca54..a1be88d05c 100644
--- a/awx/ui/client/src/adhoc/adhoc.controller.js
+++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.controller.js
@@ -9,7 +9,7 @@
* @name controllers.function:Adhoc
* @description This controller controls the adhoc form creation, command launching and navigating to standard out after command has been succesfully ran.
*/
-function adhocController($q, $scope, $rootScope, $location, $stateParams,
+function adhocController($q, $scope, $location, $stateParams,
$state, CheckPasswords, PromptForPasswords, CreateLaunchDialog, adhocForm,
GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices,
KindChange, LookUpInit, CredentialList, Empty, Wait) {
@@ -23,7 +23,7 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams,
this.privateFn = privateFn;
var id = $stateParams.inventory_id,
- hostPattern = $rootScope.hostPatterns || "all";
+ hostPattern = $stateParams.pattern;
// note: put any urls that the controller will use in here!!!!
privateFn.setAvailableUrls = function() {
@@ -102,7 +102,6 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams,
privateFn.instantiateHostPatterns = function(hostPattern) {
$scope.limit = hostPattern;
$scope.providedHostPatterns = $scope.limit;
- delete $rootScope.hostPatterns;
};
// call helpers to initialize lookup and select fields through get
@@ -295,7 +294,7 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams,
}
-export default ['$q', '$scope', '$rootScope', '$location', '$stateParams',
+export default ['$q', '$scope', '$location', '$stateParams',
'$state', 'CheckPasswords', 'PromptForPasswords', 'CreateLaunchDialog', 'adhocForm',
'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
'GetChoices', 'KindChange', 'LookUpInit', 'CredentialList', 'Empty', 'Wait',
diff --git a/awx/ui/client/src/adhoc/adhoc.form.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js
similarity index 97%
rename from awx/ui/client/src/adhoc/adhoc.form.js
rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js
index 44a5c3ba6d..6c61349352 100644
--- a/awx/ui/client/src/adhoc/adhoc.form.js
+++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.form.js
@@ -122,20 +122,19 @@ export default function() {
dataContainer: "body"
},
},
-
buttons: {
- reset: {
- ngClick: 'formReset()',
- ngDisabled: true,
- label: 'Reset',
- 'class': 'Form-buttonDefault Form-button'
- },
launch: {
label: 'Save',
ngClick: 'launchJob()',
ngDisabled: true,
- 'class': 'Form-buttonDefault Form-button'
- }
+ 'class': 'btn btn-sm List-buttonSubmit'
+ },
+ reset: {
+ ngClick: 'formReset()',
+ ngDisabled: true,
+ label: 'Reset',
+ 'class': 'btn btn-sm Form-cancelButton'
+ }
},
related: {}
diff --git a/awx/ui/client/src/adhoc/adhoc.partial.html b/awx/ui/client/src/inventories/manage/adhoc/adhoc.partial.html
similarity index 100%
rename from awx/ui/client/src/adhoc/adhoc.partial.html
rename to awx/ui/client/src/inventories/manage/adhoc/adhoc.partial.html
diff --git a/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js
new file mode 100644
index 0000000000..17307ff562
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js
@@ -0,0 +1,24 @@
+/*************************************************
+ * Copyright (c) 2015 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ import {templateUrl} from '../../../shared/template-url/template-url.factory';
+
+export default {
+ route: '/adhoc',
+ params:{
+ pattern: {
+ value: 'all',
+ squash: true
+ }
+ },
+ name: 'inventoryManage.adhoc',
+ views: {
+ 'form@inventoryManage': {
+ templateUrl: templateUrl('inventories/manage/adhoc/adhoc'),
+ controller: 'adhocController'
+ }
+ }
+};
diff --git a/awx/ui/client/src/inventories/manage/adhoc/main.js b/awx/ui/client/src/inventories/manage/adhoc/main.js
new file mode 100644
index 0000000000..7072a23063
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/adhoc/main.js
@@ -0,0 +1,11 @@
+import route from './adhoc.route';
+import adhocController from './adhoc.controller';
+import form from './adhoc.form';
+
+export default
+ angular.module('adhoc', [])
+ .controller('adhocController', adhocController)
+ .run(['$stateExtender', function($stateExtender) {
+ $stateExtender.addState(route);
+ }])
+ .factory('adhocForm', form);
diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less
new file mode 100644
index 0000000000..d53e9174c8
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.block.less
@@ -0,0 +1,25 @@
+.InventoryManageBreadCrumbs .BreadCrumb-list{
+ padding-right: 0px;
+}
+.InventoryManageBreadCrumb-ncy.BreadCrumb-list{
+ padding-left: 5px;
+}
+.InventoryManageBreadCrumbs-separator{
+ content: "/";
+ padding: 0 5px;
+ color: #B7B7B7;
+}
+.InventoryManageBreadCrumbs{
+ position: relative;
+ height: auto;
+ top: -40px;
+ .BreadCrumb-list{
+ margin-bottom: 0px;
+ }
+}
+.InventoryManage-breakWord{
+ word-break: break-all;
+}
+ol.BreadCrumb-list{
+ display: inline-block;
+}
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js
new file mode 100644
index 0000000000..c04f014df2
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.controller.js
@@ -0,0 +1,27 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+export default
+ ['$state', '$stateParams', '$scope', 'inventoryData', 'breadCrumbData', function($state, $stateParams, $scope, inventoryData, breadCrumbData){
+ // process result data into the same order specified in the traversal path
+ $scope.groups = _.sortBy(breadCrumbData, function(item){
+ var index = _.indexOf($stateParams.group, item.id);
+ return (index === -1) ? $stateParams.group.length : index;
+ });
+ $scope.inventory = inventoryData;
+ // slices the group stack at $index to supply new group params to $state.go()
+ $scope.goToGroup = function($index){
+ var group = $stateParams.group.slice(0, $index);
+ $state.go('inventoryManage', {group: group}, {reload: true});
+ };
+ $scope.state = $state;
+ $scope.isRootState = function(){
+ return $state.current.name === 'inventoryManage';
+ };
+ $scope.goToInventory = function(){
+ $state.go('inventoryManage', {group: undefined}, {reload: true});
+ };
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html
new file mode 100644
index 0000000000..16a59d4031
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/breadcrumbs/breadcrumbs.partial.html
@@ -0,0 +1,50 @@
+
diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js
new file mode 100644
index 0000000000..90ce9c5fda
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move-groups.controller.js
@@ -0,0 +1,68 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$scope', '$state', '$stateParams', 'generateList', 'SearchInit', 'PaginateInit', 'GroupManageService', 'GetBasePath', 'CopyMoveGroupList', 'group',
+ function($scope, $state, $stateParams, GenerateList, SearchInit, PaginateInit, GroupManageService, GetBasePath, CopyMoveGroupList, group){
+ var list = CopyMoveGroupList,
+ view = GenerateList;
+ $scope.item = group;
+ $scope.submitMode = $stateParams.groups === undefined ? 'move' : 'copy';
+ $scope['toggle_'+ list.iterator] = 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':
+ // 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, _.last($stateParams.group))
+ .then(() => $state.go('^', null, {reload: true}));
+ });
+ }
+ break;
+ }
+ };
+ var init = function(){
+ var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
+ url += $stateParams.group ? '?not__id__in=' + group.id + ',' + _.last($stateParams.group) : '?not__id=' + group.id;
+ list.basePath = url;
+ view.inject(list, {
+ mode: 'lookup',
+ id: 'copyMove-list',
+ scope: $scope
+ });
+ SearchInit({
+ scope: $scope,
+ set: list.name,
+ list: list,
+ url: url
+ });
+ PaginateInit({
+ scope: $scope,
+ list: list,
+ url : url,
+ mode: 'lookup'
+ });
+ $scope.search(list.iterator, null, true, false);
+ // remove the current group from list
+ };
+ init();
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js
new file mode 100644
index 0000000000..14774de3ba
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move-hosts.controller.js
@@ -0,0 +1,65 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$scope', '$state', '$stateParams', 'generateList', 'SearchInit', 'PaginateInit', 'HostManageService', 'GetBasePath', 'CopyMoveGroupList', 'host',
+ function($scope, $state, $stateParams, GenerateList, SearchInit, PaginateInit, HostManageService, GetBasePath, CopyMoveGroupList, host){
+ var list = CopyMoveGroupList,
+ view = GenerateList;
+ $scope.item = host;
+ $scope.submitMode = 'copy';
+ $scope['toggle_'+ list.iterator] = 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(){
+ var url = GetBasePath('inventory') + $stateParams.inventory_id + '/groups/';
+ list.basePath = url;
+ view.inject(list, {
+ mode: 'lookup',
+ id: 'copyMove-list',
+ scope: $scope
+ });
+ SearchInit({
+ scope: $scope,
+ set: list.name,
+ list: list,
+ url: url
+ });
+ PaginateInit({
+ scope: $scope,
+ list: list,
+ url : url,
+ mode: 'lookup'
+ });
+ $scope.search(list.iterator, null, true, false);
+ };
+ init();
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.block.less b/awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less
similarity index 69%
rename from awx/ui/client/src/inventories/manage/copy/copy.block.less
rename to awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less
index 34b93417f6..76bdc2724c 100644
--- a/awx/ui/client/src/inventories/manage/copy/copy.block.less
+++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.block.less
@@ -4,13 +4,6 @@
.List-searchRow {
width: 50%;
}
-
- .ui-dialog-buttonpane.ui-widget-content {
- border: none;
- text-align: right;
- margin-top: 15px;
- }
-
.Form-header {
width: 50%;
margin-top: -20px;
@@ -22,9 +15,12 @@
}
}
}
-
-.copyMove-directive--copyMoveChoices {
+.copyMove-choices {
float: right;
width: 25%;
text-align: right;
}
+.copyMove-buttons{
+ height: 30px;
+ margin-top: 10px;
+}
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html b/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html
new file mode 100644
index 0000000000..a148985287
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.partial.html
@@ -0,0 +1,19 @@
+
+
+
+
+ Copy
+
+
+ Move
+
+
+
+
+
+ Cancel
+ Save
+
+
diff --git a/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js
new file mode 100644
index 0000000000..85d856c5ed
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/copy-move/copy-move.route.js
@@ -0,0 +1,51 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+import {templateUrl} from '../../../shared/template-url/template-url.factory';
+
+import CopyMoveGroupsController from './copy-move-groups.controller';
+import CopyMoveHostsController from './copy-move-hosts.controller';
+
+var copyMoveGroup = {
+ name: 'inventoryManage.copyMoveGroup',
+ route: '/copy-move-group/{group_id}',
+ data: {
+ group_id: 'group_id',
+ },
+ ncyBreadcrumb: {
+ label: "COPY OR MOVE {{item.name}}"
+ },
+ resolve: {
+ group: ['GroupManageService', '$stateParams', function(GroupManageService, $stateParams){
+ return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]);
+ }]
+ },
+ views: {
+ 'form@inventoryManage' : {
+ controller: CopyMoveGroupsController,
+ templateUrl: templateUrl('inventories/manage/copy-move/copy-move'),
+ }
+ }
+};
+var copyMoveHost = {
+ name: 'inventoryManage.copyMoveHost',
+ route: '/copy-move-host/{host_id}',
+ ncyBreadcrumb: {
+ label: "COPY OR MOVE {{item.name}}"
+ },
+ resolve: {
+ host: ['HostManageService', '$stateParams', function(HostManageService, $stateParams){
+ return HostManageService.get({id: $stateParams.host_id}).then(res => res.data.results[0]);
+ }]
+ },
+ views: {
+ 'form@inventoryManage': {
+ templateUrl: templateUrl('inventories/manage/copy-move/copy-move'),
+ controller: CopyMoveHostsController,
+ }
+ }
+};
+
+export {copyMoveGroup, copyMoveHost};
diff --git a/awx/ui/client/src/inventories/manage/copy/main.js b/awx/ui/client/src/inventories/manage/copy-move/main.js
similarity index 53%
rename from awx/ui/client/src/inventories/manage/copy/main.js
rename to awx/ui/client/src/inventories/manage/copy-move/main.js
index 898d5f9ae1..d68348cba8 100644
--- a/awx/ui/client/src/inventories/manage/copy/main.js
+++ b/awx/ui/client/src/inventories/manage/copy-move/main.js
@@ -4,12 +4,11 @@
* All Rights Reserved
*************************************************/
-import route from './copy.route';
+import {copyMoveGroup, copyMoveHost} from './copy-move.route';
export default
-angular.module('inventory-copy', [])
+angular.module('manageCopyMove', [])
.run(['$stateExtender', function($stateExtender) {
- $stateExtender.addState(route.copy);
- $stateExtender.addState(route.copyGroup);
- $stateExtender.addState(route.copyHost);
+ $stateExtender.addState(copyMoveGroup);
+ $stateExtender.addState(copyMoveHost);
}]);
diff --git a/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js b/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js
deleted file mode 100644
index 4690bb9b62..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy-groups.controller.js
+++ /dev/null
@@ -1,306 +0,0 @@
-function CopyGroupsCtrl($compile, $state, $scope, $location, Rest, ProcessErrors, CreateDialog,
- GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit, GetRootGroups, ParamPass, Store) {
- var vm = this;
- var name;
-
- var params = ParamPass.get(),
- group_id,
- parent_scope,
- scope;
-
- if (params !== undefined) {
- group_id = $state.params.group_id;
- parent_scope = params.scope;
- scope = parent_scope.$new();
- var parent_group = parent_scope.selected_group_id,
- url, group;
- } else {
- group_id = $state.params.group_id;
- parent_scope = $scope.$new();
- scope = parent_scope.$new();
- }
-
- var inventory_id = $state.params.inventory_id;
- var PreviousSearchParams = Store('group_current_search_params');
-
- if (scope.removeGroupsCopyPostRefresh) {
- scope.removeGroupsCopyPostRefresh();
- }
-
- scope.removeGroupCopyPostRefresh = scope.$on('PostRefresh', function() {
- scope.copy_groups.forEach(function(row, i) {
- scope.copy_groups[i].checked = '0';
- });
- Wait('stop');
-
- // prevent backspace from navigation when not in input or textarea field
- $(document).on('keydown', function(e) {
- if (e.which === 8 && !$(e.target).is('input[type="text"], textarea')) {
- e.preventDefault();
- }
- });
-
- });
-
- if (scope.removeCopyDialogReady) {
- scope.removeCopyDialogReady();
- }
-
- scope.removeCopyDialogReady = scope.$on('CopyDialogReady', function() {
- var url = GetBasePath('inventory') + inventory_id + '/groups/';
- url += (parent_group) ? '?not__id__in=' + group_id + ',' + parent_group : '?not__id=' + group_id;
- GenerateList.inject(GroupList, {
- mode: 'lookup',
- id: 'copyMove-directive--copyGroupSelect',
- scope: scope
- });
- SearchInit({
- scope: scope,
- set: GroupList.name,
- list: GroupList,
- url: url
- });
- PaginateInit({
- scope: scope,
- list: GroupList,
- url: url,
- mode: 'lookup'
- });
- scope.search(GroupList.iterator);
- });
-
- if (scope.removeShowDialog) {
- scope.removeShowDialog();
- }
-
- scope.removeShowDialog = scope.$on('ShowDialog', function() {
- var d;
- scope.name = group.name;
- scope.copy_choice = "copy";
- d = angular.element(document.getElementById('copyMove-directive--copyGroupSelect'));
- $compile(d)(scope);
- scope.$emit('CopyDialogReady');
- });
-
- if (scope.removeRootGroupsReady) {
- scope.removeRootGroupsReady();
- }
-
- scope.removeRootGroupsReady = scope.$on('RootGroupsReady', function(e, root_groups) {
- scope.offer_root_group = true;
- scope.use_root_group = false;
- root_groups.every(function(row) {
- if (row.id === group_id) {
- scope.offer_root_group = false;
- return false;
- }
- return true;
- });
- url = GetBasePath('groups') + group_id + '/';
- Rest.setUrl(url);
- Rest.get()
- .success(function(data) {
- group = data;
- vm.name = group.name;
- scope.$emit('ShowDialog');
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Call to ' + url + ' failed. GET returned: ' + status
- });
- });
- });
-
- Wait('start');
-
- GetRootGroups({
- scope: scope,
- group_id: group_id,
- inventory_id: $state.params.inventory_id,
- callback: 'RootGroupsReady'
- });
-
- var restoreSearch = function() {
- // Restore search params and related stuff, plus refresh
- // groups and hosts lists
- SearchInit({
- scope: $scope,
- set: PreviousSearchParams.set,
- list: PreviousSearchParams.list,
- url: PreviousSearchParams.defaultUrl,
- iterator: PreviousSearchParams.iterator,
- sort_order: PreviousSearchParams.sort_order,
- setWidgets: false
- });
- $scope.refreshHostsOnGroupRefresh = true;
- //$scope.search(InventoryGroups.iterator, null, true, false, true);
- };
-
- var cancel = function() {
- restoreSearch(); // Restore all parent search stuff and refresh hosts and groups lists
- scope.$destroy();
- $state.go('inventoryManage', {}, {
- reload: true
- });
- };
-
- var allowSave = false;
- scope['toggle_' + GroupList.iterator] = function(id) {
- var count = 0,
- list = GroupList;
- scope[list.name].forEach(function(row, i) {
- if (row.id === id) {
- if (row.checked) {
- scope[list.name][i].success_class = 'success';
- } else {
- scope[list.name][i].success_class = '';
- }
- } else {
- scope[list.name][i].checked = 0;
- scope[list.name][i].success_class = '';
- }
- });
- // Check if any rows are checked
- scope[list.name].forEach(function(row) {
- if (row.checked) {
- count++;
- }
- });
- if (count === 0) {
- vm.allowSave = false;
- } else {
- vm.allowSave = true;
- }
- };
-
- scope.toggleUseRootGroup = function() {
- var list = GroupList;
- if (scope.use_root_group) {
- $('#group-copy-ok-button').removeAttr('disabled');
- } else {
- // check for group selection
- $('#group-copy-ok-button').attr('disabled', 'disabled');
- scope[list.name].every(function(row) {
- if (row.checked === 1) {
- $('#group-copy-ok-button').removeAttr('disabled');
- return false;
- }
- return true;
- });
- }
- };
-
- var performCopy = function() {
- var list = GroupList,
- target,
- url;
-
- Wait('start');
-
- if (scope.use_root_group) {
- target = null;
- } else {
- scope[list.name].every(function(row) {
- if (row.checked === 1) {
- target = row;
- return false;
- }
- return true;
- });
- }
-
- if (vm.copy_choice === 'move') {
- // Respond to move
-
- // disassociate the group from the original parent
- if (scope.removeGroupRemove) {
- scope.removeGroupRemove();
- }
- scope.removeGroupRemove = scope.$on('RemoveGroup', function() {
- if (parent_group > 0) {
- // Only remove a group from a parent when the parent is a group and not the inventory root
- url = GetBasePath('groups') + parent_group + '/children/';
- Rest.setUrl(url);
- Rest.post({
- id: group.id,
- disassociate: 1
- })
- .success(function() {
- vm.cancel();
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to remove ' + group.name + ' from group ' + parent_group + '. POST returned: ' + status
- });
- });
- } else {
- vm.cancel();
- }
- });
-
- // add the new group to the target
- url = (target) ?
- GetBasePath('groups') + target.id + '/children/' :
- GetBasePath('inventory') + inventory_id + '/groups/';
- group = {
- id: group.id,
- name: group.name,
- description: group.description,
- inventory: inventory_id
- };
- Rest.setUrl(url);
- Rest.post(group)
- .success(function() {
- scope.$emit('RemoveGroup');
- })
- .error(function(data, status) {
- var target_name = (target) ? target.name : 'inventory';
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to add ' + group.name + ' to ' + target_name + '. POST returned: ' + status
- });
- });
- } else {
- // Respond to copy by adding the new group to the target
- url = (target) ?
- GetBasePath('groups') + target.id + '/children/' :
- GetBasePath('inventory') + inventory_id + '/groups/';
-
- group = {
- id: group.id,
- name: group.name,
- description: group.description,
- inventory: inventory_id
- };
-
- Rest.setUrl(url);
- Rest.post(group)
- .success(function() {
- vm.cancel();
- })
- .error(function(data, status) {
- var target_name = (target) ? target.name : 'inventory';
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to add ' + group.name + ' to ' + target_name + '. POST returned: ' + status
- });
- });
- }
- };
-
- var copy_choice = 'copy';
-
- angular.extend(vm, {
- cancel: cancel,
- performCopy: performCopy,
- copy_choice: copy_choice,
- name: name,
- allowSave: allowSave
- });
-}
-
-export default ['$compile', '$state', '$scope', '$location', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit',
- 'PaginateInit', 'GetRootGroups', 'ParamPass', 'Store', CopyGroupsCtrl
-];
diff --git a/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html b/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html
deleted file mode 100644
index d82ca6956f..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy-groups.partial.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
- Copy
-
-
- Move
-
-
-
-
-
-
- Save
-
- Cancel
-
-
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js b/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js
deleted file mode 100644
index 3883fed6ad..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy-hosts.controller.js
+++ /dev/null
@@ -1,239 +0,0 @@
-function CopyHostsCtrl($compile, $state, $scope, Rest, ProcessErrors, CreateDialog, GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit, ParamPass, Store) {
- var vm = this;
- var name;
-
- var host_id = $state.params.host_id;
- var inventory_id = $state.params.inventory_id;
- var url, host, group_scope, parent_scope, scope, parent_group;
-
- var params = ParamPass.get();
- if (params !== undefined) {
- group_scope = params.group_scope;
- parent_scope = params.host_scope;
- parent_group = group_scope.selected_group_id;
- scope = parent_scope.$new();
- } else {
- group_scope = $scope.$new();
- parent_scope = $scope.$new();
- scope = parent_scope.$new();
- }
-
- var PreviousSearchParams = Store('group_current_search_params');
-
- if (scope.removeHostCopyPostRefresh) {
- scope.removeHostCopyPostRefresh();
- }
- scope.removeHostCopyPostRefresh = scope.$on('PostRefresh', function() {
- scope.copy_groups.forEach(function(row, i) {
- scope.copy_groups[i].checked = '0';
- });
- Wait('stop');
- // prevent backspace from navigation when not in input or textarea field
- $(document).on("keydown", function(e) {
- if (e.which === 8 && !$(e.target).is('input[type="text"], textarea')) {
- e.preventDefault();
- }
- });
- });
-
- if (scope.removeHostCopyDialogReady) {
- scope.removeHostCopyDialogReady();
- }
- scope.removeCopyDialogReady = scope.$on('HostCopyDialogReady', function() {
- var url = GetBasePath('inventory') + inventory_id + '/groups/';
- GenerateList.inject(GroupList, {
- mode: 'lookup',
- id: 'copyMove-directive--copyHostSelect',
- scope: scope
- //,
- //instructions: instructions
- });
- SearchInit({
- scope: scope,
- set: GroupList.name,
- list: GroupList,
- url: url
- });
- PaginateInit({
- scope: scope,
- list: GroupList,
- url: url,
- mode: 'lookup'
- });
- scope.search(GroupList.iterator, null, true, false);
- });
-
- if (scope.removeShowDialog) {
- scope.removeShowDialog();
- }
- scope.removeShowDialog = scope.$on('ShowDialog', function() {
- var d;
- scope.name = host.name;
- d = angular.element(document.getElementById('copyMove-directive--copyHostPanel'));
- $compile(d)(scope);
- scope.$emit('HostCopyDialogReady');
- });
-
- Wait('start');
-
- url = GetBasePath('hosts') + host_id + '/';
- Rest.setUrl(url);
- Rest.get()
- .success(function(data) {
- host = data;
- vm.name = host.name;
- scope.$emit('ShowDialog');
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Call to ' + url + ' failed. GET returned: ' + status
- });
- });
-
- var restoreSearch = function() {
- // Restore search params and related stuff, plus refresh
- // groups and hosts lists
- SearchInit({
- scope: $scope,
- set: PreviousSearchParams.set,
- list: PreviousSearchParams.list,
- url: PreviousSearchParams.defaultUrl,
- iterator: PreviousSearchParams.iterator,
- sort_order: PreviousSearchParams.sort_order,
- setWidgets: false
- });
- $scope.refreshHostsOnGroupRefresh = true;
- };
-
- var cancel = function() {
- $(document).off("keydown");
- restoreSearch(); // Restore all parent search stuff and refresh hosts and groups lists
- scope.$destroy();
- $state.go('inventoryManage', {}, {
- reload: true
- });
- };
-
- var allowSave = false;
- scope['toggle_' + GroupList.iterator] = function(id) {
- var count = 0,
- list = GroupList;
- scope[list.name].forEach(function(row, i) {
- if (row.id === id) {
- if (row.checked) {
- scope[list.name][i].success_class = 'success';
- } else {
- scope[list.name][i].success_class = '';
- }
- } else {
- scope[list.name][i].checked = 0;
- scope[list.name][i].success_class = '';
- }
- });
- // Check if any rows are checked
- scope[list.name].forEach(function(row) {
- if (row.checked) {
- count++;
- }
- });
- if (count === 0) {
- vm.allowSave = false;
- } else {
- vm.allowSave = true;
- }
- };
-
- var performCopy = function() {
- var list = GroupList,
- target,
- url;
-
- Wait('start');
-
- if (scope.use_root_group) {
- target = null;
- } else {
- scope[list.name].every(function(row) {
- if (row.checked === 1) {
- target = row;
- return false;
- }
- return true;
- });
- }
-
- if (vm.copy_choice === 'move') {
- // Respond to move
- // disassociate the host from the original parent
- if (scope.removeHostRemove) {
- scope.removeHostRemove();
- }
- scope.removeHostRemove = scope.$on('RemoveHost', function() {
- if (parent_group > 0) {
- // Only remove a host from a parent when the parent is a group and not the inventory root
- url = GetBasePath('groups') + parent_group + '/hosts/';
- Rest.setUrl(url);
- Rest.post({
- id: host.id,
- disassociate: 1
- })
- .success(function() {
- vm.cancel();
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to remove ' + host.name + ' from group ' + parent_group + '. POST returned: ' + status
- });
- });
- } else {
- vm.cancel();
- }
- });
-
- // add the new host to the target
- url = GetBasePath('groups') + target.id + '/hosts/';
- Rest.setUrl(url);
- Rest.post(host)
- .success(function() {
- scope.$emit('RemoveHost');
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to add ' + host.name + ' to ' + target.name + '. POST returned: ' + status
- });
- });
- } else {
- // Respond to copy by adding the new host to the target
- url = GetBasePath('groups') + target.id + '/hosts/';
- Rest.setUrl(url);
- Rest.post(host)
- .success(function() {
- vm.cancel();
- })
- .error(function(data, status) {
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to add ' + host.name + ' to ' + target.name + '. POST returned: ' + status
- });
- });
- }
- };
-
-
- var copy_choice = 'copy';
-
- angular.extend(vm, {
- copy_choice: copy_choice,
- name: name,
- cancel: cancel,
- allowSave: allowSave,
- performCopy: performCopy
- });
-}
-
-export default ['$compile', '$state', '$scope', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit',
- 'PaginateInit', 'ParamPass', 'Store', CopyHostsCtrl
-];
diff --git a/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html b/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html
deleted file mode 100644
index aa2990434a..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy-hosts.partial.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- Copy
-
-
- Move
-
-
-
-
-
-
-
- Save
-
- Cancel
-
-
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.controller.js b/awx/ui/client/src/inventories/manage/copy/copy.controller.js
deleted file mode 100644
index 144f55da70..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy.controller.js
+++ /dev/null
@@ -1,16 +0,0 @@
-function inventoryManageCopyCtrl($state) {
- var vm = this;
-
- var cancelPanel = function() {
- $state.go('inventoryManage', {}, {
- reload: true
- });
- };
-
- angular.extend(vm, {
- cancelPanel: cancelPanel
- });
-}
-
-export default ['$state', inventoryManageCopyCtrl
-];
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.partial.html b/awx/ui/client/src/inventories/manage/copy/copy.partial.html
deleted file mode 100644
index ff19016e98..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy.partial.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/awx/ui/client/src/inventories/manage/copy/copy.route.js b/awx/ui/client/src/inventories/manage/copy/copy.route.js
deleted file mode 100644
index 360cc30edc..0000000000
--- a/awx/ui/client/src/inventories/manage/copy/copy.route.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-import {
- templateUrl
-} from '../../../shared/template-url/template-url.factory';
-
-import inventoryManageCopyCtrl from './copy.controller';
-import CopyGroupsCtrl from './copy-groups.controller';
-import CopyHostsCtrl from './copy-hosts.controller';
-
-export default {
- copy: {
- name: 'inventoryManage.copy',
- route: '/copy',
- templateUrl: templateUrl('inventories/manage/copy/copy'),
- ncyBreadcrumb: {
- label: "COPY"
- },
- controller: inventoryManageCopyCtrl,
- controllerAs: 'vm',
- bindToController: true,
- },
- copyGroup: {
- name: 'inventoryManage.copy.group',
- route: '/group/:group_id?groups',
- templateUrl: templateUrl('inventories/manage/copy/copy-groups'),
- data: {
- group_id: 'group_id',
- },
- ncyBreadcrumb: {
- label: "GROUP"
- },
- controller: CopyGroupsCtrl,
- controllerAs: 'vm',
- bindToController: true
- },
- copyHost: {
- name: 'inventoryManage.copy.host',
- route: '/host/:host_id?groups',
- templateUrl: templateUrl('inventories/manage/copy/copy-hosts'),
- data: {
- host_id: 'host_id',
- },
- ncyBreadcrumb: {
- label: "HOST"
- },
- controller: CopyHostsCtrl,
- controllerAs: 'vm',
- bindToController: true
- }
-};
diff --git a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js
new file mode 100644
index 0000000000..dff577c546
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js
@@ -0,0 +1,215 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'LookUpInit',
+ 'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
+ function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ParseTypeChange, GenerateForm, inventoryData, LookUpInit,
+ GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions){
+ var generator = GenerateForm,
+ form = GroupForm();
+
+ $scope.formCancel = function(){
+ $state.go('^');
+ };
+ $scope.formSave = function(){
+ var params, source;
+ // group fields
+ var group = {
+ variables: $scope.variables === ('---' || '{}') ? null : $scope.variables,
+ name: $scope.name,
+ description: $scope.description,
+ inventory: inventoryData.id
+ };
+ if ($scope.source){
+ // inventory_source fields
+ params = {
+ instance_filters: $scope.instance_filters,
+ source_vars: $scope[$scope.source.value + '_variables'] === ('---' || '{}') ? null : $scope[$scope.source.value + '_variables'],
+ source_script: $scope.inventory_script,
+ source: $scope.source.value,
+ credential: $scope.credential,
+ overwrite: $scope.overwrite,
+ overwrite_vars: $scope.overwrite_vars,
+ update_on_launch: $scope.update_on_launch,
+ update_cache_timeout: $scope.update_cache_timeout || 0,
+ // comma-delimited strings
+ group_by: _.map($scope.group_by, 'value').join(','),
+ source_regions: _.map($scope.source_regions, 'value').join(',')
+ };
+ source = $scope.source.value;
+ }
+ else{
+ source = null;
+ }
+ switch(source){
+ // no inventory source set, just create a new group
+ // '' is the value supplied for Manual source type
+ case null || '':
+ GroupManageService.post(group).then(res => {
+ // associate
+ if ($stateParams.group){
+ return GroupManageService.associateGroup(res.data, _.last($stateParams.group))
+ .then(() => $state.go('^', null, {reload: true}));
+ }
+ else{
+ $state.go('^', null, {reload: true});
+ }
+ });
+ break;
+ // create a new group and create/associate an inventory source
+ // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom'
+ default:
+ GroupManageService.post(group)
+ // associate to group
+ .then(res => {
+ if ($stateParams.group){
+ GroupManageService.associateGroup(res.data, _.last($stateParams.group));
+ return res;
+ }
+ else {return res;}
+ // pass the original POST response and not the association response
+ })
+ .then(res => GroupManageService.putInventorySource(
+ // put the received group ID into inventory source payload
+ // and pass the related endpoint
+ _.assign(params, {group: res.data.id}), res.data.related.inventory_source))
+ .then(res => $state.go('inventoryManage.editGroup', {group_id: res.data.group}, {reload: true}));
+ break;
+ }
+ };
+ $scope.sourceChange = function(source){
+ source = source.value === 'azure_rm' ? 'azure' : source.value;
+ if (source === 'custom'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('inventory_script'),
+ form: form,
+ list: InventoryScriptsList,
+ field: 'inventory_script',
+ input_type: "radio"
+ });
+ }
+ else if (source === 'ec2'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + '?kind=aws',
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ // equal to case 'rax' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom'
+ else{
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + (source === '' ? '' : '?kind=' + source),
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ // reset fields
+ $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null;
+ $scope.source_region_choices = $scope[source + '_regions'];
+ $scope.cloudCredentialRequired = source !== 'manual' && source !== 'custom' ? true : false;
+ $scope.group_by = null;
+ $scope.source_regions = null;
+ $scope.credential = null;
+ $scope.credential_name = null;
+ initRegionSelect();
+ };
+ var initRegionSelect = function(){
+ CreateSelect2({
+ element: '#group_source_regions',
+ multiple: true
+ });
+ CreateSelect2({
+ element: '#group_group_by',
+ multiple: true
+ });
+ };
+ var initSourceSelect = function(){
+ CreateSelect2({
+ element: '#group_source',
+ multiple: false
+ });
+ };
+ var initSources = function(){
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'rax_regions',
+ choice_name: 'rax_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'ec2_regions',
+ choice_name: 'ec2_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'gce_regions',
+ choice_name: 'gce_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'azure_regions',
+ choice_name: 'azure_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+
+ // Load options for group_by
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'group_by',
+ variable: 'ec2_group_by',
+ choice_name: 'ec2_group_by_choices',
+ callback: 'choicesReadyGroup'
+ });
+ GetSourceTypeOptions({
+ scope: $scope,
+ variable: 'source_type_options',
+ //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref
+ });
+ };
+ // region / source options callback
+ $scope.$on('choicesReadyGroup', function(){
+ initRegionSelect();
+ });
+
+ $scope.$on('sourceTypeOptionsReady', function(){
+ initSourceSelect();
+ });
+ var init = function(){
+ $scope.parseType = 'yaml';
+ $scope.variables = '---';
+ generator.inject(form, {mode: 'add', related: false, id: 'Inventory-groupManage--panel', scope: $scope});
+ ParseTypeChange({
+ scope: $scope,
+ field_id: 'group_variables',
+ variable: 'variables',
+ });
+ initSources();
+ };
+ init();
+ }];
diff --git a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js
new file mode 100644
index 0000000000..6b60ebfa38
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js
@@ -0,0 +1,288 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ToggleNotification',
+ 'ParseTypeChange', 'GenerateForm', 'LookUpInit', 'RelatedSearchInit', 'RelatedPaginateInit', 'NotificationsListInit',
+ 'GroupManageService','GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'groupData', 'inventorySourceData',
+ function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ToggleNotification,
+ ParseTypeChange, GenerateForm, LookUpInit, RelatedSearchInit, RelatedPaginateInit, NotificationsListInit,
+ GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, groupData, inventorySourceData){
+ var generator = GenerateForm,
+ form = GroupForm();
+ $scope.formCancel = function(){
+ $state.go('^');
+ };
+ $scope.formSave = function(){
+ var params, source;
+ // group fields
+ var group = {
+ variables: $scope.variables === ('---' || '{}') ? null : $scope.variables,
+ name: $scope.name,
+ description: $scope.description,
+ inventory: $scope.inventory,
+ id: groupData.id
+ };
+ if ($scope.source){
+ // inventory_source fields
+ params = {
+ group: groupData.id,
+ source: $scope.source.value,
+ credential: $scope.credential,
+ overwrite: $scope.overwrite,
+ overwrite_vars: $scope.overwrite_vars,
+ source_script: $scope.inventory_script,
+ update_on_launch: $scope.update_on_launch,
+ update_cache_timeout: $scope.update_cache_timeout || 0,
+ // comma-delimited strings
+ group_by: _.map($scope.group_by, 'value').join(','),
+ source_regions: _.map($scope.source_regions, 'value').join(','),
+ instance_filters: $scope.instance_filters,
+ source_vars: $scope[$scope.source.value + '_variables'] === '' ? null : $scope[$scope.source.value + '_variables']
+ };
+ source = $scope.source.value;
+ }
+ else{
+ source = null;
+ }
+ switch(source){
+ // no inventory source set, just create a new group
+ // '' is the value supplied for Manual source type
+ case null || '':
+ GroupManageService.put(group).then(() => $state.go('^', null, {reload: true}));
+ break;
+ // create a new group and create/associate an inventory source
+ // equal to case 'rax' || 'ec2' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom'
+ default:
+ GroupManageService.put(group)
+ .then(() => GroupManageService.putInventorySource(params, groupData.related.inventory_source))
+ .then(() => $state.go('^', null, {reload: true}));
+ break;
+ }
+ };
+ $scope.toggleNotification = function(event, notifier_id, column) {
+ var notifier = this.notification;
+ try {
+ $(event.target).tooltip('hide');
+ }
+ catch(e) {
+ // ignore
+ }
+ ToggleNotification({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ id: inventorySourceData.id,
+ notifier: notifier,
+ column: column,
+ callback: 'NotificationRefresh'
+ });
+ };
+ $scope.sourceChange = function(source){
+ $scope.source = source;
+ if (source.value === 'custom'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('inventory_script'),
+ form: form,
+ list: InventoryScriptsList,
+ field: 'inventory_script',
+ input_type: "radio"
+ });
+ }
+ else if (source.value === 'ec2'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + '?kind=aws',
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ else{
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + (source.value === '' ? '' : '?kind=' + (source.value)),
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ // reset fields
+ $scope.source_region_choices = $scope[source + '_regions'];
+ $scope.cloudCredentialRequired = source !== 'manual' && source !== 'custom' ? true : false;
+ $scope.group_by = null;
+ $scope.source_regions = null;
+ $scope.credential = null;
+ $scope.credential_name = null;
+ initRegionSelect();
+ };
+ var initRegionSelect = function(){
+ CreateSelect2({
+ element: '#group_source_regions',
+ multiple: true
+ });
+ CreateSelect2({
+ element: '#group_group_by',
+ multiple: true
+ });
+ };
+ var initSourceSelect = function(){
+ $scope.source = _.find($scope.source_type_options, {value: inventorySourceData.source});
+ CreateSelect2({
+ element: '#group_source',
+ multiple: false
+ });
+ };
+ var initRegionData = function(){
+ var source = $scope.source.value === 'azure_rm' ? 'azure' : $scope.source.value;
+ var regions = inventorySourceData.source_regions.split(',');
+ $scope.source_region_choices = $scope[source + '_regions'];
+ $scope.source_regions = _.map(regions, (region) => _.find($scope[source+'_regions'], {value: region}));
+ $scope.group_by_choices = source === 'ec2' ? $scope.ec2_group_by : null;
+ if (source ==='ec2'){
+ var group_by = inventorySourceData.group_by.split(',');
+ $scope.group_by = _.map(group_by, (item) => _.find($scope.ec2_group_by, {value: item}));
+ }
+ initRegionSelect();
+ };
+ var initSources = function(){
+ GetSourceTypeOptions({
+ scope: $scope,
+ variable: 'source_type_options',
+ //callback: 'sourceTypeOptionsReady' this callback is hard-coded into GetSourceTypeOptions(), included for ref
+ });
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'rax_regions',
+ choice_name: 'rax_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'ec2_regions',
+ choice_name: 'ec2_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'gce_regions',
+ choice_name: 'gce_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'source_regions',
+ variable: 'azure_regions',
+ choice_name: 'azure_region_choices',
+ callback: 'choicesReadyGroup'
+ });
+ GetChoices({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ field: 'group_by',
+ variable: 'ec2_group_by',
+ choice_name: 'ec2_group_by_choices',
+ callback: 'choicesReadyGroup'
+ });
+ };
+ // region / source options callback
+ $scope.$on('choicesReadyGroup', function(){
+ if (angular.isObject($scope.source)){
+ initRegionData();
+ }
+ });
+
+ $scope.$on('sourceTypeOptionsReady', function(){
+ initSourceSelect();
+ });
+ var init = function(){
+ // instantiate expected $scope values from inventorySourceData & groupData
+ var relatedSets = form.relatedSets(groupData.related);
+ generator.inject(form, {mode: 'edit', related: false, id: 'Inventory-groupManage--panel', scope: $scope});
+ _.assign($scope,
+ {credential: inventorySourceData.credential},
+ {overwrite: inventorySourceData.overwrite},
+ {overwrite_vars: inventorySourceData.overwrite_vars},
+ {update_on_launch: inventorySourceData.update_on_launch},
+ {update_cache_timeout: inventorySourceData.update_cache_timeout},
+ {instance_filters: inventorySourceData.instance_filters},
+ {inventory_script: inventorySourceData.source_script}
+ );
+ if(inventorySourceData.source === ('ec2' || 'openstack' || 'custom' || 'vmware')){
+ $scope[inventorySourceData.source + '_variables'] = inventorySourceData.source_vars;
+ }
+ if (inventorySourceData.credential){
+ GroupManageService.getCredential(inventorySourceData.credential).then(res => $scope.credential_name = res.data.name);
+ }
+ $scope = angular.extend($scope, groupData);
+ $scope.variables = $scope.variables === (null || '') ? '---' : $scope.variables;
+ $scope.parseType = 'yaml';
+ // instantiate lookup fields
+ if (inventorySourceData.source !== 'custom'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + (inventorySourceData.source === '' ? '' : 'kind=' + (inventorySourceData.source)),
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ else if (inventorySourceData.source === 'ec2'){
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('credentials') + '?kind=aws',
+ form: form,
+ list: CredentialList,
+ field: 'credential',
+ input_type: "radio"
+ });
+ }
+ // equal to case 'rax' || 'azure' || 'azure_rm' || 'vmware' || 'foreman' || 'cloudforms' || 'openstack' || 'custom'
+ else{
+ $scope.inventory_script_name = inventorySourceData.summary_fields.source_script.name;
+ LookUpInit({
+ scope: $scope,
+ url: GetBasePath('inventory_script'),
+ form: form,
+ list: InventoryScriptsList,
+ field: 'inventory_script',
+ input_type: "radio"
+ });
+ }
+ ParseTypeChange({
+ scope: $scope,
+ field_id: 'group_variables',
+ variable: 'variables',
+ });
+ NotificationsListInit({
+ scope: $scope,
+ url: GetBasePath('inventory_sources'),
+ id: inventorySourceData.id
+ });
+ RelatedSearchInit({
+ scope: $scope,
+ form: form,
+ relatedSets: relatedSets
+ });
+ RelatedPaginateInit({
+ scope: $scope,
+ relatedSets: relatedSets
+ });
+ initSources();
+ _.forEach(relatedSets, (value, key) => $scope.search(relatedSets[key].iterator));
+ };
+ init();
+ }];
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html b/awx/ui/client/src/inventories/manage/groups/groups-form.partial.html
similarity index 77%
rename from awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html
rename to awx/ui/client/src/inventories/manage/groups/groups-form.partial.html
index e39e0984ac..45ebffb9e3 100644
--- a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.partial.html
+++ b/awx/ui/client/src/inventories/manage/groups/groups-form.partial.html
@@ -1,5 +1,4 @@
diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js
new file mode 100644
index 0000000000..b5969304bc
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js
@@ -0,0 +1,145 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+ export default
+ ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus',
+ 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
+ function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus,
+ InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg){
+ var list = InventoryGroups,
+ view = generateList,
+ pageSize = 20;
+ $scope.inventory_id = $stateParams.inventory_id;
+ $scope.groupSelect = function(id){
+ var group = $stateParams.group === undefined ? [id] : _($stateParams.group).concat(id).value();
+ $state.go('inventoryManage', {inventory_id: $stateParams.inventory_id, group: group}, {reload: true});
+ };
+ $scope.createGroup = function(){
+ $state.go('inventoryManage.addGroup');
+ };
+ $scope.editGroup = function(id){
+ $state.go('inventoryManage.editGroup', {group_id: id});
+ };
+ $scope.deleteGroup = function(group){
+ $scope.toDelete = {};
+ angular.extend($scope.toDelete, group);
+ $('#group-delete-modal').modal('show');
+ };
+ $scope.confirmDelete = function(){
+ switch($scope.deleteOption){
+ case 'promote':
+ GroupManageService.promote($scope.toDelete.id, $stateParams.inventory_id)
+ .then(() => {
+ $state.go('inventoryManage', null, {reload: true});
+ $('#group-delete-modal').modal('hide');
+ });
+ break;
+ case 'delete':
+ GroupManageService.delete($scope.toDelete.id).then(() => {
+ $state.go('inventoryManage', null, {reload: true});
+ $('#group-delete-modal').modal('hide');
+ });
+ }
+ };
+ $scope.updateGroup = function(group) {
+ GroupManageService.getInventorySource({group: group.id}).then(res =>InventoryUpdate({
+ scope: $scope,
+ group_id: group.id,
+ url: res.data.results[0].related.update,
+ group_name: group.name,
+ group_source: res.data.results[0].source
+ }));
+ $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates
+ $rootScope.$on('JobStatusChange-inventory', (event, data) => {
+ switch(data.status){
+ case 'failed' || 'successful':
+ $state.reload();
+ break;
+ default:
+ var status = GetSyncStatusMsg({
+ status: data.status,
+ has_inventory_sources: group.has_inventory_sources,
+ source: group.source
+ });
+ group.status = data.status;
+ group.status_class = status.class;
+ group.status_tooltip = status.tooltip;
+ group.launch_tooltip = status.launch_tip;
+ group.launch_class = status.launch_class;
+ }
+ });
+ };
+ $scope.cancelUpdate = function (id) {
+ GroupsCancelUpdate({ scope: $scope, id: id });
+ };
+ $scope.viewUpdateStatus = function (id) {
+ ViewUpdateStatus({
+ scope: $scope,
+ group_id: id
+ });
+ };
+ $scope.showFailedHosts = function(x, y, z){
+ $state.go('inventoryManage', {failed: true}, {reload: true});
+ };
+ $scope.scheduleGroup = function(id) {
+ $state.go('inventoryManage.schedules', {id: id});
+ };
+ // $scope.$parent governed by InventoryManageController, for unified multiSelect options
+ $scope.$on('multiSelectList.selectionChanged', (event, selection) => {
+ $scope.$parent.groupsSelected = selection.length > 0 ? true : false;
+ $scope.$parent.groupsSelectedItems = selection.selectedItems;
+ });
+ $scope.$on('PostRefresh', () =>{
+ $scope.groups.forEach( (group, index) => {
+ var group_status, hosts_status;
+ group_status = GetSyncStatusMsg({
+ status: group.summary_fields.inventory_source.status,
+ has_inventory_sources: group.has_inventory_sources,
+ source: ( (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null )
+ });
+ hosts_status = GetHostsStatusMsg({
+ active_failures: group.hosts_with_active_failures,
+ total_hosts: group.total_hosts,
+ inventory_id: $scope.inventory_id,
+ group_id: group.id
+ });
+ _.assign($scope.groups[index],
+ {status_class: group_status.class},
+ {status_tooltip: group_status.tooltip},
+ {launch_tooltip: group_status.launch_tip},
+ {launch_class: group_status.launch_class},
+ {hosts_status_tip: hosts_status.tooltip},
+ {hosts_status_class: hosts_status.class},
+ {source: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.source : null},
+ {status: group.summary_fields.inventory_source ? group.summary_fields.inventory_source.status : null});
+ });
+ });
+ $scope.copyMoveGroup = function(id){
+ $state.go('inventoryManage.copyMoveGroup', {group_id: id, groups: $stateParams.groups});
+ };
+
+ var init = function(){
+ list.basePath = groupsUrl;
+ view.inject(list,{
+ id: 'groups-list',
+ $scope: $scope,
+ mode: 'edit'
+ });
+ SearchInit({
+ scope: $scope,
+ list: list,
+ url: groupsUrl,
+ set: 'groups'
+ });
+ PaginateInit({
+ scope: $scope,
+ list: list,
+ url: groupsUrl,
+ pageSize: pageSize
+ });
+ $scope.search(list.iterator);
+ };
+ init();
+ }];
diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html b/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html
new file mode 100644
index 0000000000..84f0025183
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups-list.partial.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
Deleting group {{ toDelete.name }} .
+ This group contains {{ toDelete.total_groups }} groups and {{ toDelete.total_hosts }} hosts.
+ This group contains {{ toDelete.total_hosts }} hosts.
+ This group contains {{ toDelete.total_groups }} groups.
+ Delete or promote the group's children?
+
+
+
+
+
+
+
Are you sure you want to permanently delete the group below from the inventory?
+
{{ toDelete.name }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/groups/groups.block.less b/awx/ui/client/src/inventories/manage/groups/groups.block.less
new file mode 100644
index 0000000000..67deadef22
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups.block.less
@@ -0,0 +1,19 @@
+.select2-selection.select2-selection--multiple.Form-dropDown{
+ height: auto !important;
+}
+.GroupDelete-help--container{
+ margin-right: auto;
+}
+.GroupDelete .Modal-header{
+ margin-bottom: 0;
+}
+.GroupDelete .modal-body{
+ padding-top: 20px;
+}
+.Inventory-groupManage{
+ // ugly hack to avoid the surface area of changing form generator's default classes
+ .checkbox-inline{
+ display: block;
+ padding-bottom: 5px;
+ }
+}
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/groups/groups.route.js b/awx/ui/client/src/inventories/manage/groups/groups.route.js
new file mode 100644
index 0000000000..3f95c9a484
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups.route.js
@@ -0,0 +1,51 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+import {templateUrl} from '../../../shared/template-url/template-url.factory';
+import addController from './groups-add.controller';
+import editController from './groups-edit.controller';
+
+var ManageGroupsEdit = {
+ name: 'inventoryManage.editGroup',
+ route: '/edit-group?group_id',
+ ncyBreadcrumb: {
+ label: "EDIT {{group.name}}"
+ },
+ data: {
+ mode: 'edit'
+ },
+ resolve: {
+ groupData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService){
+ return GroupManageService.get({id: $stateParams.group_id}).then(res => res.data.results[0]);
+ }],
+ inventorySourceData: ['$stateParams', 'GroupManageService', function($stateParams, GroupManageService){
+ return GroupManageService.getInventorySource({group: $stateParams.group_id}).then(res => res.data.results[0]);
+ }]
+ },
+ views: {
+ 'form@inventoryManage': {
+ controller: editController,
+ templateUrl: templateUrl('inventories/manage/groups/groups-form'),
+ }
+ }
+};
+var ManageGroupsAdd = {
+ name: 'inventoryManage.addGroup',
+ route: '/add-group',
+ // use a query string to break regex search
+ ncyBreadcrumb: {
+ label: "ADD GROUP"
+ },
+ data: {
+ mode: 'add'
+ },
+ views: {
+ 'form@inventoryManage': {
+ controller: addController,
+ templateUrl: templateUrl('inventories/manage/groups/groups-form'),
+ }
+ }
+};
+export {ManageGroupsAdd, ManageGroupsEdit};
diff --git a/awx/ui/client/src/inventories/manage/groups/groups.service.js b/awx/ui/client/src/inventories/manage/groups/groups.service.js
new file mode 100644
index 0000000000..83b5ed224e
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/groups.service.js
@@ -0,0 +1,113 @@
+export default
+ ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){
+ return {
+ stringifyParams: function(params){
+ return _.reduce(params, (result, value, key) => {
+ return result + key + '=' + value + '&';
+ }, '');
+ },
+ // cute abstractions via fn.bind()
+ url: function(){
+ return '';
+ },
+ error: function(data, status) {
+ ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
+ msg: 'Call to ' + this.url + '. GET returned: ' + status });
+ },
+ success: function(data){
+ return data;
+ },
+ // HTTP methods
+ get: function(params){
+ Wait('start');
+ this.url = GetBasePath('groups') + '?' + this.stringifyParams(params);
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ post: function(group){
+ Wait('start');
+ this.url = GetBasePath('groups');
+ Rest.setUrl(this.url);
+ return Rest.post(group)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ put: function(group){
+ Wait('start');
+ this.url = GetBasePath('groups') + group.id;
+ Rest.setUrl(this.url);
+ return Rest.put(group)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ delete: function(id){
+ Wait('start');
+ this.url = GetBasePath('groups') + id;
+ Rest.setUrl(this.url);
+ return Rest.destroy()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ getCredential: function(id){
+ Wait('start');
+ this.url = GetBasePath('credentials') + id;
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ getInventorySource: function(params){
+ Wait('start');
+ this.url = GetBasePath('inventory_sources') + '?' + this.stringifyParams(params);
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ putInventorySource: function(params, url){
+ Wait('start');
+ this.url = url;
+ Rest.setUrl(this.url);
+ return Rest.put(params)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level
+ associateGroup: function(group, target){
+ Wait('start');
+ this.url = GetBasePath('groups') + target + '/children/';
+ Rest.setUrl(this.url);
+ return Rest.post(group)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ disassociateGroup: function(group, parent){
+ Wait('start');
+ this.url = GetBasePath('groups') + parent + '/children/';
+ Rest.setUrl(this.url);
+ return Rest.post({id: group, disassociate: 1})
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ promote: function(group, inventory){
+ Wait('start');
+ this.url = GetBasePath('inventory') + inventory + '/groups/';
+ Rest.setUrl(this.url);
+ return Rest.post({id: group, disassociate: 1})
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ }
+ };
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/groups/main.js b/awx/ui/client/src/inventories/manage/groups/main.js
new file mode 100644
index 0000000000..ffade1862a
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/groups/main.js
@@ -0,0 +1,14 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+import {ManageGroupsAdd, ManageGroupsEdit} from './groups.route';
+
+export default
+ angular.module('manageGroups', [])
+ .run(['$stateExtender', function($stateExtender){
+ $stateExtender.addState(ManageGroupsAdd);
+ $stateExtender.addState(ManageGroupsEdit);
+ }]);
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js
similarity index 66%
rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js
rename to awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js
index 620a68f1ac..1eefe86020 100644
--- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-add.controller.js
+++ b/awx/ui/client/src/inventories/manage/hosts/hosts-add.controller.js
@@ -5,16 +5,16 @@
*************************************************/
export default
- ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService',
- function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService){
+ ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService',
+ function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService){
var generator = GenerateForm,
form = HostForm;
$scope.parseType = 'yaml';
$scope.extraVars = '---';
$scope.formCancel = function(){
- $state.go('^', null, {reload: true});
+ $state.go('^');
};
- $scope.toggleEnabled = function(){
+ $scope.toggleHostEnabled = function(){
$scope.host.enabled = !$scope.host.enabled;
};
$scope.formSave = function(){
@@ -25,8 +25,16 @@
enabled: $scope.host.enabled,
inventory: $stateParams.inventory_id
};
- ManageHostsService.post(params).then(function(){
- $state.go('^', null, {reload: true});
+ HostManageService.post(params).then(function(res){
+ // assign the host to current group if not at the root level
+ if ($stateParams.group){
+ HostManageService.associateGroup(res.data, _.last($stateParams.group)).then(function(){
+ $state.go('inventoryManage', null, {reload: true});
+ });
+ }
+ else{
+ $state.go('inventoryManage', null, {reload: true});
+ }
});
};
var init = function(){
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js
similarity index 88%
rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js
rename to awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js
index de733124fa..8e764d95d5 100644
--- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts-edit.controller.js
+++ b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js
@@ -5,13 +5,13 @@
*************************************************/
export default
- ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService', 'host',
- function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService, host){
+ ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'host',
+ function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){
var generator = GenerateForm,
form = HostForm;
$scope.parseType = 'yaml';
$scope.formCancel = function(){
- $state.go('^', null, {reload: true});
+ $state.go('^');
};
$scope.toggleHostEnabled = function(){
$scope.host.enabled = !$scope.host.enabled;
@@ -24,7 +24,7 @@
description: $scope.description,
enabled: $scope.host.enabled
};
- ManageHostsService.put(host).then(function(){
+ HostManageService.put(host).then(function(){
$state.go('^', null, {reload: true});
});
};
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.partial.html b/awx/ui/client/src/inventories/manage/hosts/hosts-form.partial.html
similarity index 100%
rename from awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.partial.html
rename to awx/ui/client/src/inventories/manage/hosts/hosts-form.partial.html
diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js
new file mode 100644
index 0000000000..13540fb489
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js
@@ -0,0 +1,84 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+ export default
+ ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryHosts', 'generateList', 'InventoryManageService', 'HostManageService',
+ 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData',
+ function($scope, $rootScope, $state, $stateParams, InventoryHosts, generateList, InventoryManageService, HostManageService,
+ hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData){
+ var list = InventoryHosts,
+ view = generateList,
+ pageSize = 20;
+ $scope.createHost = function(){
+ $state.go('inventoryManage.addHost');
+ };
+ $scope.editHost = function(id){
+ $state.go('inventoryManage.editHost', {host_id: id});
+ };
+ $scope.deleteHost = function(id, name){
+ var body = '
Are you sure you want to permanently delete the host below from the inventory?
' + name + '
';
+ var action = function(){
+ delete $rootScope.promptActionBtnClass;
+ Wait('start');
+ HostManageService.delete(id).then(() => {
+ $('#prompt-modal').modal('hide');
+ $state.go($state.current.name, null, {reload: true});
+ Wait('stop');
+ });
+ };
+ // Prompt depends on having $rootScope.promptActionBtnClass available...
+ Prompt({
+ hdr: 'Delete Host',
+ body: body,
+ action: action,
+ actionText: 'DELETE',
+ });
+ $rootScope.promptActionBtnClass = 'Modal-errorButton';
+ };
+ $scope.copyMoveHost = function(id){
+ $state.go('inventoryManage.copyMoveHost', {host_id: id});
+ };
+ $scope.systemTracking = function(){
+ var hostIds = _.map($scope.$parent.hostsSelectedItems, (host) => host.id);
+ $state.go('systemTracking', {
+ inventory: inventoryData,
+ inventoryId: $stateParams.inventory_id,
+ hosts: $scope.$parent.hostsSelectedItems,
+ hostIds: hostIds
+ });
+ };
+ // $scope.$parent governed by InventoryManageController, for unified multiSelect options
+ $scope.$on('multiSelectList.selectionChanged', (event, selection) => {
+ $scope.$parent.hostsSelected = selection.length > 0 ? true : false;
+ $scope.$parent.hostsSelectedItems = selection.selectedItems;
+ $scope.$parent.systemTrackingDisabled = selection.length > 0 && selection.length < 3 ? false : true;
+ $scope.$parent.systemTrackingTooltip = selection.length === 1 ? "Compare host facts over time" : "Compare hosts' facts";
+ });
+ $scope.$on('PostRefresh', ()=>{
+ _.forEach($scope.hosts, (host) => SetStatus({scope: $scope, host: host}));
+ });
+ var init = function(){
+ list.basePath = hostsUrl;
+ view.inject(list,{
+ id: 'hosts-list',
+ scope: $scope,
+ mode: 'edit'
+ });
+ SearchInit({
+ scope: $scope,
+ list: list,
+ url: hostsUrl,
+ set: 'hosts'
+ });
+ PaginateInit({
+ scope: $scope,
+ list: list,
+ url: hostsUrl,
+ pageSize: pageSize
+ });
+ $scope.search(list.iterator);
+ };
+ init();
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts.route.js b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js
new file mode 100644
index 0000000000..54a9c3f7d0
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/hosts/hosts.route.js
@@ -0,0 +1,50 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+import {templateUrl} from '../../../shared/template-url/template-url.factory';
+import addController from './hosts-add.controller';
+import editController from './hosts-edit.controller';
+
+var ManageHostsEdit = {
+ name: 'inventoryManage.editHost',
+ route: '/edit-host?host_id',
+ ncyBreadcrumb: {
+ label: "EDIT {{host.name}}",
+ },
+ data: {
+ mode: 'edit'
+ },
+ resolve: {
+ host: ['$stateParams', 'HostManageService', function($stateParams, HostManageService){
+ return HostManageService.get({id: $stateParams.host_id}).then(function(res){
+ return res.data.results[0];
+ });
+ }]
+ },
+ views: {
+ 'form@inventoryManage': {
+ controller: editController,
+ templateUrl: templateUrl('inventories/manage/hosts/hosts-form'),
+ }
+ }
+};
+var ManageHostsAdd = {
+ name: 'inventoryManage.addHost',
+ route: '/add-host',
+ // use a query string to break regex search
+ ncyBreadcrumb: {
+ label: "ADD HOST"
+ },
+ data: {
+ mode: 'add'
+ },
+ views: {
+ 'form@inventoryManage': {
+ controller: addController,
+ templateUrl: templateUrl('inventories/manage/hosts/hosts-form'),
+ }
+ }
+};
+export {ManageHostsAdd, ManageHostsEdit};
diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts.service.js b/awx/ui/client/src/inventories/manage/hosts/hosts.service.js
new file mode 100644
index 0000000000..a85a159c8a
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/hosts/hosts.service.js
@@ -0,0 +1,84 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
+ function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){
+ return {
+ stringifyParams: function(params){
+ return _.reduce(params, (result, value, key) => {
+ return result + key + '=' + value + '&';
+ }, '');
+ },
+ // cute abstractions via fn.bind()
+ url: function(){
+ return '';
+ },
+ error: function(data, status) {
+ ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
+ msg: 'Call to ' + this.url + '. GET returned: ' + status });
+ },
+ success: function(data){
+ return data;
+ },
+ // HTTP methods
+ get: function(params){
+ Wait('start');
+ this.url = GetBasePath('hosts') + '?' + this.stringifyParams(params);
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ post: function(host){
+ Wait('start');
+ this.url = GetBasePath('hosts');
+ Rest.setUrl(this.url);
+ return Rest.post(host)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ put: function(host){
+ Wait('start');
+ this.url = GetBasePath('hosts') + host.id;
+ Rest.setUrl(this.url);
+ return Rest.put(host)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ delete: function(id){
+ Wait('start');
+ this.url = GetBasePath('hosts') + id;
+ Rest.setUrl(this.url);
+ return Rest.destroy()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ // these relationship setters could be consolidated, but verbosity makes the operation feel more clear @ controller level
+ associateGroup: function(host, group){
+ Wait('start');
+ this.url = GetBasePath('groups') + group + '/hosts/';
+ Rest.setUrl(this.url);
+ return Rest.post(host)
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ disassociateGroup: function(host, group){
+ Wait('start');
+ this.url = GetBasePath('groups') + group + '/hosts/';
+ Rest.setUrl(this.url);
+ return Rest.post({id: host.id, disassociate: 1})
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ }
+ };
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/main.js b/awx/ui/client/src/inventories/manage/hosts/main.js
similarity index 60%
rename from awx/ui/client/src/inventories/manage/manage-hosts/main.js
rename to awx/ui/client/src/inventories/manage/hosts/main.js
index 90d5cf3e70..8b71ce162a 100644
--- a/awx/ui/client/src/inventories/manage/manage-hosts/main.js
+++ b/awx/ui/client/src/inventories/manage/hosts/main.js
@@ -4,13 +4,11 @@
* All Rights Reserved
*************************************************/
-import {ManageHostsAdd, ManageHostsEdit} from './manage-hosts.route';
-import service from './manage-hosts.service';
+import {ManageHostsAdd, ManageHostsEdit} from './hosts.route';
export default
angular.module('manageHosts', [])
- .service('ManageHostsService', service)
- .run(['$stateExtender', function($stateExtender){
+ .run(['$stateExtender', '$state', function($stateExtender, $state){
$stateExtender.addState(ManageHostsAdd);
$stateExtender.addState(ManageHostsEdit);
}]);
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.block.less b/awx/ui/client/src/inventories/manage/inventory-manage.block.less
new file mode 100644
index 0000000000..4bf257dffe
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/inventory-manage.block.less
@@ -0,0 +1,3 @@
+.InventoryManage-container{
+ margin-top: -40px;
+}
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js
index fab1b0334e..0588e8ed17 100644
--- a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js
+++ b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js
@@ -3,532 +3,18 @@
*
* All Rights Reserved
*************************************************/
-
-/**
- * @ngdoc function
- * @name controllers.function:Inventories
- * @description This controller's for the Inventory page
- */
-
-function InventoriesManage($log, $scope, $rootScope, $location,
- $state, $compile, generateList, ClearScope, Empty, Wait, Rest, Alert,
- GetBasePath, ProcessErrors, InventoryGroups,
- InjectHosts, Find, HostsReload, SearchInit, PaginateInit, GetSyncStatusMsg,
- GetHostsStatusMsg, GroupsEdit, InventoryUpdate, GroupsCancelUpdate,
- ViewUpdateStatus, GroupsDelete, Store, HostsEdit, HostsDelete,
- EditInventoryProperties, ShowJobSummary,
- InventoryGroupsHelp, HelpDialog,
- GroupsCopy, HostsCopy, $stateParams, ParamPass) {
-
- var PreviousSearchParams,
- url,
- hostScope = $scope.$new();
-
- ClearScope();
-
- // TODO: only display adhoc button if the user has permission to use it.
- // TODO: figure out how to get the action-list partial to update so that
- // the tooltip can be changed based off things being selected or not.
- $scope.adhocButtonTipContents = "Launch adhoc command for the inventory";
-
- // watcher for the group list checkbox changes
- $scope.$on('multiSelectList.selectionChanged', function(e, selection) {
- if (selection.length > 0) {
- $scope.groupsSelected = true;
- // $scope.adhocButtonTipContents = "Launch adhoc command for the "
- // + "selected groups and hosts.";
- } else {
- $scope.groupsSelected = false;
- // $scope.adhocButtonTipContents = "Launch adhoc command for the "
- // + "inventory.";
- }
- $scope.groupsSelectedItems = selection.selectedItems;
- });
-
- // watcher for the host list checkbox changes
- hostScope.$on('multiSelectList.selectionChanged', function(e, selection) {
- // you need this so that the event doesn't bubble to the watcher above
- // for the host list
- e.stopPropagation();
- var trackingButton = angular.element(document.querySelector('.system-tracking'));
- trackingButton.html('SYSTEM TRACKING');
- if (selection.length === 0) {
- $scope.hostsSelected = false;
- } else if (selection.length === 1) {
- $scope.systemTrackingTooltip = "Compare host over time";
- $scope.hostsSelected = true;
- $scope.systemTrackingDisabled = false;
- } else if (selection.length === 2) {
- $scope.systemTrackingTooltip = "Compare hosts against each other";
- $scope.hostsSelected = true;
- $scope.systemTrackingDisabled = false;
- } else {
- $scope.hostsSelected = true;
- $scope.systemTrackingDisabled = true;
- }
- $scope.hostsSelectedItems = selection.selectedItems;
- });
-
- $scope.systemTracking = function() {
- var hostIds = _.map($scope.hostsSelectedItems, function(x){
- return x.id;
- });
- $state.transitionTo('systemTracking',
- { inventory: $scope.inventory,
- inventoryId: $scope.inventory.id,
- hosts: $scope.hostsSelectedItems,
- hostIds: hostIds
- });
- };
-
- // populates host patterns based on selected hosts/groups
- $scope.populateAdhocForm = function() {
- var host_patterns = "all";
- if ($scope.hostsSelected || $scope.groupsSelected) {
- var allSelectedItems = [];
- if ($scope.groupsSelectedItems) {
- allSelectedItems = allSelectedItems.concat($scope.groupsSelectedItems);
- }
- if ($scope.hostsSelectedItems) {
- allSelectedItems = allSelectedItems.concat($scope.hostsSelectedItems);
- }
- if (allSelectedItems) {
- host_patterns = _.pluck(allSelectedItems, "name").join(":");
- }
- }
- $rootScope.hostPatterns = host_patterns;
- $state.go('inventoryManage.adhoc');
- };
-
- $scope.refreshHostsOnGroupRefresh = false;
- $scope.selected_group_id = null;
-
- Wait('start');
-
-
- if ($scope.removeHostReloadComplete) {
- $scope.removeHostReloadComplete();
- }
- $scope.removeHostReloadComplete = $scope.$on('HostReloadComplete', function() {
- if ($scope.initial_height) {
- var host_height = $('#hosts-container .well').height(),
- group_height = $('#group-list-container .well').height(),
- new_height;
-
- if (host_height > group_height) {
- new_height = host_height - (host_height - group_height);
- }
- else if (host_height < group_height) {
- new_height = host_height + (group_height - host_height);
- }
- if (new_height) {
- $('#hosts-container .well').height(new_height);
- }
- $scope.initial_height = null;
- }
- });
-
- if ($scope.removeRowCountReady) {
- $scope.removeRowCountReady();
- }
- $scope.removeRowCountReady = $scope.$on('RowCountReady', function(e, rows) {
- // Add hosts view
- $scope.show_failures = false;
- InjectHosts({
- group_scope: $scope,
- host_scope: hostScope,
- inventory_id: $scope.inventory.id,
- tree_id: null,
- group_id: null,
- pageSize: rows
- });
-
- SearchInit({ scope: $scope, set: 'groups', list: InventoryGroups, url: $scope.inventory.related.root_groups });
- PaginateInit({ scope: $scope, list: InventoryGroups , url: $scope.inventory.related.root_groups, pageSize: rows });
- $scope.search(InventoryGroups.iterator, null, true);
- });
-
- if ($scope.removeInventoryLoaded) {
- $scope.removeInventoryLoaded();
- }
- $scope.removeInventoryLoaded = $scope.$on('InventoryLoaded', function() {
- var rows;
- generateList.inject(InventoryGroups, {
- mode: 'edit',
- id: 'group-list-container',
- searchSize: 'col-lg-6 col-md-6 col-sm-6 col-xs-12',
- scope: $scope
- });
-
- rows = 20;
- hostScope.host_page_size = rows;
- $scope.group_page_size = rows;
-
- $scope.show_failures = false;
- InjectHosts({
- group_scope: $scope,
- host_scope: hostScope,
- inventory_id: $scope.inventory.id,
- tree_id: null,
- group_id: null,
- pageSize: rows
- });
-
- // Load data
- SearchInit({
- scope: $scope,
- set: 'groups',
- list: InventoryGroups,
- url: $scope.inventory.related.root_groups
- });
-
- PaginateInit({
- scope: $scope,
- list: InventoryGroups ,
- url: $scope.inventory.related.root_groups,
- pageSize: rows
- });
-
- $scope.search(InventoryGroups.iterator, null, true);
-
- $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates
- });
-
- if ($scope.removePostRefresh) {
- $scope.removePostRefresh();
- }
- $scope.removePostRefresh = $scope.$on('PostRefresh', function(e, set) {
- if (set === 'groups') {
- $scope.groups.forEach( function(group, idx) {
- var stat, hosts_status;
- stat = GetSyncStatusMsg({
- status: group.summary_fields.inventory_source.status,
- has_inventory_sources: group.has_inventory_sources,
- source: ( (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null )
- }); // from helpers/Groups.js
- $scope.groups[idx].status_class = stat['class'];
- $scope.groups[idx].status_tooltip = stat.tooltip;
- $scope.groups[idx].launch_tooltip = stat.launch_tip;
- $scope.groups[idx].launch_class = stat.launch_class;
- hosts_status = GetHostsStatusMsg({
- active_failures: group.hosts_with_active_failures,
- total_hosts: group.total_hosts,
- inventory_id: $scope.inventory.id,
- group_id: group.id
- }); // from helpers/Groups.js
- $scope.groups[idx].hosts_status_tip = hosts_status.tooltip;
- $scope.groups[idx].show_failures = hosts_status.failures;
- $scope.groups[idx].hosts_status_class = hosts_status['class'];
-
- $scope.groups[idx].source = (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.source : null;
- $scope.groups[idx].status = (group.summary_fields.inventory_source) ? group.summary_fields.inventory_source.status : null;
-
- });
- if ($scope.refreshHostsOnGroupRefresh) {
- $scope.refreshHostsOnGroupRefresh = false;
- HostsReload({
- scope: hostScope,
- group_id: $scope.selected_group_id,
- inventory_id: $scope.inventory.id,
- pageSize: hostScope.host_page_size
- });
- }
- else {
- Wait('stop');
- }
- }
- });
-
- // Load Inventory
- url = GetBasePath('inventory') + $stateParams.inventory_id + '/';
- Rest.setUrl(url);
- Rest.get()
- .success(function (data) {
- $scope.inventory = data;
- $scope.$emit('InventoryLoaded');
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve inventory: ' + $stateParams.inventory_id +
- ' GET returned status: ' + status });
- });
-
- // start watching for real-time updates
- if ($rootScope.removeWatchUpdateStatus) {
- $rootScope.removeWatchUpdateStatus();
- }
- $rootScope.removeWatchUpdateStatus = $rootScope.$on('JobStatusChange-inventory', function(e, data) {
- var stat, group;
- if (data.group_id) {
- group = Find({ list: $scope.groups, key: 'id', val: data.group_id });
- if (data.status === "failed" || data.status === "successful") {
- if (data.group_id === $scope.selected_group_id || group) {
- // job completed, fefresh all groups
- $log.debug('Update completed. Refreshing the tree.');
- $scope.refreshGroups();
- }
- }
- else if (group) {
- // incremental update, just update
- $log.debug('Status of group: ' + data.group_id + ' changed to: ' + data.status);
- stat = GetSyncStatusMsg({
- status: data.status,
- has_inventory_sources: group.has_inventory_sources,
- source: group.source
- });
- $log.debug('changing tooltip to: ' + stat.tooltip);
- group.status = data.status;
- group.status_class = stat['class'];
- group.status_tooltip = stat.tooltip;
- group.launch_tooltip = stat.launch_tip;
- group.launch_class = stat.launch_class;
- }
- }
- });
-
- // Load group on selection
- function loadGroups(url) {
- SearchInit({ scope: $scope, set: 'groups', list: InventoryGroups, url: url });
- PaginateInit({ scope: $scope, list: InventoryGroups , url: url, pageSize: $scope.group_page_size });
- $scope.search(InventoryGroups.iterator, null, true, false, true);
- }
-
- $scope.refreshHosts = function() {
- HostsReload({
- scope: hostScope,
- group_id: $scope.selected_group_id,
- inventory_id: $scope.inventory.id,
- pageSize: hostScope.host_page_size
- });
- };
-
- $scope.refreshGroups = function() {
- $scope.refreshHostsOnGroupRefresh = true;
- $scope.search(InventoryGroups.iterator, null, true, false, true);
- };
-
- $scope.restoreSearch = function() {
- // Restore search params and related stuff, plus refresh
- // groups and hosts lists
- SearchInit({
- scope: $scope,
- set: PreviousSearchParams.set,
- list: PreviousSearchParams.list,
- url: PreviousSearchParams.defaultUrl,
- iterator: PreviousSearchParams.iterator,
- sort_order: PreviousSearchParams.sort_order,
- setWidgets: false
- });
- $scope.refreshHostsOnGroupRefresh = true;
- $scope.search(InventoryGroups.iterator, null, true, false, true);
- };
-
- $scope.groupSelect = function(id) {
- var groups = [], group = Find({ list: $scope.groups, key: 'id', val: id });
- if($state.params.groups){
- groups.push($state.params.groups);
- }
- groups.push(group.id);
- groups = groups.join();
- $state.transitionTo('inventoryManage', {inventory_id: $state.params.inventory_id, groups: groups}, { notify: false});
- loadGroups(group.related.children, group.id);
- $scope.selected_group_id = group.id;
- HostsReload({
- scope: hostScope,
- group_id: $scope.selected_group_id,
- inventory_id: $scope.inventory.id,
- pageSize: hostScope.host_page_size
- });
- };
-
- $scope.createGroup = function () {
- PreviousSearchParams = Store('group_current_search_params');
- var params = {
- scope: $scope,
- inventory_id: $scope.inventory.id,
- group_id: $scope.selected_group_id,
- mode: 'add'
- };
- ParamPass.set(params);
- $state.go('inventoryManage.addGroup');
- };
-
- $scope.editGroup = function (id) {
- PreviousSearchParams = Store('group_current_search_params');
- var params = {
- scope: $scope,
- inventory_id: $scope.inventory.id,
- group_id: id,
- mode: 'edit'
- };
- ParamPass.set(params);
- $state.go('inventoryManage.editGroup', {group_id: id});
- };
-
- // Launch inventory sync
- $scope.updateGroup = function (id) {
- var group = Find({ list: $scope.groups, key: 'id', val: id });
- if (group) {
- if (Empty(group.source)) {
- // if no source, do nothing.
- } else if (group.status === 'updating') {
- Alert('Update in Progress', 'The inventory update process is currently running for group
' +
- group.name + ' Click the
button to monitor the status.', 'alert-info', null, null, null, null, true);
- } else {
- Wait('start');
- Rest.setUrl(group.related.inventory_source);
- Rest.get()
- .success(function (data) {
- InventoryUpdate({
- scope: $scope,
- url: data.related.update,
- group_name: data.summary_fields.group.name,
- group_source: data.source,
- group_id: group.id,
- });
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve inventory source: ' +
- group.related.inventory_source + ' GET returned status: ' + status });
- });
- }
- }
- };
-
- $scope.cancelUpdate = function (id) {
- GroupsCancelUpdate({ scope: $scope, id: id });
- };
-
- $scope.viewUpdateStatus = function (id) {
- ViewUpdateStatus({
- scope: $scope,
- group_id: id
- });
- };
-
- $scope.scheduleGroup = function(id) {
- $state.go('inventoryManageSchedules', {
- inventory_id: $scope.inventory.id, id: id
- });
- };
-
- $scope.copyGroup = function(id) {
- PreviousSearchParams = Store('group_current_search_params');
- var params = {
- scope: $scope
- };
- ParamPass.set(params);
- $location.search('groups', null);
- $state.go('inventoryManage.copy.group', {group_id: id});
- };
-
- $scope.deleteGroup = function (id) {
- GroupsDelete({
- scope: $scope,
- group_id: id,
- inventory_id: $scope.inventory.id
- });
- };
-
- $scope.editInventoryProperties = function () {
- // EditInventoryProperties({ scope: $scope, inventory_id: $scope.inventory.id });
- $location.path('/inventories/' + $scope.inventory.id + '/');
- };
-
- hostScope.createHost = function () {
- var params = {
- host_scope: hostScope,
- group_scope: $scope,
- mode: 'add',
- host_id: null,
- selected_group_id: $scope.selected_group_id,
- inventory_id: $scope.inventory.id
- };
- ParamPass.set(params);
- $state.go('inventoryManage.addHost');
- };
-
- hostScope.editHost = function (host_id) {
- var params = {
- host_scope: hostScope,
- group_scope: $scope,
- mode: 'edit',
- host_id: host_id,
- inventory_id: $scope.inventory.id
- };
- ParamPass.set(params);
- $state.go('inventoryManage.editHost', {host_id: host_id});
- };
-
- hostScope.deleteHost = function (host_id, host_name) {
- HostsDelete({
- parent_scope: $scope,
- host_scope: hostScope,
- host_id: host_id,
- host_name: host_name
- });
- };
-
- hostScope.copyHost = function(id) {
- PreviousSearchParams = Store('group_current_search_params');
- var params = {
- group_scope: $scope,
- host_scope: hostScope,
- host_id: id
- };
-
- ParamPass.set(params);
-
- $state.go('inventoryManage.copy.host', {host_id: id});
- };
-
- hostScope.showJobSummary = function (job_id) {
- ShowJobSummary({
- job_id: job_id
- });
- };
-
- $scope.showGroupHelp = function (params) {
- var opts = {
- defn: InventoryGroupsHelp
- };
- if (params) {
- opts.autoShow = params.autoShow || false;
- }
- HelpDialog(opts);
- }
-;
- $scope.showHosts = function (group_id, show_failures) {
- // Clicked on group
- if (group_id !== null) {
- Wait('start');
- hostScope.show_failures = show_failures;
- $scope.groupSelect(group_id);
- hostScope.hosts = [];
- $scope.show_failures = show_failures; // turn on failed hosts
- // filter in hosts view
- } else {
- Wait('stop');
- }
- };
-
- if ($scope.removeGroupDeleteCompleted) {
- $scope.removeGroupDeleteCompleted();
- }
- $scope.removeGroupDeleteCompleted = $scope.$on('GroupDeleteCompleted',
- function() {
- $scope.refreshGroups();
- }
- );
-}
-
-export default [
- '$log', '$scope', '$rootScope', '$location',
- '$state', '$compile', 'generateList', 'ClearScope', 'Empty', 'Wait',
- 'Rest', 'Alert', 'GetBasePath', 'ProcessErrors',
- 'InventoryGroups', 'InjectHosts', 'Find', 'HostsReload',
- 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
- 'GroupsEdit', 'InventoryUpdate', 'GroupsCancelUpdate', 'ViewUpdateStatus',
- 'GroupsDelete', 'Store', 'HostsEdit', 'HostsDelete',
- 'EditInventoryProperties', 'ShowJobSummary', 'InventoryGroupsHelp', 'HelpDialog', 'GroupsCopy',
- 'HostsCopy', '$stateParams', 'ParamPass', InventoriesManage
-];
+ export default
+ ['$scope', '$state', function($scope, $state){
+ $scope.groupsSelected = false;
+ $scope.hostsSelected = false;
+ $scope.hostsSelectedItems = [];
+ $scope.groupsSelectedItems = [];
+ $scope.setAdhocPattern = function(){
+ var pattern = _($scope.groupsSelectedItems)
+ .concat($scope.hostsSelectedItems)
+ .map(function(item){
+ return item.name;
+ }).value().join(':');
+ $state.go('inventoryManage.adhoc', {pattern: pattern});
+ };
+ }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.partial.html b/awx/ui/client/src/inventories/manage/inventory-manage.partial.html
index 7daf685f3f..41e8084a42 100644
--- a/awx/ui/client/src/inventories/manage/inventory-manage.partial.html
+++ b/awx/ui/client/src/inventories/manage/inventory-manage.partial.html
@@ -1,152 +1,10 @@
-
-
+
+
-
-
-
-
2. Select a target group below, OR choose the inventory root:
-
- Use the inventory root
-
-
-
2. Select a target group:
-
-
-
-
-
-
-
-
2. Select a target group:
-
-
-
-
-
-
-
-
-
-
-
-
Deleting group {{ group_name }} .
- This group contains {{ groupsCount }} groups and {{ hostsCount }} hosts.
- This group contains {{ hostsCount }} hosts.
- This group contains {{ groupsCount }} groups.
- Delete or promote the group's children?
-
-
-
-
-
-
-
-
-
Delete group {{ group_name }} ?
-
-
-
-
-
-
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.route.js b/awx/ui/client/src/inventories/manage/inventory-manage.route.js
index 674297bb0a..317f584930 100644
--- a/awx/ui/client/src/inventories/manage/inventory-manage.route.js
+++ b/awx/ui/client/src/inventories/manage/inventory-manage.route.js
@@ -6,18 +6,71 @@
import {templateUrl} from '../../shared/template-url/template-url.factory';
import InventoriesManage from './inventory-manage.controller';
+import BreadcrumbsController from './breadcrumbs/breadcrumbs.controller';
+import HostsListController from './hosts/hosts-list.controller';
+import GroupsListController from './groups/groups-list.controller';
export default {
name: 'inventoryManage',
- url: '/inventories/:inventory_id/manage?groups',
- templateUrl: templateUrl('inventories/manage/inventory-manage'),
- controller: InventoriesManage,
+ url: '/inventories/:inventory_id/manage?{group:int}{failed}',
data: {
activityStream: true,
activityStreamTarget: 'inventory',
activityStreamId: 'inventory_id'
},
+ params:{
+ group:{
+ array: true
+ },
+ failed:{
+ value: 'false',
+ squash: true
+ }
+ },
ncyBreadcrumb: {
- label: "INVENTORY MANAGE"
+ skip: true // Never display this state in ncy-breadcrumb.
+ },
+ // enforce uniqueness in group param
+ onEnter: function($stateParams){
+ $stateParams.group = _.uniq($stateParams.group);
+ },
+ resolve: {
+ groupsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){
+ return !$stateParams.group ?
+ InventoryManageService.rootGroupsUrl($stateParams.inventory_id) :
+ InventoryManageService.childGroupsUrl(_.last($stateParams.group));
+ }],
+ hostsUrl: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){
+ // at the root group level
+ return !$stateParams.group ?
+ InventoryManageService.rootHostsUrl($stateParams.inventory_id, $stateParams.failed) :
+ InventoryManageService.childHostsUrl(_.last($stateParams.group, $stateParams.failed));
+ }],
+ inventoryData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){
+ return InventoryManageService.getInventory($stateParams.inventory_id).then(res => res.data);
+ }],
+ breadCrumbData: ['InventoryManageService', '$stateParams', function(InventoryManageService, $stateParams){
+ return ( (!$stateParams.group) ? false : InventoryManageService.getBreadcrumbs($stateParams.group).then(res => res.data.results));
+ }]
+ },
+ views:{
+ // target the ui-view with name "groupBreadcrumbs" at the root template level
+ 'groupBreadcrumbs@': {
+ controller: BreadcrumbsController,
+ templateUrl: templateUrl('inventories/manage/breadcrumbs/breadcrumbs')
+ },
+ '': {
+ templateUrl: templateUrl('inventories/manage/inventory-manage'),
+ controller: InventoriesManage
+ },
+ // target ui-views with name@inventoryManage template level
+ 'groupsList@inventoryManage': {
+ templateUrl: templateUrl('inventories/manage/groups/groups-list'),
+ controller: GroupsListController
+ },
+ 'hostsList@inventoryManage': {
+ template: '
',
+ controller: HostsListController
+ }
}
};
diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.service.js b/awx/ui/client/src/inventories/manage/inventory-manage.service.js
new file mode 100644
index 0000000000..d61d27e758
--- /dev/null
+++ b/awx/ui/client/src/inventories/manage/inventory-manage.service.js
@@ -0,0 +1,63 @@
+/*************************************************
+ * Copyright (c) 2016 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default
+ ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
+ function($rootScope, Rest, GetBasePath, ProcessErrors, Wait){
+ return {
+ // cute abstractions via fn.bind()
+ url: function(){
+ return '';
+ },
+ error: function(data, status) {
+ ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
+ msg: 'Call to ' + this.url + '. GET returned: ' + status });
+ },
+ success: function(data){
+ return data;
+ },
+ // data getters
+ getInventory: function(id){
+ Wait('start');
+ this.url = GetBasePath('inventory') + id;
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this))
+ .finally(Wait('stop'));
+ },
+ getBreadcrumbs: function(groups){
+ Wait('start');
+ this.url = GetBasePath('groups') + '?' + _.map(groups, function(item){
+ return '&or__id=' + item;
+ }).join('');
+ Rest.setUrl(this.url);
+ return Rest.get()
+ .success(this.success.bind(this))
+ .error(this.error.bind(this));
+ },
+ // these methods generate a query string to pass to PaginateInit(), SearchInit()
+ // always supply trailing slashes and ? prefix
+ rootHostsUrl: function(id, failed){
+ var url = GetBasePath('inventory') + id + '/hosts' +
+ (failed === 'true' ? '?has_active_failures=true' : '?');
+ return url;
+ },
+ childHostsUrl: function(id, failed){
+ var url = GetBasePath('groups') + id + '/hosts' +
+ (failed === 'true' ? '?has_active_failures=true' : '?');
+ return url;
+ },
+ childGroupsUrl: function(id){
+ var url = GetBasePath('groups') + id + '/children?';
+ return url;
+ },
+ rootGroupsUrl: function(id){
+ var url = GetBasePath('inventory') + id+ '/root_groups/';
+ return url;
+ }
+ };
+ }];
diff --git a/awx/ui/client/src/inventories/manage/main.js b/awx/ui/client/src/inventories/manage/main.js
index 435db696f7..df2b14469e 100644
--- a/awx/ui/client/src/inventories/manage/main.js
+++ b/awx/ui/client/src/inventories/manage/main.js
@@ -1,21 +1,28 @@
/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
+ * Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import route from './inventory-manage.route';
-
-import manageHosts from './manage-hosts/main';
-import manageGroups from './manage-groups/main';
-import copy from './copy/main';
+import InventoryManageService from './inventory-manage.service';
+import HostManageService from './hosts/hosts.service';
+import GroupManageService from './groups/groups.service';
+import hosts from './hosts/main';
+import groups from './groups/main';
+import adhoc from './adhoc/main';
+import copyMove from './copy-move/main';
export default
angular.module('inventoryManage', [
- manageHosts.name,
- manageGroups.name,
- copy.name,
+ hosts.name,
+ groups.name,
+ copyMove.name,
+ adhoc.name
])
+ .service('InventoryManageService', InventoryManageService)
+ .service('HostManageService', HostManageService)
+ .service('GroupManageService', GroupManageService)
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(route);
}]);
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js
deleted file mode 100644
index 6bad2c274a..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.controller.js
+++ /dev/null
@@ -1,574 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-function manageGroupsDirectiveController($filter, $location, $log,
- $stateParams, $compile, $state, $scope, Rest, Alert, GroupForm,
- GenerateForm, Prompt, ProcessErrors, GetBasePath, SetNodeName,
- ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, LookUpInit, Empty,
- Wait, GetChoices, UpdateGroup, SourceChange, Find, ParseVariableString,
- ToJSON, GroupsScheduleListInit, SetSchedulesInnerDialogSize,
- CreateSelect2, ToggleNotification, NotificationsListInit,
- RelatedSearchInit, RelatedPaginateInit) {
-
- var vm = this;
-
- var group_id = $stateParams.group_id,
- mode = $state.current.data.mode,
- inventory_id = $stateParams.inventory_id,
- generator = GenerateForm,
- group_created = false,
- defaultUrl,
- master = {},
- form = GroupForm(),
- relatedSets = {},
- choicesReady, group;
-
- if (mode === 'edit') {
- defaultUrl = GetBasePath('groups') + group_id + '/';
- } else {
- defaultUrl = (group_id !== undefined) ? GetBasePath('groups') + group_id + '/children/' :
- GetBasePath('inventory') + inventory_id + '/groups/';
- }
-
- Rest.setUrl(defaultUrl);
- Rest.get()
- .success(function(data) {
- group = data;
- for (var fld in form.fields) {
- if (data[fld]) {
- $scope[fld] = data[fld];
- master[fld] = $scope[fld];
- }
- }
- if(mode === 'edit') {
- $scope.variable_url = data.related.variable_data;
- $scope.source_url = data.related.inventory_source;
- $scope.source_id = data.related.inventory_source.split('/')[4];
- $scope.$emit('LoadSourceData');
- }
- })
- .error(function(data, status) {
- ProcessErrors($scope, data, status, {
- hdr: 'Error!',
- msg: 'Failed to retrieve group: ' + defaultUrl + '. GET status: ' + status
- });
- });
-
-
- $scope.parseType = 'yaml';
-
- generator.inject(form, {
- mode: mode,
- id: 'group-manage-panel',
- scope: $scope,
- related: false,
- cancelButton: false
- });
-
- generator.reset();
-
- GetSourceTypeOptions({
- scope: $scope,
- variable: 'source_type_options'
- });
-
- $scope.source = form.fields.source['default'];
- $scope.sourcePathRequired = false;
- $scope[form.fields.source_vars.parseTypeName] = 'yaml';
- $scope.update_cache_timeout = 0;
- $scope.parseType = 'yaml';
-
-
- function initSourceChange() {
- $scope.showSchedulesTab = (mode === 'edit' && $scope.source && $scope.source.value !== "manual") ? true : false;
- SourceChange({
- scope: $scope,
- form: form
- });
- }
-
- // JT -- this gets called after the properties & properties variables are loaded, and is emitted from (groupLoaded)
- if ($scope.removeLoadSourceData) {
- $scope.removeLoadSourceData();
- }
- $scope.removeLoadSourceData = $scope.$on('LoadSourceData', function() {
- ParseTypeChange({
- scope: $scope,
- variable: 'variables',
- parse_variable: 'parseType',
- field_id: 'group_variables'
- });
-
- NotificationsListInit({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- id: $scope.source_id
- });
-
- if ($scope.source_url) {
- // get source data
- Rest.setUrl($scope.source_url);
- Rest.get()
- .success(function(data) {
- var fld, i, j, flag, found, set, opts, list;
- for (fld in form.fields) {
- if (fld === 'checkbox_group') {
- for (i = 0; i < form.fields[fld].fields.length; i++) {
- flag = form.fields[fld].fields[i];
- if (data[flag.name] !== undefined) {
- $scope[flag.name] = data[flag.name];
- master[flag.name] = $scope[flag.name];
- }
- }
- }
- if (fld === 'source') {
- found = false;
- data.source = (data.source === "") ? "manual" : data.source;
- for (i = 0; i < $scope.source_type_options.length; i++) {
- if ($scope.source_type_options[i].value === data.source) {
- $scope.source = $scope.source_type_options[i];
- found = true;
- }
- }
- if (!found || $scope.source.value === "manual") {
- $scope.groupUpdateHide = true;
- } else {
- $scope.groupUpdateHide = false;
- }
- master.source = $scope.source;
- } else if (fld === 'source_vars') {
- // Parse source_vars, converting to YAML.
- $scope.source_vars = ParseVariableString(data.source_vars);
- master.source_vars = $scope.variables;
- } else if (fld === "inventory_script") {
- // the API stores it as 'source_script', we call it inventory_script
- data.summary_fields.inventory_script = data.summary_fields.source_script;
- $scope.inventory_script = data.source_script;
- master.inventory_script = $scope.inventory_script;
- } else if (fld === "source_regions") {
- if (data[fld] === "") {
- $scope[fld] = data[fld];
- master[fld] = $scope[fld];
- } else {
- $scope[fld] = data[fld].split(",");
- master[fld] = $scope[fld];
- }
- } else if (data[fld] !== undefined &&
- fld !== "description" &&
- fld !== "name" &&
- fld !== "variables") {
- $scope[fld] = data[fld];
- master[fld] = $scope[fld];
- }
-
- if (form.fields[fld].sourceModel && data.summary_fields &&
- data.summary_fields[form.fields[fld].sourceModel]) {
- $scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
- data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
- master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
- data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
- }
- }
- relatedSets = form.relatedSets(data.related);
- RelatedSearchInit({
- scope: $scope,
- form: form,
- relatedSets: relatedSets
- });
-
- RelatedPaginateInit({
- scope: $scope,
- relatedSets: relatedSets
- });
- initSourceChange();
-
- if (data.source_regions) {
- if (data.source === 'ec2' ||
- data.source === 'rax' ||
- data.source === 'gce' ||
- data.source === 'azure') {
- if (data.source === 'ec2') {
- set = $scope.ec2_regions;
- } else if (data.source === 'rax') {
- set = $scope.rax_regions;
- } else if (data.source === 'gce') {
- set = $scope.gce_regions;
- } else if (data.source === 'azure') {
- set = $scope.azure_regions;
- }
- opts = [];
- list = data.source_regions.split(',');
- for (i = 0; i < list.length; i++) {
- for (j = 0; j < set.length; j++) {
- if (list[i] === set[j].value) {
- opts.push({
- id: set [j].value,
- text: set [j].label
- });
- }
- }
- }
- master.source_regions = opts;
- CreateSelect2({
- element: "group_source_regions",
- multiple: true,
- opts: opts
- });
-
- }
- } else {
- // If empty, default to all
- master.source_regions = [{
- id: 'all',
- text: 'All'
- }];
- }
- if (data.group_by && data.source === 'ec2') {
- set = $scope.ec2_group_by;
- opts = [];
- list = data.group_by.split(',');
- for (i = 0; i < list.length; i++) {
- for (j = 0; j < set.length; j++) {
- if (list[i] === set[j].value) {
- opts.push({
- id: set [j].value,
- text: set [j].label
- });
- }
- }
- }
- master.group_by = opts;
- CreateSelect2({
- element: "#group_group_by",
- multiple: true,
- opts: opts
- });
- }
-
- $scope.group_update_url = data.related.update;
- for (set in relatedSets) {
- $scope.search(relatedSets[set].iterator);
- }
- })
- .error(function(data, status) {
- $scope.source = "";
- ProcessErrors($scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to retrieve inventory source. GET status: ' + status
- });
- });
- }
- });
-
- if ($scope.remove$scopeSourceTypeOptionsReady) {
- $scope.remove$scopeSourceTypeOptionsReady();
- }
- $scope.remove$scopeSourceTypeOptionsReady = $scope.$on('sourceTypeOptionsReady', function() {
- if (mode === 'add') {
- $scope.source = Find({
- list: $scope.source_type_options,
- key: 'value',
- val: ''
- });
- $scope.showSchedulesTab = false;
- }
- });
-
- choicesReady = 0;
-
- if ($scope.removeChoicesReady) {
- $scope.removeChoicesReady();
- }
- $scope.removeChoicesReady = $scope.$on('choicesReadyGroup', function() {
- CreateSelect2({
- element: '#group_source',
- multiple: false
- });
- $scope.$emit('LoadSourceData');
-
- choicesReady++;
- if (choicesReady === 5) {
- if (mode !== 'edit') {
- $scope.variables = "---";
- master.variables = $scope.variables;
- }
- }
- });
-
- // Load options for source regions
- GetChoices({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- field: 'source_regions',
- variable: 'rax_regions',
- choice_name: 'rax_region_choices',
- callback: 'choicesReadyGroup'
- });
-
- GetChoices({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- field: 'source_regions',
- variable: 'ec2_regions',
- choice_name: 'ec2_region_choices',
- callback: 'choicesReadyGroup'
- });
-
- GetChoices({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- field: 'source_regions',
- variable: 'gce_regions',
- choice_name: 'gce_region_choices',
- callback: 'choicesReadyGroup'
- });
-
- GetChoices({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- field: 'source_regions',
- variable: 'azure_regions',
- choice_name: 'azure_region_choices',
- callback: 'choicesReadyGroup'
- });
-
- // Load options for group_by
- GetChoices({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- field: 'group_by',
- variable: 'ec2_group_by',
- choice_name: 'ec2_group_by_choices',
- callback: 'choicesReadyGroup'
- });
-
- //Wait('start');
-
- if ($scope.removeAddTreeRefreshed) {
- $scope.removeAddTreeRefreshed();
- }
- $scope.removeAddTreeRefreshed = $scope.$on('GroupTreeRefreshed', function() {
- // Clean up
- Wait('stop');
-
- if ($scope.searchCleanUp) {
- $scope.searchCleanup();
- }
- try {
- //$('#group-modal-dialog').dialog('close');
- } catch (e) {
- // ignore
- }
- });
-
- if ($scope.removeSaveComplete) {
- $scope.removeSaveComplete();
- }
- $scope.removeSaveComplete = $scope.$on('SaveComplete', function(e, error) {
- if (!error) {
- $scope.formCancel();
- }
- });
-
- if ($scope.removeFormSaveSuccess) {
- $scope.removeFormSaveSuccess();
- }
- $scope.removeFormSaveSuccess = $scope.$on('formSaveSuccess', function() {
-
- // Source data gets stored separately from the group. Validate and store Source
- // related fields, then call SaveComplete to wrap things up.
-
- var parseError = false,
- regions, r, i,
- group_by,
- data = {
- group: group_id,
- source: (($scope.source && $scope.source.value !== 'manual') ? $scope.source.value : ''),
- source_path: $scope.source_path,
- credential: $scope.credential,
- overwrite: $scope.overwrite,
- overwrite_vars: $scope.overwrite_vars,
- source_script: $scope.inventory_script,
- update_on_launch: $scope.update_on_launch,
- update_cache_timeout: ($scope.update_cache_timeout || 0)
- };
-
- // Create a string out of selected list of regions
- if ($scope.source_regions) {
- regions = $('#group_source_regions').select2("data");
- r = [];
- for (i = 0; i < regions.length; i++) {
- r.push(regions[i].id);
- }
- data.source_regions = r.join();
- }
-
- if ($scope.source && ($scope.source.value === 'ec2')) {
- data.instance_filters = $scope.instance_filters;
- // Create a string out of selected list of regions
- group_by = $('#group_group_by').select2("data");
- r = [];
- for (i = 0; i < group_by.length; i++) {
- r.push(group_by[i].id);
- }
- data.group_by = r.join();
- }
-
- if ($scope.source && ($scope.source.value === 'ec2')) {
- // for ec2, validate variable data
- data.source_vars = ToJSON($scope.envParseType, $scope.source_vars, true);
- }
-
- if ($scope.source && ($scope.source.value === 'custom')) {
- data.source_vars = ToJSON($scope.envParseType, $scope.extra_vars, true);
- }
-
- if ($scope.source && ($scope.source.value === 'vmware' ||
- $scope.source.value === 'openstack')) {
- data.source_vars = ToJSON($scope.envParseType, $scope.inventory_variables, true);
- }
-
- // the API doesn't expect the credential to be passed with a custom inv script
- if ($scope.source && $scope.source.value === 'custom') {
- delete(data.credential);
- }
-
- if (!parseError) {
- Rest.setUrl($scope.source_url);
- Rest.put(data)
- .success(function() {
- $scope.$emit('SaveComplete', false);
- })
- .error(function(data, status) {
- $('#group_tabs a:eq(1)').tab('show');
- ProcessErrors($scope, data, status, form, {
- hdr: 'Error!',
- msg: 'Failed to update group inventory source. PUT status: ' + status
- });
- });
- }
- });
- $scope.toggleNotification = function(event, notifier_id, column) {
- var notifier = this.notification;
- try {
- $(event.target).tooltip('hide');
- }
- catch(e) {
- // ignore
- }
- ToggleNotification({
- scope: $scope,
- url: GetBasePath('inventory_sources'),
- id: $scope.source_id,
- notifier: notifier,
- column: column,
- callback: 'NotificationRefresh'
- });
- };
- // Cancel
- $scope.formCancel = function() {
- Wait('stop');
- $state.go('inventoryManage', {}, {reload: true});
- };
-
- // Save
- $scope.saveGroup = function() {
- Wait('start');
- var fld, data, json_data;
-
- try {
-
- json_data = ToJSON($scope.parseType, $scope.variables, true);
-
- data = {};
- for (fld in form.fields) {
- data[fld] = $scope[fld];
- }
-
- data.inventory = inventory_id;
-
- Rest.setUrl(defaultUrl);
- if (mode === 'edit' || (mode === 'add' && group_created)) {
- Rest.put(data)
- .success(function() {
- $scope.$emit('formSaveSuccess');
- })
- .error(function(data, status) {
- $('#group_tabs a:eq(0)').tab('show');
- ProcessErrors($scope, data, status, form, {
- hdr: 'Error!',
- msg: 'Failed to update group: ' + group_id + '. PUT status: ' + status
- });
- });
- } else {
- Rest.post(data)
- .success(function(data) {
- group_created = true;
- group_id = data.id;
- $scope.source_url = data.related.inventory_source;
- $scope.source_id = $scope.source_url.split('/')[4];
- $scope.$emit('formSaveSuccess');
- })
- .error(function(data, status) {
- $('#group_tabs a:eq(0)').tab('show');
- ProcessErrors($scope, data, status, form, {
- hdr: 'Error!',
- msg: 'Failed to create group: ' + group_id + '. POST status: ' + status
- });
- });
- }
- } catch (e) {
- // ignore. ToJSON will have already alerted the user
- }
- };
-
- // Start the update process
- $scope.updateGroup = function() {
- if ($scope.source === "manual" || $scope.source === null) {
- Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group, provide Source settings, ' +
- 'and then run an update.', 'alert-info');
- } else if ($scope.status === 'updating') {
- Alert('Update in Progress', 'The inventory update process is currently running for group
' +
- $filter('sanitize')($scope.summary_fields.group.name) + ' . Use the Refresh button to monitor the status.', 'alert-info', null, null, null, null, true);
- } else {
- InventoryUpdate({
- scope: $scope,
- group_id: group_id,
- url: $scope.group_update_url,
- group_name: $scope.name,
- group_source: $scope.source.value
- });
- }
- };
-
- // Change the lookup and regions when the source changes
- $scope.sourceChange = function() {
- $scope.credential_name = "";
- $scope.credential = "";
- if ($scope.credential_name_api_error) {
- delete $scope.credential_name_api_error;
- }
- initSourceChange();
- };
-
-
- angular.extend(vm, {
- formCancel : $scope.formCancel,
- saveGroup: $scope.saveGroup
- });
-}
-
-export default ['$filter', '$location', '$log', '$stateParams',
- '$compile', '$state', '$scope', 'Rest', 'Alert', 'GroupForm',
- 'GenerateForm','Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName',
- 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', 'LookUpInit',
- 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find',
- 'ParseVariableString', 'ToJSON', 'GroupsScheduleListInit',
- 'SetSchedulesInnerDialogSize', 'CreateSelect2',
- 'ToggleNotification', 'NotificationsListInit', 'RelatedSearchInit',
- 'RelatedPaginateInit',
- manageGroupsDirectiveController
-];
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js
deleted file mode 100644
index b4c3fbff73..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-/* jshint unused: vars */
-import manageGroupsDirectiveController from './manage-groups.directive.controller';
-
-export default ['templateUrl', 'ParamPass',
- function(templateUrl, ParamPass) {
- return {
- restrict: 'EA',
- scope: true,
- replace: true,
- templateUrl: templateUrl('inventories/manage/manage-groups/directive/manage-groups.directive'),
- link: function(scope, element, attrs) {
-
- },
- controller: manageGroupsDirectiveController,
- controllerAs: 'vm',
- bindToController: true
- };
- }
-];
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html b/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html
deleted file mode 100644
index 889e561114..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-groups/directive/manage-groups.directive.partial.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/main.js b/awx/ui/client/src/inventories/manage/manage-groups/main.js
deleted file mode 100644
index b015b64628..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-groups/main.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-import route from './manage-groups.route';
-import manageGroupsDirective from './directive/manage-groups.directive';
-
-export default
- angular.module('manage-groups', [])
- .directive('manageGroups', manageGroupsDirective)
- .run(['$stateExtender', function($stateExtender) {
- $stateExtender.addState(route.edit);
- $stateExtender.addState(route.add);
- }]);
diff --git a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js b/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js
deleted file mode 100644
index 8fb8b16952..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-groups/manage-groups.route.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-import {
- templateUrl
-} from '../../../shared/template-url/template-url.factory';
-
-export default {
- edit: {
- name: 'inventoryManage.editGroup',
- route: '/:group_id/editGroup',
- templateUrl: templateUrl('inventories/manage/manage-groups/manage-groups'),
- data: {
- group_id: 'group_id',
- mode: 'edit'
- },
- ncyBreadcrumb: {
- label: "INVENTORY EDIT GROUPS"
- }
- },
-
- add: {
- name: 'inventoryManage.addGroup',
- route: '/addGroup',
- templateUrl: templateUrl('inventories/manage/manage-groups/manage-groups'),
- ncyBreadcrumb: {
- label: "INVENTORY ADD GROUP"
- },
- data: {
- mode: 'add'
- }
- },
-
-};
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js b/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js
deleted file mode 100644
index bf349a9e1c..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.route.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-import {templateUrl} from '../../../shared/template-url/template-url.factory';
-import addController from './manage-hosts-add.controller';
-import editController from './manage-hosts-edit.controller';
-
-var ManageHostsEdit = {
- name: 'inventoryManage.editHost',
- route: '/host/:host_id',
- controller: editController,
- templateUrl: templateUrl('inventories/manage/manage-hosts/manage-hosts'),
- ncyBreadcrumb: {
- label: "INVENTORY EDIT HOSTS"
- },
- data: {
- mode: 'edit'
- },
- resolve: {
- host: ['$stateParams', 'ManageHostsService', function($stateParams, ManageHostsService){
- return ManageHostsService.get({id: $stateParams.host_id}).then(function(res){
- return res.data.results[0];
- });
- }]
- }
-};
-var ManageHostsAdd = {
- name: 'inventoryManage.addHost',
- route: '/host/add',
- controller: addController,
- templateUrl: templateUrl('inventories/manage/manage-hosts/manage-hosts'),
- ncyBreadcrumb: {
- label: "INVENTORY ADD HOST"
- },
- data: {
- mode: 'add'
- }
-};
-export {ManageHostsAdd, ManageHostsEdit};
diff --git a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js b/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js
deleted file mode 100644
index c7a64cb60d..0000000000
--- a/awx/ui/client/src/inventories/manage/manage-hosts/manage-hosts.service.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
- export default
- ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors',
- function($rootScope, Rest, GetBasePath, ProcessErrors){
- return {
- stringifyParams: function(params){
- return _.reduce(params, (result, value, key) => {
- return result + key + '=' + value + '&';
- }, '');
- },
- get: function(params){
- var url = GetBasePath('hosts') + '?' + this.stringifyParams(params);
- Rest.setUrl(url);
- return Rest.get()
- .success(function(res){
- return res;
- })
- .error(function(data, status) {
- ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
- msg: 'Call to ' + url + '. GET returned: ' + status });
- });
- },
- post: function(params){
- var url = GetBasePath('hosts');
- Rest.setUrl(url);
- return Rest.post(params)
- .success(function(res){
- return res;
- })
- .error(function(data, status) {
- ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
- msg: 'Call to ' + url + '. GET returned: ' + status });
- });
- },
- put: function(host){
- var url = GetBasePath('hosts') + host.id;
- Rest.setUrl(url);
- return Rest.put(host)
- .success(function(res){
- return res;
- })
- .error(function(data, status) {
- ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
- msg: 'Call to ' + url + '. GET returned: ' + status });
- });
- }
- };
- }];
\ No newline at end of file
diff --git a/awx/ui/client/src/inventories/manage/manage.block.less b/awx/ui/client/src/inventories/manage/manage.block.less
deleted file mode 100644
index 772423c2e4..0000000000
--- a/awx/ui/client/src/inventories/manage/manage.block.less
+++ /dev/null
@@ -1,18 +0,0 @@
-#Inventory-groupManage--panel,
-#Inventory-hostManage--panel {
- .ui-dialog-buttonpane.ui-widget-content {
- border: none;
- text-align: right;
- }
-
- #host-panel-form,
- #properties-tab {
- .Form-header {
- margin-top: -20px;
- }
- }
-
- .Form-textArea {
- width: 100%;
- }
-}
diff --git a/awx/ui/client/src/job-detail/job-detail.controller.js b/awx/ui/client/src/job-detail/job-detail.controller.js
index 2061d00df3..2e927fad2c 100644
--- a/awx/ui/client/src/job-detail/job-detail.controller.js
+++ b/awx/ui/client/src/job-detail/job-detail.controller.js
@@ -11,22 +11,17 @@
*/
export default
- [ '$location', '$rootScope', '$filter', '$scope', '$compile',
- '$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait',
- 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed',
- 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun',
- 'LoadPlays', 'LoadTasks', 'HostsEdit',
- 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
- 'EditSchedule', 'ParseTypeChange', 'JobDetailService',
+ [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$stateParams', '$log', 'ClearScope',
+ 'GetBasePath', 'Wait', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed', 'JobIsFinished',
+ 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun', 'LoadPlays', 'LoadTasks',
+ 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule',
+ 'ParseTypeChange', 'JobDetailService',
function(
- $location, $rootScope, $filter, $scope, $compile, $stateParams,
- $log, ClearScope, GetBasePath, Wait, ProcessErrors,
- SelectPlay, SelectTask, GetElapsed,
- JobIsFinished,
- SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob,
- InitiatePlaybookRun, LoadPlays, LoadTasks,
- HostsEdit, ParseVariableString, GetChoices, fieldChoices,
- fieldLabels, EditSchedule, ParseTypeChange, JobDetailService
+ $location, $rootScope, $filter, $scope, $compile, $stateParams, $log, ClearScope,
+ GetBasePath, Wait, ProcessErrors, SelectPlay, SelectTask, GetElapsed, JobIsFinished,
+ SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, InitiatePlaybookRun, LoadPlays, LoadTasks,
+ ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule,
+ ParseTypeChange, JobDetailService
) {
ClearScope();
diff --git a/awx/ui/client/src/lists/Groups.js b/awx/ui/client/src/lists/Groups.js
index 33bf611371..f93162b302 100644
--- a/awx/ui/client/src/lists/Groups.js
+++ b/awx/ui/client/src/lists/Groups.js
@@ -9,41 +9,17 @@
export default
angular.module('GroupListDefinition', [])
- .value('GroupList', {
+ .value('CopyMoveGroupList', {
- name: 'copy_groups',
- iterator: 'copy_group',
+ name: 'groups',
+ iterator: 'group',
selectTitle: 'Copy Groups',
- editTitle: 'Groups',
index: false,
- well: false,
-
+ well: false,
fields: {
name: {
key: true,
- label: 'Name'
- }
- },
-
- actions: { },
-
- fieldActions: {
- edit: {
- label: 'Edit',
- ngClick: "editGroup(group.id)",
- icon: 'icon-edit',
- "class": 'btn-xs',
- awToolTip: 'Edit group',
- dataPlacement: 'top'
- },
-
- "delete": {
- label: 'Delete',
- ngClick: "deleteGroup(group.id, group.name)",
- icon: 'icon-trash',
- "class": 'btn-xs',
- awToolTip: 'Delete group',
- dataPlacement: 'top'
+ label: 'Target Group Name'
}
}
});
diff --git a/awx/ui/client/src/lists/Inventories.js b/awx/ui/client/src/lists/Inventories.js
index a40850649f..60543239c0 100644
--- a/awx/ui/client/src/lists/Inventories.js
+++ b/awx/ui/client/src/lists/Inventories.js
@@ -96,7 +96,7 @@ export default
edit: {
label: 'Edit',
- ngClick: 'editInventory(inventory.id)', //'editInventoryProperties(inventory.id)',
+ ngClick: 'editInventory(inventory.id)',
awToolTip: 'Edit inventory',
dataPlacement: 'top'
},
diff --git a/awx/ui/client/src/lists/InventoryGroups.js b/awx/ui/client/src/lists/InventoryGroups.js
index 6002000e53..1f12a3af5a 100644
--- a/awx/ui/client/src/lists/InventoryGroups.js
+++ b/awx/ui/client/src/lists/InventoryGroups.js
@@ -21,18 +21,47 @@ export default
multiSelect: true,
fields: {
+ sync_status: {
+ label: '',
+ nosort: true,
+ searchable: false,
+ mode: 'all',
+ iconOnly: true,
+ ngClick: 'viewUpdateStatus(group.id)',
+ awToolTip: "{{ group.status_tooltip }}",
+ dataTipWatch: "group.status_tooltip",
+ icon: "{{ 'fa icon-cloud-' + group.status_class }}",
+ ngClass: "group.status_class",
+ dataPlacement: "top",
+ columnClass: 'status-column List-staticColumn--smallStatus'
+ },
+ failed_hosts: {
+ label: '',
+ nosort: true,
+ searchable: false,
+ mode: 'all',
+ iconOnly: true,
+ awToolTip: "{{ group.hosts_status_tip }}",
+ dataPlacement: "top",
+ ngClick: "showFailedHosts(group)",
+ icon: "{{ 'fa icon-job-' + group.hosts_status_class }}",
+ columnClass: 'status-column List-staticColumn--smallStatus'
+ },
name: {
label: 'Groups',
key: true,
ngClick: "groupSelect(group.id)",
- columnClick: "groupSelect(group.id)",
- columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-3'
+ columnClass: 'col-lg-3 col-md-3 col-sm-3 col-xs-3',
+ class: 'InventoryManage-breakWord'
},
total_groups: {
nosort: true,
label: '',
type: 'badgeCount',
ngHide: 'group.total_groups == 0',
+ noLink: true,
+ awToolTip: "{{group.name}} contains {{group.total_groups}} {{group.total_groups === 1 ? 'child' : 'children'}}",
+
},
source: {
label: 'Source',
@@ -100,8 +129,9 @@ export default
},
launch: {
mode: 'all',
- ngShow: 'inventory.can_run_ad_hoc_commands',
- ngClick: 'populateAdhocForm()',
+ // $scope.$parent is governed by InventoryManageController,
+ ngShow: '$parent.groupsSelected || $parent.hostsSelected',
+ ngClick: '$parent.setAdhocPattern()',
awToolTip: "Run a command on the selected inventory",
actionClass: 'btn List-buttonDefault',
buttonContent: 'RUN COMMANDS'
@@ -116,7 +146,7 @@ export default
ngClick: "createGroup()",
awToolTip: "Create a new group",
actionClass: 'btn List-buttonSubmit',
- buttonContent: '+ ADD'
+ buttonContent: '+ ADD GROUP'
}
},
@@ -124,32 +154,16 @@ export default
columnClass: 'col-lg-6 col-md-6 col-sm-6 col-xs-6 text-right',
- sync_status: {
- mode: 'all',
- ngClick: "viewUpdateStatus(group.id)",
- awToolTip: "{{ group.status_tooltip }}",
- dataTipWatch: "group.status_tooltip",
- iconClass: "{{ 'fa icon-cloud-' + group.status_class }}",
- ngClass: "group.status_class",
- dataPlacement: "top"
- },
- failed_hosts: {
- mode: 'all',
- awToolTip: "{{ group.hosts_status_tip }}",
- dataPlacement: "top",
- ngClick: "showHosts(group.id, group.group_id, group.show_failures)",
- iconClass: "{{ 'fa icon-job-' + group.hosts_status_class }}"
- },
group_update: {
//label: 'Sync',
mode: 'all',
- ngClick: 'updateGroup(group.id)',
+ ngClick: 'updateGroup(group)',
awToolTip: "{{ group.launch_tooltip }}",
dataTipWatch: "group.launch_tooltip",
ngShow: "group.status !== 'running' && group.status " +
"!== 'pending' && group.status !== 'updating'",
ngClass: "group.launch_class",
- dataPlacement: "top"
+ dataPlacement: "top",
},
cancel: {
//label: 'Cancel',
@@ -159,11 +173,12 @@ export default
'class': 'red-txt',
ngShow: "group.status == 'running' || group.status == 'pending' " +
"|| group.status == 'updating'",
- dataPlacement: "top"
+ dataPlacement: "top",
+ iconClass: "fa fa-minus-circle"
},
copy: {
mode: 'all',
- ngClick: "copyGroup(group.id)",
+ ngClick: "copyMoveGroup(group.id)",
awToolTip: 'Copy or move group',
ngShow: "group.id > 0",
dataPlacement: "top"
@@ -186,7 +201,7 @@ export default
"delete": {
//label: 'Delete',
mode: 'all',
- ngClick: "deleteGroup(group.id)",
+ ngClick: "deleteGroup(group)",
awToolTip: 'Delete group',
dataPlacement: "top"
}
diff --git a/awx/ui/client/src/lists/InventoryHosts.js b/awx/ui/client/src/lists/InventoryHosts.js
index 655f8e28ac..d99589968e 100644
--- a/awx/ui/client/src/lists/InventoryHosts.js
+++ b/awx/ui/client/src/lists/InventoryHosts.js
@@ -22,6 +22,23 @@ export default
multiSelect: true,
fields: {
+ active_failures: {
+ label: '',
+ iconOnly: true,
+ searchable: false,
+ 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',
@@ -29,7 +46,8 @@ export default
ngClass: "{ 'host-disabled-label': !host.enabled }",
columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7',
dataHostId: "{{ host.id }}",
- dataType: "host"
+ dataType: "host",
+ class: 'InventoryManage-breakWord'
},
enabled: {
label: 'Disabled?',
@@ -50,20 +68,9 @@ export default
fieldActions: {
columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right',
- label: false,
-
- active_failures: {
- awPopOver: "{{ host.job_status_html }}",
- dataTitle: "{{ host.job_status_title }}",
- awToolTip: "{{ host.badgeToolTip }}",
- awTipPlacement: 'top',
- dataPlacement: 'left',
- iconClass: "{{ 'fa icon-job-' + host.active_failures }}",
- id: 'active-failutes-action'
- },
copy: {
mode: 'all',
- ngClick: "copyHost(host.id)",
+ ngClick: "copyMoveHost(host.id)",
awToolTip: 'Copy or move host to another group',
dataPlacement: "top"
},
@@ -85,15 +92,15 @@ export default
actions: {
system_tracking: {
- label: 'System Tracking',
- ngClick: 'systemTracking()', //'editInventoryProperties(inventory.id)',
+ buttonContent: 'System Tracking',
+ ngClick: 'systemTracking()',
awToolTip: "{{ systemTrackingTooltip }}",
dataTipWatch: "systemTrackingTooltip",
dataPlacement: 'top',
awFeature: 'system_tracking',
- ngDisabled: 'systemTrackingDisabled',
actionClass: 'btn List-buttonDefault system-tracking',
- ngShow: 'hostsSelected'
+ ngShow: 'hostsSelected',
+ ngDisabled: 'systemTrackingDisabled'
},
refresh: {
mode: 'all',
@@ -108,7 +115,7 @@ export default
ngClick: "createHost()",
awToolTip: "Create a new host",
actionClass: 'btn List-buttonSubmit',
- buttonContent: '+ ADD'
+ buttonContent: '+ ADD HOST'
}
}
diff --git a/awx/ui/client/src/main-menu/main-menu.directive.js b/awx/ui/client/src/main-menu/main-menu.directive.js
index a8056e233f..8a3ea0917f 100644
--- a/awx/ui/client/src/main-menu/main-menu.directive.js
+++ b/awx/ui/client/src/main-menu/main-menu.directive.js
@@ -10,6 +10,9 @@ export default
scope.isCurrentState = function(name){
return $state.current.name === name;
};
+ scope.includesCurrentState = function(name){
+ return $state.includes(name);
+ };
// set up the user tooltip
$rootScope.$on('current_user', function(user) {
diff --git a/awx/ui/client/src/scheduler/main.js b/awx/ui/client/src/scheduler/main.js
index b75ee987b9..faaf6ecce7 100644
--- a/awx/ui/client/src/scheduler/main.js
+++ b/awx/ui/client/src/scheduler/main.js
@@ -52,19 +52,26 @@ export default
controller: 'schedulerEditController'
});
$stateExtender.addState({
- name: 'inventoryManageSchedules',
- route: '/inventory/:inventory_id/manage/:id/schedules',
- templateUrl: templateUrl("scheduler/scheduler"),
- controller: 'schedulerController'
+ name: 'inventoryManage.schedules',
+ route: '/schedules/:id',
+ views: {
+ 'form@inventoryManage': {
+ templateUrl: templateUrl("scheduler/scheduler"),
+ controller: 'schedulerController'
+ }
+ },
+ ncyBreadcrumb: {
+ label: "{{name}} SCHEDULES"
+ },
});
$stateExtender.addState({
- name: 'inventoryManageSchedules.add',
+ name: 'inventoryManage.schedules.add',
route: '/add',
templateUrl: templateUrl("scheduler/schedulerForm"),
controller: 'schedulerAddController'
});
$stateExtender.addState({
- name: 'inventoryManageSchedules.edit',
+ name: 'inventoryManage.schedules.edit',
route: '/:schedule_id',
templateUrl: templateUrl("scheduler/schedulerForm"),
controller: 'schedulerEditController'
diff --git a/awx/ui/client/src/shared/InventoryTree.js b/awx/ui/client/src/shared/InventoryTree.js
deleted file mode 100644
index f6c9ecb925..0000000000
--- a/awx/ui/client/src/shared/InventoryTree.js
+++ /dev/null
@@ -1,609 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-
- /**
- * @ngdoc function
- * @name shared.function:inventoryTree
- * @description
- * InventoryTree.js
- *
- * Build data for the tree selector table used on inventory detail page.
- *
- */
-
-
-export default
-angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'PromptDialog'])
-
-.factory('SortNodes', [
- function () {
- return function (data) {
- //Sort nodes by name
- var i, j, names = [], newData = [];
- for (i = 0; i < data.length; i++) {
- names.push(data[i].name);
- }
- names.sort();
- for (j = 0; j < names.length; j++) {
- for (i = 0; i < data.length; i++) {
- if (data[i].name === names[j]) {
- newData.push(data[i]);
- }
- }
- }
- return newData;
- };
- }
-])
-
-.factory('BuildTree', ['$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Store',
- function ($location, Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg, Store) {
- return function (params) {
-
- var inventory_id = params.inventory_id,
- scope = params.scope,
- refresh = params.refresh,
- emit = params.emit,
- new_group_id = params.new_group_id,
- groups = [],
- id = 1,
- local_child_store,
- path = $location.path();
-
- function buildAllHosts(tree_data) {
- // Start our tree object with All Hosts
- var children = [],
- sorted = SortNodes(tree_data),
- j, all_hosts;
-
- for (j = 0; j < sorted.length; j++) {
- children.push(sorted[j].id);
- }
-
- all_hosts = {
- name: 'All Hosts',
- id: 1,
- group_id: null,
- parent: 0,
- description: '',
- show: true,
- ngicon: null,
- has_children: false,
- related: {},
- selected_class: '',
- show_failures: false,
- isDraggable: false,
- isDroppable: true,
- children: children
- };
- groups.push(all_hosts);
- }
-
- function getExpandState(key) {
- var result = true;
- local_child_store.every(function(child) {
- if (child.key === key) {
- result = child.expand;
- return false;
- }
- return true;
- });
- return result;
- }
-
- function getShowState(key) {
- var result = null;
- local_child_store.every(function(child) {
- if (child.key === key) {
- result = (child.show !== undefined) ? child.show : true;
- return false;
- }
- return true;
- });
- return result;
- }
-
- function buildGroups(tree_data, parent, level) {
-
- var children, stat, hosts_status, group,
- sorted = SortNodes(tree_data),
- expand, show;
-
- sorted.forEach( function(row, i) {
- id++;
-
- stat = GetSyncStatusMsg({
- status: sorted[i].summary_fields.inventory_source.status,
- has_inventory_sources: sorted[i].has_inventory_sources,
- source: ( (sorted[i].summary_fields.inventory_source) ? sorted[i].summary_fields.inventory_source.source : null )
- }); // from helpers/Groups.js
-
- hosts_status = GetHostsStatusMsg({
- active_failures: sorted[i].hosts_with_active_failures,
- total_hosts: sorted[i].total_hosts,
- inventory_id: inventory_id,
- group_id: sorted[i].id
- }); // from helpers/Groups.js
-
- children = [];
- sorted[i].children.forEach( function(child, j) {
- children.push(sorted[i].children[j].id);
- });
-
- expand = (sorted[i].children.length > 0) ? getExpandState(sorted[i].id) : false;
- show = getShowState(sorted[i].id);
- if (show === null) {
- // this is a node we haven't seen before, so check the parent expand/collapse state
- // If parent is not expanded, then child should be hidden.
- show = true;
- if (parent > 0) {
- groups.every(function(g) {
- if (g.id === parent) {
- show = getExpandState(g.key);
- return false;
- }
- return true;
- });
- }
- }
-
- group = {
- name: sorted[i].name,
- has_active_failures: sorted[i].has_active_failures,
- total_hosts: sorted[i].total_hosts,
- hosts_with_active_failures: sorted[i].hosts_with_active_failures,
- total_groups: sorted[i].total_groups,
- groups_with_active_failures: sorted[i].groups_with_active_failures,
- parent: parent,
- has_children: (sorted[i].children.length > 0) ? true : false,
- has_inventory_sources: sorted[i].has_inventory_sources,
- id: id,
- source: sorted[i].summary_fields.inventory_source.source,
- key: sorted[i].id,
- group_id: sorted[i].id,
- event_level: level,
- children: children,
- show: show,
- related: sorted[i].related,
- status: sorted[i].summary_fields.inventory_source.status,
- status_class: stat['class'],
- status_tooltip: stat.tooltip,
- launch_tooltip: stat.launch_tip,
- launch_class: stat.launch_class,
- hosts_status_tip: hosts_status.tooltip,
- show_failures: hosts_status.failures,
- hosts_status_class: hosts_status['class'],
- inventory_id: inventory_id,
- selected_class: '',
- isDraggable: true,
- isDroppable: true
- };
- if (sorted[i].children.length > 0) {
- if (expand) {
- group.ngicon = 'fa fa-minus-square-o node-toggle';
- }
- else {
- group.ngicon = 'fa fa-plus-square-o node-toggle';
- }
- }
- else {
- group.ngicon = 'fa fa-square-o node-no-toggle';
- }
- if (new_group_id && group.group_id === new_group_id) {
- scope.selected_tree_id = id;
- scope.selected_group_id = group.group_id;
- }
- groups.push(group);
- if (sorted[i].children.length > 0) {
- buildGroups(sorted[i].children, id, level + 1);
- }
- });
- }
-
- // Build the HTML for our tree
- if (scope.buildAllGroupsRemove) {
- scope.buildAllGroupsRemove();
- }
- scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function (e, inventory_name, inventory_tree) {
- Rest.setUrl(inventory_tree);
- Rest.get()
- .success(function (data) {
- buildAllHosts(data);
- buildGroups(data, 0, 0);
- scope.autoShowGroupHelp = (data.length === 0) ? true : false;
- if (refresh) {
- scope.groups = groups;
- scope.$emit('GroupTreeRefreshed', inventory_name, groups, emit);
- } else {
- scope.$emit('GroupTreeLoaded', inventory_name, groups, emit);
- }
- })
- .error(function (data, status) {
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status
- });
- });
- });
-
-
- function loadTreeData() {
- // Load the inventory root node
- Wait('start');
- Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
- Rest.get()
- .success(function (data) {
- scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
- })
- .error(function (data, status) {
- Wait('stop');
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status
- });
- });
- }
- local_child_store = Store(path + '_children');
- if (!local_child_store) {
- local_child_store = [];
- }
- loadTreeData();
- };
- }
-])
-
-
-// Update a group with a set of properties
-.factory('UpdateGroup', ['ApplyEllipsis', 'GetSyncStatusMsg', 'Empty',
- function (ApplyEllipsis, GetSyncStatusMsg, Empty) {
- return function (params) {
-
- var scope = params.scope,
- group_id = params.group_id,
- properties = params.properties,
- i, p, grp, old_name, stat;
-
- for (i = 0; i < scope.groups.length; i++) {
- if (scope.groups[i].id === group_id) {
- grp = scope.groups[i];
- for (p in properties) {
- if (p === 'name') {
- old_name = scope.groups[i].name;
- }
- if (p === 'source') {
- if (properties[p] !== scope.groups[i][p]) {
- // User changed source
- if (!Empty(properties[p]) && (scope.groups[i].status === 'none' || Empty(scope.groups[i].status))) {
- // We have a source but no status, seed the status with 'never' to enable sync button
- scope.groups[i].status = 'never updated';
- } else if (!properties[p]) {
- // User removed source
- scope.groups[i].status = 'none';
- }
- // Update date sync status links/icons
- stat = GetSyncStatusMsg({
- status: scope.groups[i].status,
- has_inventory_sources: properties.has_inventory_sources,
- source: properties.source
- });
- scope.groups[i].status_class = stat['class'];
- scope.groups[i].status_tooltip = stat.tooltip;
- scope.groups[i].launch_tooltip = stat.launch_tip;
- scope.groups[i].launch_class = stat.launch_class;
- }
- }
- scope.groups[i][p] = properties[p];
- }
- }
- /*if (scope.groups[i].id === scope.selected_tree_id) {
- //Make sure potential group name change gets reflected throughout the page
- scope.selected_group_name = scope.groups[i].name;
- scope.search_place_holder = 'Search ' + scope.groups[i].name;
- scope.hostSearchPlaceholder = 'Search ' + scope.groups[i].name;
- }*/
- }
-
- // Update any titles attributes created by ApplyEllipsis
- if (old_name) {
- setTimeout(function () {
- $('#groups_table .group-name a[title="' + old_name + '"]').attr('title', properties.name);
- ApplyEllipsis('#groups_table .group-name a');
- }, 2500);
- }
-
- };
- }
-])
-
-
-// Set node name and description after an update to Group properties.
-.factory('SetNodeName', [
- function () {
- return function (params) {
- var name = params.name,
- descr = params.description,
- group_id = (params.group_id !== undefined) ? params.group_id : null,
- inventory_id = (params.inventory_id !== undefined) ? params.inventory_id : null;
-
- if (group_id !== null) {
- $('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function () {
- $(this).attr('data-name', name);
- $(this).attr('data-description', descr);
- $(this).find('.activate').first().text(name);
- });
- }
-
- if (inventory_id !== null) {
- $('#inventory-root-node').attr('data-name', name).attr('data-description', descr).find('.activate').first().text(name);
- }
- };
- }
-])
-
-
-// Copy or Move a group on the tree after drag-n-drop
-.factory('CopyMoveGroup', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
- function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
- return function (params) {
-
- var scope = params.scope,
- target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }),
- inbound = Find({ list: scope.groups, key: 'id', val: params.inbound_tree_id }),
- e, html = '';
-
- // Build the html for our prompt dialog
- html += "
\n";
- html += "
\n";
- html += "
\n";
- html += "\n";
- html += "
\n";
-
- if (target.id === 1) {
- html += "
Are you sure you want to move group " + inbound.name + " to the top level?
";
- } else if (inbound.parent === 0) {
- html += "
Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " +
- target.name + "?
";
- } else {
- html += "
\n";
- html += "
Would you like to copy or move group " + inbound.name + " to group " + target.name + " ?
\n";
- html += "
\n";
- html += "
Move\n";
- html += "
Copy\n";
- html += "
\n";
- html += "
\n";
- }
-
- html += "
\n";
- html += "\n";
- html += "
\n";
- html += "
\n";
- html += "
\n";
-
- // Inject our custom dialog
- e= angular.element(document.getElementById('inventory-modal-container'));
- e.empty().append(html);
- $compile(e)(scope);
-
- // Display it
- $('#copy-prompt-modal').modal({
- backdrop: 'static',
- keyboard: true,
- show: true
- });
-
- // Respond to move
- scope.moveGroup = function () {
- var url, group, parent;
- $('#copy-prompt-modal').modal('hide');
- Wait('start');
-
- // disassociate the group from the original parent
- if (scope.removeGroupRemove) {
- scope.removeGroupRemove();
- }
- scope.removeGroupRemove = scope.$on('removeGroup', function () {
- if (inbound.parent > 0) {
- // Only remove a group from a parent when the parent is a group and not the inventory root
- parent = Find({ list: scope.groups, key: 'id', val: inbound.parent });
- url = GetBasePath('base') + 'groups/' + parent.group_id + '/children/';
- Rest.setUrl(url);
- Rest.post({ id: inbound.group_id, disassociate: 1 })
- .success(function () {
- //Triggers refresh of group list in inventory controller
- scope.$emit('GroupDeleteCompleted');
- })
- .error(function (data, status) {
- Wait('stop');
- ProcessErrors(scope, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to remove ' + inbound.name +
- ' from ' + parent.name + '. POST returned status: ' + status
- });
- });
- } else {
- //Triggers refresh of group list in inventory controller
- scope.$emit('GroupDeleteCompleted');
- }
- });
-
- // add the new group to the target parent
- url = (!Empty(target.group_id)) ?
- GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
- GetBasePath('inventory') + scope.inventory_id + '/groups/';
- group = {
- id: inbound.group_id,
- name: inbound.name,
- description: inbound.description,
- inventory: scope.inventory_id
- };
- Rest.setUrl(url);
- Rest.post(group)
- .success(function () {
- scope.$emit('removeGroup');
- })
- .error(function (data, status) {
- var target_name = (Empty(target.group_id)) ? 'inventory' : target.name;
- Wait('stop');
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status });
- });
- };
-
-
- scope.copyGroup = function () {
- $('#copy-prompt-modal').modal('hide');
- Wait('start');
- // add the new group to the target parent
- var url = (!Empty(target.group_id)) ?
- GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
- GetBasePath('inventory') + scope.inventory_id + '/groups/',
- group = {
- id: inbound.group_id,
- name: inbound.name,
- description: inbound.description,
- inventory: scope.inventory_id
- };
-
- Rest.setUrl(url);
- Rest.post(group)
- .success(function () {
- //Triggers refresh of group list in inventory controller
- scope.$emit('GroupDeleteCompleted');
- })
- .error(function (data, status) {
- var target_name = (Empty(target.group_id)) ? 'inventory' : target.name;
- Wait('stop');
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status
- });
- });
- };
-
- };
- }
-])
-
-// Copy a host after drag-n-drop
-.factory('CopyMoveHost', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
- function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
- return function (params) {
-
- var scope = params.scope,
- target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }),
- host = Find({ list: scope.hosts, key: 'id', val: params.host_id }),
- found = false, e, i, html = '';
-
- if (host.summary_fields.all_groups) {
- for (i = 0; i < host.summary_fields.all_groups.length; i++) {
- if (host.summary_fields.all_groups[i].id === target.group_id) {
- found = true;
- break;
- }
- }
- }
- if (found) {
- html += "
\n";
- html += "
\n";
- html += "
\n";
- html += "\n";
- html += "
\n";
- html += "
Host " + host.name + " is already in group " + target.name + ".
\n";
- html += "
\n";
- html += "\n";
- html += "
\n";
- html += "
\n";
- html += "
\n";
-
- // Inject our custom dialog
- e = angular.element(document.getElementById('inventory-modal-container'));
- e.empty().append(html);
- $compile(e)(scope);
-
- // Display it
- $('#copy-alert-modal').modal({
- backdrop: 'static',
- keyboard: true,
- show: true
- });
-
- } else {
- // Build the html for our prompt dialog
- html = '';
- html += "
\n";
- html += "
\n";
- html += "
\n";
- html += "\n";
- html += "
\n";
- html += "
Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?
';
- html += "
\n";
- html += "\n";
- html += "
\n";
- html += "
\n";
- html += "
\n";
-
- // Inject our custom dialog
- e = angular.element(document.getElementById('inventory-modal-container'));
- e.empty().append(html);
- $compile(e)(scope);
-
- // Display it
- $('#copy-prompt-modal').modal({
- backdrop: 'static',
- keyboard: true,
- show: true
- });
-
- scope.copyHost = function () {
- $('#copy-prompt-modal').modal('hide');
- Wait('start');
- Rest.setUrl(GetBasePath('groups') + target.group_id + '/hosts/');
- Rest.post(host)
- .success(function () {
- // Signal the controller to refresh the hosts view
- scope.$emit('GroupTreeRefreshed');
- })
- .error(function (data, status) {
- Wait('stop');
- ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Failed to add ' + host.name + ' to ' +
- target.name + '. POST returned status: ' + status });
- });
- };
- }
- };
- }
-]);
diff --git a/awx/ui/client/src/shared/generator-helpers.js b/awx/ui/client/src/shared/generator-helpers.js
index fc62bbecbd..7a0c517a58 100644
--- a/awx/ui/client/src/shared/generator-helpers.js
+++ b/awx/ui/client/src/shared/generator-helpers.js
@@ -277,10 +277,14 @@ angular.module('GeneratorHelpers', [systemStatus.name])
html = "
\n";
- html += "";
+ }
+ html += "";
- html += "";
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 9e2da09fc4..a0a8258595 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
@@ -439,6 +439,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
innerTable += "ng-class-odd=\"'List-tableRow--oddRow'\" ";
innerTable += "ng-class-even=\"'List-tableRow--evenRow'\" ";
innerTable += "ng-repeat=\"" + list.iterator + " in " + list.name;
+ innerTable += (list.trackBy) ? " track by " + list.trackBy : " track by $index";
innerTable += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : "";
innerTable += (list.filterBy) ? " | filter: " + list.filterBy : "";
innerTable += "\">\n";
@@ -459,7 +460,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
"ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" /> ";
}
else { // its assumed that options.input_type = checkbox
- innerTable += "
";
}
@@ -619,7 +620,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
html += buildSelectAll().prop('outerHTML');
}
else if (options.mode === 'lookup') {
- html += "";
+ html += "";
}
for (fld in list.fields) {
if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) &&
diff --git a/awx/ui/client/tests/adhoc/adhoc.controller-test.js b/awx/ui/client/tests/adhoc/adhoc.controller-test.js
index 27d61b3f30..d49c699994 100644
--- a/awx/ui/client/tests/adhoc/adhoc.controller-test.js
+++ b/awx/ui/client/tests/adhoc/adhoc.controller-test.js
@@ -1,6 +1,6 @@
import '../support/node';
-import adhocModule from 'adhoc/main';
+import adhocModule from 'inventories/manage/adhoc/main';
import RestStub from '../support/rest-stub';
describe("adhoc.controller", function() {
diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html
index 7960ba38c9..3e8395b3e8 100644
--- a/awx/ui/templates/ui/index.html
+++ b/awx/ui/templates/ui/index.html
@@ -40,7 +40,7 @@
-
+