mirror of
https://github.com/ansible/awx.git
synced 2026-03-27 05:45:02 -02:30
Refactor Inventories > Inventory Manage module (#2013)
* refactor InventoryManage modules, resolves #1748, #1354, #1754, #1960, #1961, #1962, #1963, #1965 * refactor InventoryManage modules, resolves #1748, #1354, #1754, #1960, #1961, #1962, #1963, #1965 * instantiate lookupfields with correct values / endpoint queries #1979 * fix groups/host list sort and remove some unnecessary service abstractions #1979 * fix childless delete wording * add host > toggle enabled/disabled * fix breadcrumb indexing * remove extra required asterisk from inventory script lookup field * fix delete prompt styling * remove group badge linking, add toolip * full width host var form, fix add/edit group inventory source vars * restrict copy/moving multiselect to one item * break word on host/group names and support multiple rows of breakcrumbs * hide trailing breadcrumb slash at root group view * fix failing unit test dependency path, hook up system tracking * fix ec2 group by label rendering in group > edit view, fix add/edit/adhoc breadcrumb display when breadcrumbs are 2+ rows * fix select spacing on copy/move groups * limit group/host/copyMove search to current context * refresh status icons on page/search event * move status indicators to left side of lists * fix typo in select2 init * fix assorted typos * $track by statement needs to tail | filterBy:xyz * fix JSHint failure * PR feedback, hook up filter for hosts with active failures, hook up status tooltips/popovers
This commit is contained in:
@@ -1,14 +0,0 @@
|
|||||||
/*************************************************
|
|
||||||
* Copyright (c) 2015 Ansible, Inc.
|
|
||||||
*
|
|
||||||
* All Rights Reserved
|
|
||||||
*************************************************/
|
|
||||||
|
|
||||||
import {templateUrl} from '../shared/template-url/template-url.factory';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
route: '/adhoc',
|
|
||||||
name: 'inventoryManage.adhoc',
|
|
||||||
templateUrl: templateUrl('adhoc/adhoc'),
|
|
||||||
controller: 'adhocController'
|
|
||||||
};
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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);
|
|
||||||
@@ -47,7 +47,6 @@ import browserData from './browser-data/main';
|
|||||||
import dashboard from './dashboard/main';
|
import dashboard from './dashboard/main';
|
||||||
import moment from './shared/moment/main';
|
import moment from './shared/moment/main';
|
||||||
import templateUrl from './shared/template-url/main';
|
import templateUrl from './shared/template-url/main';
|
||||||
import adhoc from './adhoc/main';
|
|
||||||
import login from './login/main';
|
import login from './login/main';
|
||||||
import activityStream from './activity-stream/main';
|
import activityStream from './activity-stream/main';
|
||||||
import standardOut from './standard-out/main';
|
import standardOut from './standard-out/main';
|
||||||
@@ -67,7 +66,6 @@ import './shared/Modal';
|
|||||||
import './shared/prompt-dialog';
|
import './shared/prompt-dialog';
|
||||||
import './shared/directives';
|
import './shared/directives';
|
||||||
import './shared/filters';
|
import './shared/filters';
|
||||||
import './shared/InventoryTree';
|
|
||||||
import './shared/Socket';
|
import './shared/Socket';
|
||||||
import './shared/features/main';
|
import './shared/features/main';
|
||||||
import './login/authenticationServices/pendo/ng-pendo';
|
import './login/authenticationServices/pendo/ng-pendo';
|
||||||
@@ -99,7 +97,6 @@ var tower = angular.module('Tower', [
|
|||||||
dashboard.name,
|
dashboard.name,
|
||||||
moment.name,
|
moment.name,
|
||||||
templateUrl.name,
|
templateUrl.name,
|
||||||
adhoc.name,
|
|
||||||
login.name,
|
login.name,
|
||||||
activityStream.name,
|
activityStream.name,
|
||||||
footer.name,
|
footer.name,
|
||||||
@@ -169,7 +166,6 @@ var tower = angular.module('Tower', [
|
|||||||
'StreamWidget',
|
'StreamWidget',
|
||||||
'JobsHelper',
|
'JobsHelper',
|
||||||
'InventoryGroupsHelpDefinition',
|
'InventoryGroupsHelpDefinition',
|
||||||
'InventoryTree',
|
|
||||||
'CredentialsHelper',
|
'CredentialsHelper',
|
||||||
'StreamListDefinition',
|
'StreamListDefinition',
|
||||||
'HomeGroupListDefinition',
|
'HomeGroupListDefinition',
|
||||||
@@ -224,6 +220,7 @@ var tower = angular.module('Tower', [
|
|||||||
|
|
||||||
// route to the details pane of /job/:id/host-event/:eventId if no other child specified
|
// route to the details pane of /job/:id/host-event/:eventId if no other child specified
|
||||||
$urlRouterProvider.when('/jobs/*/host-event/*', '/jobs/*/host-event/*/details');
|
$urlRouterProvider.when('/jobs/*/host-event/*', '/jobs/*/host-event/*/details');
|
||||||
|
|
||||||
// $urlRouterProvider.otherwise("/home");
|
// $urlRouterProvider.otherwise("/home");
|
||||||
$urlRouterProvider.otherwise(function($injector){
|
$urlRouterProvider.otherwise(function($injector){
|
||||||
var $state = $injector.get("$state");
|
var $state = $injector.get("$state");
|
||||||
|
|||||||
@@ -61,18 +61,10 @@ export default
|
|||||||
label: 'Source',
|
label: 'Source',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
ngOptions: 'source.label for source in source_type_options track by source.value',
|
ngOptions: 'source.label for source in source_type_options track by source.value',
|
||||||
ngChange: 'sourceChange()',
|
ngChange: 'sourceChange(source)',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
},
|
ngModel: 'source'
|
||||||
source_path: {
|
|
||||||
label: 'Script Path',
|
|
||||||
ngShow: "source && source.value == 'file'",
|
|
||||||
type: 'text',
|
|
||||||
awRequiredWhen: {
|
|
||||||
reqExpression: "sourcePathRequired",
|
|
||||||
init: "false"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
credential: {
|
credential: {
|
||||||
label: 'Cloud Credential',
|
label: 'Cloud Credential',
|
||||||
@@ -147,7 +139,6 @@ export default
|
|||||||
},
|
},
|
||||||
inventory_script: {
|
inventory_script: {
|
||||||
label : "Custom Inventory Script",
|
label : "Custom Inventory Script",
|
||||||
labelClass: 'prepend-asterisk',
|
|
||||||
type: 'lookup',
|
type: 'lookup',
|
||||||
ngShow: "source && source.value === 'custom'",
|
ngShow: "source && source.value === 'custom'",
|
||||||
sourceModel: 'inventory_script',
|
sourceModel: 'inventory_script',
|
||||||
@@ -157,7 +148,8 @@ export default
|
|||||||
editRequired: true,
|
editRequired: true,
|
||||||
ngRequired: "source && source.value === 'custom'",
|
ngRequired: "source && source.value === 'custom'",
|
||||||
},
|
},
|
||||||
extra_vars: {
|
custom_variables: {
|
||||||
|
id: 'custom_variables',
|
||||||
label: 'Environment Variables', //"{{vars_label}}" ,
|
label: 'Environment Variables', //"{{vars_label}}" ,
|
||||||
ngShow: "source && source.value=='custom' ",
|
ngShow: "source && source.value=='custom' ",
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
@@ -176,9 +168,10 @@ export default
|
|||||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n",
|
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n",
|
||||||
dataContainer: 'body'
|
dataContainer: 'body'
|
||||||
},
|
},
|
||||||
source_vars: {
|
ec2_variables: {
|
||||||
|
id: 'ec2_variables',
|
||||||
label: 'Source Variables', //"{{vars_label}}" ,
|
label: 'Source Variables', //"{{vars_label}}" ,
|
||||||
ngShow: "source && (source.value == 'file' || source.value == 'ec2')",
|
ngShow: "source && source.value == 'ec2'",
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
@@ -200,11 +193,11 @@ export default
|
|||||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||||
dataContainer: 'body'
|
dataContainer: 'body'
|
||||||
},
|
},
|
||||||
inventory_variables: {
|
vmware_variables: {
|
||||||
|
id: 'vmware_variables',
|
||||||
label: 'Source Variables', //"{{vars_label}}" ,
|
label: 'Source Variables', //"{{vars_label}}" ,
|
||||||
|
|
||||||
ngShow: "source && (source.value == 'vmware' || " +
|
ngShow: "source && source.value == 'vmware'",
|
||||||
"source.value == 'openstack')",
|
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||||
@@ -226,6 +219,32 @@ export default
|
|||||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||||
dataContainer: 'body'
|
dataContainer: 'body'
|
||||||
},
|
},
|
||||||
|
openstack_variables: {
|
||||||
|
id: 'openstack_variables',
|
||||||
|
label: 'Source Variables', //"{{vars_label}}" ,
|
||||||
|
|
||||||
|
ngShow: "source && source.value == 'openstack'",
|
||||||
|
type: 'textarea',
|
||||||
|
addRequired: false,
|
||||||
|
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||||
|
editRequird: false,
|
||||||
|
rows: 6,
|
||||||
|
'default': '---',
|
||||||
|
parseTypeName: 'envParseType',
|
||||||
|
dataTitle: "Source Variables",
|
||||||
|
dataPlacement: 'right',
|
||||||
|
awPopOver: "<p>Override variables found in openstack.yml and used by the inventory update script. For an example variable configuration " +
|
||||||
|
"<a href=\"https://github.com/ansible/ansible/blob/devel/contrib/inventory/openstack.yml\" target=\"_blank\">" +
|
||||||
|
"view openstack.yml in the Ansible github repo.</a></p>" +
|
||||||
|
"<p>Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.</p>" +
|
||||||
|
"JSON:<br />\n" +
|
||||||
|
"<blockquote>{<br /> \"somevar\": \"somevalue\",<br /> \"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||||
|
"YAML:<br />\n" +
|
||||||
|
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n" +
|
||||||
|
'<p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p>' +
|
||||||
|
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||||
|
dataContainer: 'body'
|
||||||
|
},
|
||||||
checkbox_group: {
|
checkbox_group: {
|
||||||
label: 'Update Options',
|
label: 'Update Options',
|
||||||
type: 'checkbox_group',
|
type: 'checkbox_group',
|
||||||
@@ -295,11 +314,11 @@ export default
|
|||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
|
save: {
|
||||||
|
ngClick: 'formSave()'
|
||||||
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()'
|
||||||
},
|
|
||||||
save: {
|
|
||||||
ngClick: 'saveGroup()'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default
|
|||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequird: false,
|
editRequird: false,
|
||||||
rows: 6,
|
rows: 6,
|
||||||
"class": "modal-input-xlarge Form-textArea",
|
"class": "modal-input-xlarge Form-textArea Form-formGroup--fullWidth",
|
||||||
"default": "---",
|
"default": "---",
|
||||||
awPopOver: "<p>Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.</p>" +
|
awPopOver: "<p>Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.</p>" +
|
||||||
"JSON:<br />\n" +
|
"JSON:<br />\n" +
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -217,489 +217,6 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', listGenerator.name,
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('InjectHosts', ['generateList', 'InventoryHosts', 'HostsReload',
|
|
||||||
function(GenerateList, InventoryHosts, HostsReload) {
|
|
||||||
return function(params) {
|
|
||||||
|
|
||||||
var group_scope = params.group_scope,
|
|
||||||
host_scope = params.host_scope,
|
|
||||||
inventory_id = params.inventory_id,
|
|
||||||
group_id = params.group_id,
|
|
||||||
pageSize = params.pageSize,
|
|
||||||
generator = GenerateList;
|
|
||||||
|
|
||||||
// Inject the list html
|
|
||||||
generator.inject(InventoryHosts, { scope: host_scope, mode: 'edit', id: 'host-list-container', searchSize: 'col-lg-6 col-md-6 col-sm-6 col-xs-12' });
|
|
||||||
|
|
||||||
// Load data
|
|
||||||
HostsReload({ scope: host_scope, group_id: group_id, inventory_id: inventory_id, parent_scope: group_scope, pageSize: pageSize });
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
.factory('HostsList', ['$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'HostList', 'generateList',
|
|
||||||
'Prompt', 'SearchInit', 'PaginateInit', 'ProcessErrors', 'GetBasePath', 'HostsAdd', 'HostsReload', 'SelectionInit',
|
|
||||||
function($rootScope, $location, $log, $stateParams, Rest, Alert, HostList, GenerateList, Prompt, SearchInit,
|
|
||||||
PaginateInit, ProcessErrors, GetBasePath, HostsAdd, HostsReload, SelectionInit) {
|
|
||||||
return function(params) {
|
|
||||||
|
|
||||||
var inventory_id = params.inventory_id,
|
|
||||||
group_id = params.group_id,
|
|
||||||
list = HostList,
|
|
||||||
generator = GenerateList,
|
|
||||||
defaultUrl, scope;
|
|
||||||
|
|
||||||
list.iterator = 'subhost'; //Override the iterator and name so the scope of the modal dialog
|
|
||||||
list.name = 'subhosts'; //will not conflict with the parent scope
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scope = generator.inject(list, {
|
|
||||||
id: 'form-modal-body',
|
|
||||||
mode: 'select',
|
|
||||||
selectButton: false
|
|
||||||
});
|
|
||||||
|
|
||||||
defaultUrl = GetBasePath('inventory') + inventory_id + '/hosts/?not__groups__id=' + scope.group_id;
|
|
||||||
|
|
||||||
scope.formModalActionLabel = 'Select';
|
|
||||||
scope.formModalHeader = 'Add Existing Hosts';
|
|
||||||
scope.formModalCancelShow = true;
|
|
||||||
|
|
||||||
SelectionInit({ scope: scope, list: list, url: GetBasePath('groups') + group_id + '/hosts/' });
|
|
||||||
|
|
||||||
if (scope.removeModalClosed) {
|
|
||||||
scope.removeModalClosed();
|
|
||||||
}
|
|
||||||
scope.removeModalClosed = scope.$on('modalClosed', function() {
|
|
||||||
// if the modal closed, assume something got changed and reload the host list
|
|
||||||
HostsReload(params);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.popover').popover('hide'); //remove any lingering pop-overs
|
|
||||||
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
|
|
||||||
$('#form-modal').modal({ backdrop: 'static', keyboard: false });
|
|
||||||
|
|
||||||
SearchInit({ scope: scope, set: 'subhosts', list: list, url: defaultUrl });
|
|
||||||
PaginateInit({ scope: scope, list: list, url: defaultUrl, mode: 'lookup' });
|
|
||||||
scope.search(list.iterator);
|
|
||||||
|
|
||||||
if (!scope.$$phase) {
|
|
||||||
scope.$digest();
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.createHost = function() {
|
|
||||||
$('#form-modal').modal('hide');
|
|
||||||
HostsAdd({ scope: params.scope, inventory_id: inventory_id, group_id: group_id });
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
|
||||||
.factory('HostsCreate', ['$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm',
|
|
||||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'ToJSON',
|
|
||||||
function($rootScope, $location, $log, $stateParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors,
|
|
||||||
GetBasePath, HostsReload, ParseTypeChange, Wait, ToJSON) {
|
|
||||||
return function(params) {
|
|
||||||
|
|
||||||
var parent_scope = params.scope,
|
|
||||||
inventory_id = parent_scope.inventory_id,
|
|
||||||
group_id = parent_scope.selected_group_id,
|
|
||||||
defaultUrl = GetBasePath('groups') + group_id + '/hosts/',
|
|
||||||
form = HostForm,
|
|
||||||
generator = GenerateForm,
|
|
||||||
scope = generator.inject(form, {mode: 'add', modal: true, related: false}),
|
|
||||||
master={};
|
|
||||||
|
|
||||||
scope.formModalActionLabel = 'Save';
|
|
||||||
scope.formModalHeader = 'Create New Host';
|
|
||||||
scope.formModalCancelShow = true;
|
|
||||||
|
|
||||||
scope.parseType = 'yaml';
|
|
||||||
ParseTypeChange({ scope: scope, field_id: 'host_variables' });
|
|
||||||
|
|
||||||
if (scope.removeHostsReload) {
|
|
||||||
scope.removeHostsReload();
|
|
||||||
}
|
|
||||||
scope.removeHostsReload = scope.$on('hostsReload', function() {
|
|
||||||
HostsReload(params);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
|
|
||||||
//$('#form-modal').unbind('hidden');
|
|
||||||
//$('#form-modal').on('hidden', function () { scope.$emit('hostsReload'); });
|
|
||||||
|
|
||||||
generator.reset();
|
|
||||||
master={};
|
|
||||||
|
|
||||||
if (!scope.$$phase) {
|
|
||||||
scope.$digest();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scope.removeHostSaveComplete) {
|
|
||||||
scope.removeHostSaveComplete();
|
|
||||||
}
|
|
||||||
scope.removeHostSaveComplete = scope.$on('HostSaveComplete', function() {
|
|
||||||
Wait('stop');
|
|
||||||
$('#form-modal').modal('hide');
|
|
||||||
|
|
||||||
HostsReload({
|
|
||||||
scope: parent_scope,
|
|
||||||
group_id: parent_scope.selected_group_id,
|
|
||||||
tree_id: parent_scope.selected_tree_id,
|
|
||||||
inventory_id: parent_scope.inventory_id
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save
|
|
||||||
scope.formModalAction = function() {
|
|
||||||
|
|
||||||
Wait('start');
|
|
||||||
|
|
||||||
var fld, data={};
|
|
||||||
scope.formModalActionDisabled = true;
|
|
||||||
data.variables = ToJSON(scope.parseType, scope.variables, true);
|
|
||||||
for (fld in form.fields) {
|
|
||||||
if (fld !== 'variables') {
|
|
||||||
data[fld] = scope[fld];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.inventory = inventory_id;
|
|
||||||
|
|
||||||
Rest.setUrl(defaultUrl);
|
|
||||||
Rest.post(data)
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('HostSaveComplete');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
Wait('stop');
|
|
||||||
scope.formModalActionDisabled = false;
|
|
||||||
ProcessErrors(scope, data, status, form,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cancel
|
|
||||||
scope.formReset = function() {
|
|
||||||
// Defaults
|
|
||||||
generator.reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.cancelModal = function() {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
|
||||||
.factory('HostsEdit', ['$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm',
|
|
||||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetStatus', 'ApplyEllipsis',
|
|
||||||
'ToJSON', 'ParseVariableString', 'CreateDialog', 'TextareaResize',
|
|
||||||
function($rootScope, $location, $log, $stateParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors,
|
|
||||||
GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus, ApplyEllipsis, ToJSON,
|
|
||||||
ParseVariableString, CreateDialog, TextareaResize) {
|
|
||||||
return function(params) {
|
|
||||||
|
|
||||||
var parent_scope = params.host_scope,
|
|
||||||
group_scope = params.group_scope,
|
|
||||||
host_id = params.host_id,
|
|
||||||
inventory_id = params.inventory_id,
|
|
||||||
mode = params.mode, // 'add' or 'edit'
|
|
||||||
selected_group_id = params.selected_group_id,
|
|
||||||
generator = GenerateForm,
|
|
||||||
form = HostForm,
|
|
||||||
defaultUrl,
|
|
||||||
scope = parent_scope.$new(),
|
|
||||||
master = {},
|
|
||||||
relatedSets = {},
|
|
||||||
buttons, url, form_scope;
|
|
||||||
|
|
||||||
form_scope =
|
|
||||||
generator.inject(HostForm, { mode: 'edit', id: 'host-modal-dialog', related: false, scope: scope });
|
|
||||||
generator.reset();
|
|
||||||
|
|
||||||
buttons = [{
|
|
||||||
label: "Cancel",
|
|
||||||
onClick: function() {
|
|
||||||
scope.cancelModal();
|
|
||||||
},
|
|
||||||
icon: "fa-times",
|
|
||||||
"class": "btn btn-default",
|
|
||||||
"id": "host-cancel-button"
|
|
||||||
},{
|
|
||||||
label: "Save",
|
|
||||||
onClick: function() {
|
|
||||||
scope.saveModal();
|
|
||||||
},
|
|
||||||
icon: "fa-check",
|
|
||||||
"class": "btn btn-primary",
|
|
||||||
"id": "host-save-button"
|
|
||||||
}];
|
|
||||||
|
|
||||||
CreateDialog({
|
|
||||||
scope: scope,
|
|
||||||
buttons: buttons,
|
|
||||||
width: 675,
|
|
||||||
height: 750,
|
|
||||||
minWidth: 400,
|
|
||||||
title: 'Host Properties',
|
|
||||||
id: 'host-modal-dialog',
|
|
||||||
closeOnEscape: false,
|
|
||||||
form: form_scope.host_form,
|
|
||||||
onClose: function() {
|
|
||||||
Wait('stop');
|
|
||||||
scope.codeMirror.destroy();
|
|
||||||
$('#host-modal-dialog').empty();
|
|
||||||
},
|
|
||||||
onResizeStop: function() {
|
|
||||||
TextareaResize({
|
|
||||||
scope: scope,
|
|
||||||
textareaId: 'host_variables',
|
|
||||||
modalId: 'host-modal-dialog',
|
|
||||||
formId: 'host_form'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
beforeDestroy: function() {
|
|
||||||
if (scope.codeMirror) {
|
|
||||||
scope.codeMirror.destroy();
|
|
||||||
}
|
|
||||||
$('#host-modal-dialog').empty();
|
|
||||||
},
|
|
||||||
onOpen: function() {
|
|
||||||
$('#host_name').focus();
|
|
||||||
},
|
|
||||||
callback: 'HostEditDialogReady'
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.parseType = 'yaml';
|
|
||||||
|
|
||||||
if (scope.hostVariablesLoadedRemove) {
|
|
||||||
scope.hostVariablesLoadedRemove();
|
|
||||||
}
|
|
||||||
scope.hostVariablesLoadedRemove = scope.$on('hostVariablesLoaded', function() {
|
|
||||||
$('#host-modal-dialog').dialog('open');
|
|
||||||
setTimeout(function() {
|
|
||||||
TextareaResize({
|
|
||||||
scope: scope,
|
|
||||||
textareaId: 'host_variables',
|
|
||||||
modalId: 'host-modal-dialog',
|
|
||||||
formId: 'host_form',
|
|
||||||
parse: true
|
|
||||||
});
|
|
||||||
}, 300);
|
|
||||||
//ParseTypeChange({ scope: scope, field_id: 'host_variables', onReady: callback });
|
|
||||||
});
|
|
||||||
|
|
||||||
Wait('start');
|
|
||||||
|
|
||||||
// Retrieve detail record and prepopulate the form
|
|
||||||
if (mode === 'edit') {
|
|
||||||
defaultUrl = GetBasePath('hosts') + host_id + '/';
|
|
||||||
Rest.setUrl(defaultUrl);
|
|
||||||
Rest.get()
|
|
||||||
.success( function(data) {
|
|
||||||
var set, fld, related;
|
|
||||||
for (fld in form.fields) {
|
|
||||||
if (data[fld]) {
|
|
||||||
scope[fld] = data[fld];
|
|
||||||
master[fld] = scope[fld];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
related = data.related;
|
|
||||||
for (set in form.related) {
|
|
||||||
if (related[set]) {
|
|
||||||
relatedSets[set] = { url: related[set], iterator: form.related[set].iterator };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.variable_url = data.related.variable_data;
|
|
||||||
scope.has_inventory_sources = data.has_inventory_sources;
|
|
||||||
scope.$emit('hostVariablesLoaded');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(parent_scope, data, status, form,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to retrieve host: ' + host_id + '. GET returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (selected_group_id) {
|
|
||||||
// adding hosts to a group
|
|
||||||
url = GetBasePath('groups') + selected_group_id + '/';
|
|
||||||
} else {
|
|
||||||
// adding hosts to the top-level (inventory)
|
|
||||||
url = GetBasePath('inventory') + inventory_id + '/';
|
|
||||||
}
|
|
||||||
// Add mode
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success( function(data) {
|
|
||||||
scope.has_inventory_sources = data.has_inventory_sources;
|
|
||||||
scope.enabled = true;
|
|
||||||
scope.variables = '---';
|
|
||||||
defaultUrl = data.related.hosts;
|
|
||||||
scope.$emit('hostVariablesLoaded');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(parent_scope, data, status, form,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to retrieve group: ' + selected_group_id + '. GET returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scope.removeSaveCompleted) {
|
|
||||||
scope.removeSaveCompleted();
|
|
||||||
}
|
|
||||||
scope.removeSaveCompleted = scope.$on('saveCompleted', function() {
|
|
||||||
try {
|
|
||||||
$('#host-modal-dialog').dialog('close');
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
if (group_scope && group_scope.refreshHosts) {
|
|
||||||
group_scope.refreshHosts();
|
|
||||||
}
|
|
||||||
if (parent_scope.refreshHosts) {
|
|
||||||
parent_scope.refreshHosts();
|
|
||||||
}
|
|
||||||
scope.$destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save changes to the parent
|
|
||||||
scope.saveModal = function() {
|
|
||||||
|
|
||||||
Wait('start');
|
|
||||||
var fld, data={};
|
|
||||||
|
|
||||||
try {
|
|
||||||
data.variables = ToJSON(scope.parseType, scope.variables, true);
|
|
||||||
for (fld in form.fields) {
|
|
||||||
data[fld] = scope[fld];
|
|
||||||
}
|
|
||||||
data.inventory = inventory_id;
|
|
||||||
Rest.setUrl(defaultUrl);
|
|
||||||
if (mode === 'edit') {
|
|
||||||
Rest.put(data)
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('saveCompleted');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, form,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Rest.post(data)
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('saveCompleted');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, form,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to create host. POST returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
// ignore. ToJSON will have already alerted the user
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cancel
|
|
||||||
scope.formReset = function() {
|
|
||||||
generator.reset();
|
|
||||||
for (var fld in master) {
|
|
||||||
scope[fld] = master[fld];
|
|
||||||
}
|
|
||||||
scope.parseType = 'yaml';
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.cancelModal = function() {
|
|
||||||
try {
|
|
||||||
$('#host-modal-dialog').dialog('close');
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
scope.$destroy();
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
|
||||||
.factory('HostsDelete', ['$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'Wait',
|
|
||||||
function($rootScope, $location, $log, $stateParams, Rest, Alert, Prompt, ProcessErrors, GetBasePath, HostsReload, Wait) {
|
|
||||||
return function(params) {
|
|
||||||
// Remove the selected host from the current group by disassociating
|
|
||||||
|
|
||||||
var action_to_take, body,
|
|
||||||
scope = params.parent_scope,
|
|
||||||
host_id = params.host_id,
|
|
||||||
host_name = params.host_name,
|
|
||||||
group,
|
|
||||||
url_list = [];
|
|
||||||
|
|
||||||
if (scope.selected_group_id) {
|
|
||||||
//group = Find({ list: parent_scope.groups, key: 'id', val: parent_scope.selected_group_id });
|
|
||||||
//getChildren(group.id);
|
|
||||||
url_list.push(GetBasePath('groups') + scope.selected_group_id + '/hosts/');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
url_list.push(GetBasePath('inventory') + scope.inventory.id + '/hosts/');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scope.removeHostsReload) {
|
|
||||||
scope.removeHostsReload();
|
|
||||||
}
|
|
||||||
scope.removeHostsReload = scope.$on('hostsReload', function() {
|
|
||||||
$('#prompt-modal').modal('hide');
|
|
||||||
scope.refreshHosts();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#prompt-modal').on('hidden.bs.modal', function(){ Wait('stop'); });
|
|
||||||
|
|
||||||
action_to_take = function() {
|
|
||||||
var count=0, i;
|
|
||||||
|
|
||||||
Wait('start');
|
|
||||||
|
|
||||||
if (scope.removeHostRemoved) {
|
|
||||||
scope.removeHostRemoved();
|
|
||||||
}
|
|
||||||
scope.removeHostRemoved = scope.$on('hostRemoved', function(){
|
|
||||||
count++;
|
|
||||||
if (count === url_list.length) {
|
|
||||||
Wait('start');
|
|
||||||
scope.$emit('hostsReload');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for(i=0; i < url_list.length; i++) {
|
|
||||||
Rest.setUrl(url_list[i]);
|
|
||||||
Rest.post({ id: host_id, disassociate: 1 })
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('hostRemoved');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null,
|
|
||||||
{ hdr: 'Error!', msg: 'Attempt to delete ' + host_name + ' failed. DELETE returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
body = (group) ? '<div class=\"Prompt-bodyQuery\"><p>Are you sure you want to remove the host below from group ' + group.name + '?' +
|
|
||||||
' It will still be part of the inventory and available in All Hosts.</p></div><div class=\"Prompt-bodyTarget\">' + host_name + '</div>' :
|
|
||||||
'<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the host below from the inventory?</div><div class=\"Prompt-bodyTarget\">' + host_name + '</div>';
|
|
||||||
Prompt({
|
|
||||||
hdr: 'Delete Host',
|
|
||||||
body: body,
|
|
||||||
action: action_to_take,
|
|
||||||
actionText: 'DELETE'
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
.factory('HostsCopy', ['$compile', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit',
|
.factory('HostsCopy', ['$compile', 'Rest', 'ProcessErrors', 'CreateDialog', 'GetBasePath', 'Wait', 'generateList', 'GroupList', 'SearchInit',
|
||||||
'PaginateInit',
|
'PaginateInit',
|
||||||
function($compile, Rest, ProcessErrors, CreateDialog, GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit) {
|
function($compile, Rest, ProcessErrors, CreateDialog, GetBasePath, Wait, GenerateList, GroupList, SearchInit, PaginateInit) {
|
||||||
@@ -933,304 +450,4 @@ return function(params) {
|
|||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}])
|
}]);
|
||||||
|
|
||||||
.factory('EditHostGroups', ['$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'GenerateForm', 'Prompt',
|
|
||||||
'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait',
|
|
||||||
function($rootScope, $location, $log, $stateParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath, HostsReload,
|
|
||||||
ParseTypeChange, Wait) {
|
|
||||||
return function(params) {
|
|
||||||
|
|
||||||
var host_id = params.host_id,
|
|
||||||
inventory_id = params.inventory_id,
|
|
||||||
generator = GenerateForm,
|
|
||||||
actions = [],
|
|
||||||
i, html, defaultUrl, scope, postAction;
|
|
||||||
|
|
||||||
html = "<div class=\"row host-groups\">\n";
|
|
||||||
html += "<div class=\"col-lg-6\">\n";
|
|
||||||
html += "<label>Available Groups:</label>\n";
|
|
||||||
html += "<select multiple class=\"form-control\" name=\"available-groups\" ng-model=\"selectedGroups\" ng-change=\"leftChange()\" " +
|
|
||||||
"ng-options=\"avail_group.name for avail_group in available_groups\"></select>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"col-lg-6\">\n";
|
|
||||||
html += "<label>Belongs to Groups:</label>\n";
|
|
||||||
html += "<select multiple class=\"form-control\" name=\"selected-groups\" ng-model=\"assignedGroups\" ng-change=\"rightChange()\" " +
|
|
||||||
"ng-options=\"host_group.name for host_group in host_groups\"></select>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"row host-group-buttons\">\n";
|
|
||||||
html += "<div class=\"col-lg-12\">\n";
|
|
||||||
html += "<button type=\"button\" ng-click=\"moveLeft()\" class=\"btn btn-sm btn-primary left-button\" ng-disabled=\"leftButtonDisabled\">" +
|
|
||||||
"<i class=\"icon-arrow-left\"></i></button>\n";
|
|
||||||
html += "<button type=\"button\" ng-click=\"moveRight()\" class=\"btn btn-sm btn-primary right-button\" ng-disabled=\"rightButtonDisabled\">" +
|
|
||||||
"<i class=\"icon-arrow-right\"></i></button>\n";
|
|
||||||
html += "<p>(move selected groups)</p>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
defaultUrl = GetBasePath('hosts') + host_id + '/';
|
|
||||||
scope = generator.inject(null, { mode: 'edit', modal: true, related: false, html: html });
|
|
||||||
|
|
||||||
for (i=0; i < scope.hosts.length; i++) {
|
|
||||||
if (scope.hosts[i].id === host_id) {
|
|
||||||
scope.host = scope.hosts[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.selectedGroups = null;
|
|
||||||
scope.assignedGroups = null;
|
|
||||||
scope.leftButtonDisabled = true;
|
|
||||||
scope.rightButtonDisabled = true;
|
|
||||||
|
|
||||||
scope.formModalActionLabel = 'Save';
|
|
||||||
//scope.formModalHeader = 'Host Groups';
|
|
||||||
scope.formModalHeader = scope.host.name + ' - <span class=\"subtitle\">Groups</span>';
|
|
||||||
scope.formModalCancelShow = true;
|
|
||||||
scope.formModalActionDisabled = true;
|
|
||||||
|
|
||||||
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
|
|
||||||
|
|
||||||
if (scope.hostGroupChangeRemove) {
|
|
||||||
scope.hostGroupChangeRemove();
|
|
||||||
}
|
|
||||||
scope.hostGroupChangeRemove = scope.$on('hostGroupChange', function() {
|
|
||||||
actions.pop();
|
|
||||||
if (actions.length === 0) {
|
|
||||||
postAction = function() {
|
|
||||||
setTimeout(function() { Wait('stop'); }, 500);
|
|
||||||
};
|
|
||||||
HostsReload({ scope: scope, inventory_id: inventory_id, group_id: scope.group_id , action: postAction });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save changes
|
|
||||||
scope.formModalAction = function() {
|
|
||||||
var i, j, found;
|
|
||||||
|
|
||||||
$('#form-modal').modal('hide');
|
|
||||||
Wait('start');
|
|
||||||
|
|
||||||
// removed host from deleted groups
|
|
||||||
for (i=0; i < scope.original_groups.length; i++) {
|
|
||||||
found = false;
|
|
||||||
for (j=0; j < scope.host_groups.length; j++) {
|
|
||||||
if (scope.original_groups[i].id === scope.host_groups[j].id) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
// group was removed
|
|
||||||
actions.push({ group_id: scope.original_groups[i].id , action: 'delete' });
|
|
||||||
Rest.setUrl(GetBasePath('groups') + scope.original_groups[i].id + '/hosts/');
|
|
||||||
Rest.post({ id: host_id, disassociate: 1 })
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('hostGroupChange');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
scope.$emit('hostGroupChange');
|
|
||||||
ProcessErrors(scope, data, status, null,
|
|
||||||
{ hdr: 'Error!', msg: 'Attempt to remove host from group ' + scope.original_groups[i].name +
|
|
||||||
' failed. POST returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add host to new groups
|
|
||||||
for (i=0; i < scope.host_groups.length; i++) {
|
|
||||||
found = false;
|
|
||||||
for (j=0; j < scope.original_groups.length; j++) {
|
|
||||||
if (scope.original_groups[j].id === scope.host_groups[i].id) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
// group was added
|
|
||||||
actions.push({ group_id: scope.host_groups[i].id , action: 'add' });
|
|
||||||
Rest.setUrl(GetBasePath('groups') + scope.host_groups[i].id + '/hosts/');
|
|
||||||
Rest.post(scope.host)
|
|
||||||
.success( function() {
|
|
||||||
scope.$emit('hostGroupChange');
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
scope.$emit('hostGroupChange');
|
|
||||||
ProcessErrors(scope, data, status, null,
|
|
||||||
{ hdr: 'Error!', msg: 'Attempt to add host to group ' + scope.host_groups[i].name +
|
|
||||||
' failed. POST returned status: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.leftChange = function() {
|
|
||||||
// Select/deselect on available groups list
|
|
||||||
if (scope.selectedGroups !== null && scope.selectedGroups.length > 0) {
|
|
||||||
scope.assignedGroups = null;
|
|
||||||
scope.leftButtonDisabled = true;
|
|
||||||
scope.rightButtonDisabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scope.rightButtonDisabled = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.rightChange = function() {
|
|
||||||
// Select/deselect made on host groups list
|
|
||||||
if (scope.assignedGroups !== null && scope.assignedGroups.length > 0) {
|
|
||||||
scope.selectedGroups = null;
|
|
||||||
scope.leftButtonDisabled = false;
|
|
||||||
scope.rightButtonDisabled = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scope.leftButtonDisabled = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.moveLeft = function() {
|
|
||||||
// Remove selected groups from the list of assigned groups
|
|
||||||
|
|
||||||
var i, j, found, placed;
|
|
||||||
|
|
||||||
for (i=0; i < scope.assignedGroups.length; i++){
|
|
||||||
for (j=0 ; j < scope.host_groups.length; j++) {
|
|
||||||
if (scope.host_groups[j].id === scope.assignedGroups[i].id) {
|
|
||||||
scope.host_groups.splice(j,1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i=0; i < scope.assignedGroups.length; i++){
|
|
||||||
found = false;
|
|
||||||
for (j=0; j < scope.available_groups.length && !found; j++){
|
|
||||||
if (scope.available_groups[j].id === scope.assignedGroups[i].id) {
|
|
||||||
found=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
placed = false;
|
|
||||||
for (j=0; j < scope.available_groups.length && !placed; j++){
|
|
||||||
if (j === 0 && scope.assignedGroups[i].name.toLowerCase() < scope.available_groups[j].name.toLowerCase()) {
|
|
||||||
// prepend to the beginning of the array
|
|
||||||
placed=true;
|
|
||||||
scope.available_groups.unshift(scope.assignedGroups[i]);
|
|
||||||
}
|
|
||||||
else if (j + 1 < scope.available_groups.length) {
|
|
||||||
if (scope.assignedGroups[i].name.toLowerCase() > scope.available_groups[j].name.toLowerCase() &&
|
|
||||||
scope.assignedGroups[i].name.toLowerCase() < scope.available_groups[j + 1].name.toLowerCase() ) {
|
|
||||||
// insert into the middle of the array
|
|
||||||
placed = true;
|
|
||||||
scope.available_groups.splice(j + 1, 0, scope.assignedGroups[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!placed) {
|
|
||||||
// append to the end of the array
|
|
||||||
scope.available_groups.push(scope.assignedGroups[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.assignedGroups = null;
|
|
||||||
scope.leftButtonDisabled = true;
|
|
||||||
scope.rightButtonDisabled = true;
|
|
||||||
scope.formModalActionDisabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.moveRight = function() {
|
|
||||||
// Remove selected groups from list of available groups
|
|
||||||
|
|
||||||
var i, j, found, placed;
|
|
||||||
|
|
||||||
for (i=0; i < scope.selectedGroups.length; i++){
|
|
||||||
for (j=0 ; j < scope.available_groups.length; j++) {
|
|
||||||
if (scope.available_groups[j].id === scope.selectedGroups[i].id) {
|
|
||||||
scope.available_groups.splice(j,1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i=0; i < scope.selectedGroups.length; i++){
|
|
||||||
found = false;
|
|
||||||
for (j=0; j < scope.host_groups.length && !found; j++){
|
|
||||||
if (scope.host_groups[j].id === scope.selectedGroups[i].id) {
|
|
||||||
found=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
placed = false;
|
|
||||||
for (j=0; j < scope.host_groups.length && !placed; j++) {
|
|
||||||
if (j === 0 && scope.selectedGroups[i].name.toLowerCase() < scope.host_groups[j].name.toLowerCase()) {
|
|
||||||
// prepend to the beginning of the array
|
|
||||||
placed=true;
|
|
||||||
scope.host_groups.unshift(scope.selectedGroups[i]);
|
|
||||||
}
|
|
||||||
else if (j + 1 < scope.host_groups.length) {
|
|
||||||
if (scope.selectedGroups[i].name.toLowerCase() > scope.host_groups[j].name.toLowerCase() &&
|
|
||||||
scope.selectedGroups[i].name.toLowerCase() < scope.host_groups[j + 1].name.toLowerCase() ) {
|
|
||||||
// insert into the middle of the array
|
|
||||||
placed = true;
|
|
||||||
scope.host_groups.splice(j + 1, 0, scope.selectedGroups[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!placed) {
|
|
||||||
// append to the end of the array
|
|
||||||
scope.host_groups.push(scope.selectedGroups[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.selectedGroups = null;
|
|
||||||
scope.leftButtonDisabled = true;
|
|
||||||
scope.rightButtonDisabled = true;
|
|
||||||
scope.formModalActionDisabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Load the host's current list of groups
|
|
||||||
scope.host_groups = [];
|
|
||||||
scope.original_groups = [];
|
|
||||||
scope.available_groups = [];
|
|
||||||
Rest.setUrl(scope.host.related.groups + '?order_by=name');
|
|
||||||
Rest.get()
|
|
||||||
.success( function(data) {
|
|
||||||
var i, j, found;
|
|
||||||
for (i=0; i < data.results.length; i++) {
|
|
||||||
scope.host_groups.push({
|
|
||||||
id: data.results[i].id,
|
|
||||||
name: data.results[i].name,
|
|
||||||
description: data.results[i].description
|
|
||||||
});
|
|
||||||
scope.original_groups.push({
|
|
||||||
id: data.results[i].id,
|
|
||||||
name: data.results[i].name,
|
|
||||||
description: data.results[i].description
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (i=0; i < scope.inventory_groups.length; i++) {
|
|
||||||
found = false;
|
|
||||||
for (j=0; j < scope.host_groups.length; j++) {
|
|
||||||
if (scope.inventory_groups[i].id === scope.host_groups[j].id) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
scope.available_groups.push(scope.inventory_groups[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.error( function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null,
|
|
||||||
{ hdr: 'Error!', msg: 'Failed to get current groups for host: ' + host_id + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeHostsReload) {
|
|
||||||
scope.removeHostsReload();
|
|
||||||
}
|
|
||||||
scope.removeHostsReload = scope.$on('hostsReload', function() {
|
|
||||||
HostsReload(params);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!scope.$$phase) {
|
|
||||||
scope.$digest();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
@@ -157,125 +157,6 @@ export default
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
.factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary',
|
|
||||||
function (Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary) {
|
|
||||||
return function (params) {
|
|
||||||
// Display status info in a modal dialog- called from inventory edit page
|
|
||||||
|
|
||||||
var job_id = params.job_id,
|
|
||||||
generator = GenerateForm,
|
|
||||||
form = JobSummary,
|
|
||||||
scope, ww, wh, x, y, maxrows, url, html;
|
|
||||||
|
|
||||||
html = '<div id=\"status-modal-dialog\" title=\"Job ' + job_id + '\">' +
|
|
||||||
'<div id=\"form-container\" style=\"width: 100%;\"></div></div>\n';
|
|
||||||
|
|
||||||
$('#inventory-modal-container').empty().append(html);
|
|
||||||
|
|
||||||
scope = generator.inject(form, { mode: 'edit', id: 'form-container', related: false });
|
|
||||||
|
|
||||||
// Set modal dimensions based on viewport width
|
|
||||||
ww = $(document).width();
|
|
||||||
wh = $('body').height();
|
|
||||||
if (ww > 1199) {
|
|
||||||
// desktop
|
|
||||||
x = 675;
|
|
||||||
y = (750 > wh) ? wh - 20 : 750;
|
|
||||||
maxrows = 20;
|
|
||||||
} else if (ww <= 1199 && ww >= 768) {
|
|
||||||
x = 550;
|
|
||||||
y = (620 > wh) ? wh - 15 : 620;
|
|
||||||
maxrows = 15;
|
|
||||||
} else {
|
|
||||||
x = (ww - 20);
|
|
||||||
y = (500 > wh) ? wh : 500;
|
|
||||||
maxrows = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the modal
|
|
||||||
$('#status-modal-dialog').dialog({
|
|
||||||
buttons: {
|
|
||||||
'OK': function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modal: true,
|
|
||||||
width: x,
|
|
||||||
height: y,
|
|
||||||
autoOpen: false,
|
|
||||||
closeOnEscape: false,
|
|
||||||
create: function () {
|
|
||||||
// fix the close button
|
|
||||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button')
|
|
||||||
.empty().attr({
|
|
||||||
'class': 'close'
|
|
||||||
}).text('x');
|
|
||||||
// fix the OK button
|
|
||||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
|
|
||||||
.attr({
|
|
||||||
'class': 'btn btn-primary'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
resizeStop: function () {
|
|
||||||
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
|
|
||||||
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]'),
|
|
||||||
titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(),
|
|
||||||
buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(),
|
|
||||||
content = dialog.find('#status-modal-dialog');
|
|
||||||
content.width(dialog.width() - 28);
|
|
||||||
content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) });
|
|
||||||
},
|
|
||||||
close: function () {
|
|
||||||
// Destroy on close
|
|
||||||
$('.tooltip').each(function () {
|
|
||||||
// Remove any lingering tooltip <div> elements
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
$('.popover').each(function () {
|
|
||||||
// remove lingering popover <div> 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) {
|
.factory('JobsListUpdate', ['Rest', function(Rest) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
|
|||||||
@@ -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 });
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
<div class="tab-pane" id="inventories">
|
<div class="tab-pane" id="inventories">
|
||||||
<div ui-view></div>
|
<div ui-view=""></div>
|
||||||
<div ng-cloak id="htmlTemplate" class="Panel"></div>
|
<div ng-cloak id="htmlTemplate" class="Panel"></div>
|
||||||
<div id="inventory-edit-modal-dialog"></div>
|
|
||||||
<div ng-include="'/static/partials/logviewer.html'"></div>
|
<div ng-include="'/static/partials/logviewer.html'"></div>
|
||||||
<div id="copy-job-modal" style="display:none">
|
|
||||||
<form name="copy_form" id="copy_form">
|
|
||||||
What would you like to name the copy of job template <b><span id=job_name></span></b>?<br>
|
|
||||||
<input id="new_copy_name" name="new_copy_name" ng-model ="new_copy_name" ng-required="true" class="form-control ng-pristine ng-invalid-required ng-invalid" style="margin-top:10px;">
|
|
||||||
<div class="error survey_error ng-hide" ng-show="copy_form.new_copy_name.$dirty && copy_form.new_copy_name.$error.required">Please enter a name for this job template copy.</div></input>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* @name controllers.function:Adhoc
|
* @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.
|
* @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,
|
$state, CheckPasswords, PromptForPasswords, CreateLaunchDialog, adhocForm,
|
||||||
GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices,
|
GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices,
|
||||||
KindChange, LookUpInit, CredentialList, Empty, Wait) {
|
KindChange, LookUpInit, CredentialList, Empty, Wait) {
|
||||||
@@ -23,7 +23,7 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams,
|
|||||||
this.privateFn = privateFn;
|
this.privateFn = privateFn;
|
||||||
|
|
||||||
var id = $stateParams.inventory_id,
|
var id = $stateParams.inventory_id,
|
||||||
hostPattern = $rootScope.hostPatterns || "all";
|
hostPattern = $stateParams.pattern;
|
||||||
|
|
||||||
// note: put any urls that the controller will use in here!!!!
|
// note: put any urls that the controller will use in here!!!!
|
||||||
privateFn.setAvailableUrls = function() {
|
privateFn.setAvailableUrls = function() {
|
||||||
@@ -102,7 +102,6 @@ function adhocController($q, $scope, $rootScope, $location, $stateParams,
|
|||||||
privateFn.instantiateHostPatterns = function(hostPattern) {
|
privateFn.instantiateHostPatterns = function(hostPattern) {
|
||||||
$scope.limit = hostPattern;
|
$scope.limit = hostPattern;
|
||||||
$scope.providedHostPatterns = $scope.limit;
|
$scope.providedHostPatterns = $scope.limit;
|
||||||
delete $rootScope.hostPatterns;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// call helpers to initialize lookup and select fields through get
|
// 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',
|
'$state', 'CheckPasswords', 'PromptForPasswords', 'CreateLaunchDialog', 'adhocForm',
|
||||||
'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
|
'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
|
||||||
'GetChoices', 'KindChange', 'LookUpInit', 'CredentialList', 'Empty', 'Wait',
|
'GetChoices', 'KindChange', 'LookUpInit', 'CredentialList', 'Empty', 'Wait',
|
||||||
@@ -122,19 +122,18 @@ export default function() {
|
|||||||
dataContainer: "body"
|
dataContainer: "body"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
reset: {
|
|
||||||
ngClick: 'formReset()',
|
|
||||||
ngDisabled: true,
|
|
||||||
label: 'Reset',
|
|
||||||
'class': 'Form-buttonDefault Form-button'
|
|
||||||
},
|
|
||||||
launch: {
|
launch: {
|
||||||
label: 'Save',
|
label: 'Save',
|
||||||
ngClick: 'launchJob()',
|
ngClick: 'launchJob()',
|
||||||
ngDisabled: true,
|
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'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
24
awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js
Normal file
24
awx/ui/client/src/inventories/manage/adhoc/adhoc.route.js
Normal file
@@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
11
awx/ui/client/src/inventories/manage/adhoc/main.js
Normal file
11
awx/ui/client/src/inventories/manage/adhoc/main.js
Normal file
@@ -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);
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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});
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<div class="BreadCrumb InventoryManageBreadCrumbs">
|
||||||
|
<ol class="BreadCrumb-list">
|
||||||
|
<li class="BreadCrumb-item"><a ui-sref="inventories">Inventories</a></li>
|
||||||
|
<li href class="BreadCrumb-item"><a href ng-click="goToInventory()">Manage {{inventory.name}}</a></li>
|
||||||
|
<!-- inside inventoryManage list view (last item is not clickable) -->
|
||||||
|
<span ng-if="isRootState()">
|
||||||
|
<li class="BreadCrumb-item"></li>
|
||||||
|
<li ng-repeat="group in groups | limitTo:(groups.length-1) track by $index" class="BreadCrumb-item">
|
||||||
|
<a href ng-click="goToGroup($index+1)">{{group.name}}</a>
|
||||||
|
</li>
|
||||||
|
<li ng-hide="groups.length == 0" class="BreadCrumb-item"><span>{{groups[groups.length-1].name}}</span></li>
|
||||||
|
</span>
|
||||||
|
<!-- inside inventoryManage.child like add/edit (last item is clickable)-->
|
||||||
|
<span ng-if="!isRootState()">
|
||||||
|
<li class="BreadCrumb-item"></li>
|
||||||
|
<li ng-repeat="group in groups track by $index" class="BreadCrumb-item">
|
||||||
|
<a href ng-click="goToGroup($index)">{{group.name}}</a>
|
||||||
|
</li>
|
||||||
|
<li class="BreadCrumb-item"></li>
|
||||||
|
</span>
|
||||||
|
<div class="InventoryManageBreadCrumb-ncy" ng-if="!licenseMissing" ncy-breadcrumb></div>
|
||||||
|
</ol>
|
||||||
|
<div class="BreadCrumb-menuLink"
|
||||||
|
id="bread_crumb_activity_stream"
|
||||||
|
aw-tool-tip="View Activity Stream"
|
||||||
|
data-placement="left"
|
||||||
|
data-trigger="hover"
|
||||||
|
data-container="body"
|
||||||
|
ng-class="{'BreadCrumb-menuLinkActive' : activityStreamActive}"
|
||||||
|
ng-if="showActivityStreamButton"
|
||||||
|
ng-hide= "licenseMissing"
|
||||||
|
ng-click="openActivityStream()">
|
||||||
|
<i class="BreadCrumb-menuLinkImage icon-activity-stream"
|
||||||
|
alt="Activity Stream">
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<a class="BreadCrumb-menuLink"
|
||||||
|
id="bread_crumb_dashboard"
|
||||||
|
ui-sref="dashboard"
|
||||||
|
aw-tool-tip="View Dashboard"
|
||||||
|
data-placement="left"
|
||||||
|
data-trigger="hover"
|
||||||
|
data-container="body"
|
||||||
|
ng-hide="licenseMissing"
|
||||||
|
ng-if="!showActivityStreamButton">
|
||||||
|
<i class="BreadCrumb-menuLinkImage fa fa-tachometer"
|
||||||
|
alt="Dashboard">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
@@ -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();
|
||||||
|
}];
|
||||||
@@ -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();
|
||||||
|
}];
|
||||||
@@ -4,13 +4,6 @@
|
|||||||
.List-searchRow {
|
.List-searchRow {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-dialog-buttonpane.ui-widget-content {
|
|
||||||
border: none;
|
|
||||||
text-align: right;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Form-header {
|
.Form-header {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
margin-top: -20px;
|
margin-top: -20px;
|
||||||
@@ -22,9 +15,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.copyMove-choices {
|
||||||
.copyMove-directive--copyMoveChoices {
|
|
||||||
float: right;
|
float: right;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
.copyMove-buttons{
|
||||||
|
height: 30px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="Panel copyMove-panel">
|
||||||
|
<div class="Form-header">
|
||||||
|
<div class="Form-title ng-binding">{{item.name}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group copyMove-choices">
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" ng-model="submitMode" value="copy" class="ng-pristine ng-valid ng-touched"> Copy
|
||||||
|
</label>
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" ng-model="submitMode" value="move" class="ng-pristine ng-untouched ng-valid"> Move
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="copyMove-select"></div>
|
||||||
|
<div id="copyMove-list"></div>
|
||||||
|
<div class="copyMove-buttons">
|
||||||
|
<button type="button" class="pull-right btn btn-sm btn-default Form-cancelButton" ng-click="formCancel()">Cancel</button>
|
||||||
|
<button type="button" class="pull-right btn btn-sm Form-saveButton" ng-disabled="!selected" ng-click="formSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -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};
|
||||||
@@ -4,12 +4,11 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
import route from './copy.route';
|
import {copyMoveGroup, copyMoveHost} from './copy-move.route';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('inventory-copy', [])
|
angular.module('manageCopyMove', [])
|
||||||
.run(['$stateExtender', function($stateExtender) {
|
.run(['$stateExtender', function($stateExtender) {
|
||||||
$stateExtender.addState(route.copy);
|
$stateExtender.addState(copyMoveGroup);
|
||||||
$stateExtender.addState(route.copyGroup);
|
$stateExtender.addState(copyMoveHost);
|
||||||
$stateExtender.addState(route.copyHost);
|
|
||||||
}]);
|
}]);
|
||||||
@@ -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
|
|
||||||
];
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div class="Form-header">
|
|
||||||
<div class="Form-title ng-binding">{{vm.name}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group copyMove-directive--copyMoveChoices">
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="vm.copy_choice" value="copy" class="ng-pristine ng-valid ng-touched" name="199"> Copy
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="vm.copy_choice" value="move" class="ng-pristine ng-untouched ng-valid" name="200"> Move
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="copyMove-directive--copyGroupSelect"></div>
|
|
||||||
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
|
|
||||||
<div class="ui-dialog-buttonset">
|
|
||||||
<button type="button" class="btn btn-primary Form-saveButton" id="Inventory-copyGroup--saveButton" ng-disabled="!vm.allowSave" ng-click="vm.performCopy()">
|
|
||||||
Save</button>
|
|
||||||
<button type="button" class="btn btn-default Form-cancelButton" id="Inventory-copyGroup--cancelButton" ng-click="vm.cancel()">
|
|
||||||
Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -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
|
|
||||||
];
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div class="Form-header">
|
|
||||||
<div class="Form-title ng-binding">{{vm.name}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group copyMove-directive--copyMoveChoices">
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="vm.copy_choice" value="copy" class="ng-pristine ng-valid ng-touched" name="199"> Copy
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="vm.copy_choice" value="move" class="ng-pristine ng-untouched ng-valid" name="200"> Move
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="copyMove-directive--copyHostSelect"></div>
|
|
||||||
<div id="copyMove-directive--copyHostPanel"></div>
|
|
||||||
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
|
|
||||||
<div class="ui-dialog-buttonset">
|
|
||||||
<button type="button" class="btn btn-primary Form-saveButton" id="Inventory-copyGroup--saveButton" ng-disabled="!vm.allowSave" ng-click="vm.performCopy()">
|
|
||||||
Save</button>
|
|
||||||
<button type="button" class="btn btn-default Form-cancelButton" id="Inventory-copyGroup--cancelButton" ng-click="vm.cancel()">
|
|
||||||
Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -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
|
|
||||||
];
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<div class="tab-pane" id="Inventory-copyMovePanel">
|
|
||||||
<div ng-cloak id="Inventory-groupCopy--panel" class="Panel">
|
|
||||||
<div class="Form-exitHolder">
|
|
||||||
<button class="Form-exit" ng-click="vm.cancelPanel()">
|
|
||||||
<i class="fa fa-times-circle"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<ui-view></ui-view>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -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();
|
||||||
|
}];
|
||||||
@@ -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();
|
||||||
|
}];
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<div class="tab-pane" id="Inventory-groupManage">
|
<div class="tab-pane" id="Inventory-groupManage">
|
||||||
<div ng-cloak id="Inventory-groupManage--panel" class="Panel">
|
<div ng-cloak id="Inventory-groupManage--panel" class="Panel">
|
||||||
<manage-groups></manage-groups>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -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();
|
||||||
|
}];
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<div id="groups-list" class="Panel"></div>
|
||||||
|
<div class="modal fade GroupDelete" id="group-delete-modal" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content Modal-content">
|
||||||
|
<div class="Modal-header">
|
||||||
|
<div class="Modal-title ng-binding">Delete Group</div>
|
||||||
|
<div class="Modal-exitHolder">
|
||||||
|
<button class="close Modal-exit" data-target="#group-delete-modal" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times-circle"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div ng-show="toDelete.total_groups > 0 || toDelete.total_hosts > 0">
|
||||||
|
<div>
|
||||||
|
<p class="Prompt-bodyQuery">Deleting group <em>{{ toDelete.name }}</em>.
|
||||||
|
<span ng-show="toDelete.total_groups > 0 && toDelete.total_hosts > 0"> This group contains {{ toDelete.total_groups }} groups and {{ toDelete.total_hosts }} hosts. </span>
|
||||||
|
<span ng-show="toDelete.total_groups == 0 && toDelete.total_hosts > 0"> This group contains {{ toDelete.total_hosts }} hosts. </span>
|
||||||
|
<span ng-show="groupsCopunt > 0 && toDelete.total_hosts == 0"> This group contains {{ toDelete.total_groups }} groups. </span>
|
||||||
|
Delete or promote the group's children?</p>
|
||||||
|
<div style="margin: 15px auto;">
|
||||||
|
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups > 0 && toDelete.total_hosts > 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="promote"> Promote groups and hosts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups > 0 && toDelete.total_hosts > 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="delete"> Delete groups and hosts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups > 0 && toDelete.total_hosts == 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="promote"> Promote groups
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups > 0 && toDelete.total_hosts == 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="delete"> Delete groups
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups == 0 && toDelete.total_hosts > 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="promote"> Promote hosts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio" ng-show="toDelete.total_groups == 0 && toDelete.total_hosts > 0">
|
||||||
|
<label>
|
||||||
|
<input type="radio" ng-model="deleteOption" value="delete"> Delete hosts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div ng-show="toDelete.total_groups == 0 && toDelete.total_hosts == 0">
|
||||||
|
<div class="Prompt-bodyQuery">Are you sure you want to permanently delete the group below from the inventory?</div>
|
||||||
|
<div class="Prompt-bodyTarget">{{ toDelete.name }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="Modal-footer">
|
||||||
|
<div class="GroupDelete-help--container">
|
||||||
|
<a href="" id="awp-promote" href="" aw-pop-over="<dl><dt>Delete</dt><dd>Deletes groups and hosts associated with the group being deleted. If a group or host is associated with other groups, it will still exist within those groups. Otherwise, the associated groups and hosts will no longer appear in the inventory.</dd>\n<dt style='margin-top: 5px;'>Promote</dt><dd>Groups and hosts associated with the group being removed will be promoted root level. Note: groups already associated with other groups cannot be promoted.</dd></dl>\n" aw-tool-tip="Click for help" data-placement="right" data-container="body" data-title="Help" class="help-link"><i class="fa fa-question-circle"></i> Click for help</a>
|
||||||
|
</div>
|
||||||
|
<a href="" ng-class="promptActionBtnClass" ng-click="confirmDelete()" id="prompt_action_btn" class="btn Modal-footerButton Modal-errorButton">DELETE</a>
|
||||||
|
<a href="#" data-target="#group-delete-modal" data-dismiss="modal" id="prompt_cancel_btn" class="btn Modal-defaultButton Modal-footerButton">CANCEL</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
awx/ui/client/src/inventories/manage/groups/groups.route.js
Normal file
51
awx/ui/client/src/inventories/manage/groups/groups.route.js
Normal file
@@ -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};
|
||||||
113
awx/ui/client/src/inventories/manage/groups/groups.service.js
Normal file
113
awx/ui/client/src/inventories/manage/groups/groups.service.js
Normal file
@@ -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'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
14
awx/ui/client/src/inventories/manage/groups/main.js
Normal file
14
awx/ui/client/src/inventories/manage/groups/main.js
Normal file
@@ -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);
|
||||||
|
}]);
|
||||||
@@ -5,16 +5,16 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService',
|
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService',
|
||||||
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService){
|
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService){
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
form = HostForm;
|
form = HostForm;
|
||||||
$scope.parseType = 'yaml';
|
$scope.parseType = 'yaml';
|
||||||
$scope.extraVars = '---';
|
$scope.extraVars = '---';
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^', null, {reload: true});
|
$state.go('^');
|
||||||
};
|
};
|
||||||
$scope.toggleEnabled = function(){
|
$scope.toggleHostEnabled = function(){
|
||||||
$scope.host.enabled = !$scope.host.enabled;
|
$scope.host.enabled = !$scope.host.enabled;
|
||||||
};
|
};
|
||||||
$scope.formSave = function(){
|
$scope.formSave = function(){
|
||||||
@@ -25,8 +25,16 @@
|
|||||||
enabled: $scope.host.enabled,
|
enabled: $scope.host.enabled,
|
||||||
inventory: $stateParams.inventory_id
|
inventory: $stateParams.inventory_id
|
||||||
};
|
};
|
||||||
ManageHostsService.post(params).then(function(){
|
HostManageService.post(params).then(function(res){
|
||||||
$state.go('^', null, {reload: true});
|
// 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(){
|
var init = function(){
|
||||||
@@ -5,13 +5,13 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'ManageHostsService', 'host',
|
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'host',
|
||||||
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, ManageHostsService, host){
|
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
form = HostForm;
|
form = HostForm;
|
||||||
$scope.parseType = 'yaml';
|
$scope.parseType = 'yaml';
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^', null, {reload: true});
|
$state.go('^');
|
||||||
};
|
};
|
||||||
$scope.toggleHostEnabled = function(){
|
$scope.toggleHostEnabled = function(){
|
||||||
$scope.host.enabled = !$scope.host.enabled;
|
$scope.host.enabled = !$scope.host.enabled;
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
description: $scope.description,
|
description: $scope.description,
|
||||||
enabled: $scope.host.enabled
|
enabled: $scope.host.enabled
|
||||||
};
|
};
|
||||||
ManageHostsService.put(host).then(function(){
|
HostManageService.put(host).then(function(){
|
||||||
$state.go('^', null, {reload: true});
|
$state.go('^', null, {reload: true});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -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 = '<div class=\"Prompt-bodyQuery\">Are you sure you want to permanently delete the host below from the inventory?</div><div class=\"Prompt-bodyTarget\">' + name + '</div>';
|
||||||
|
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();
|
||||||
|
}];
|
||||||
50
awx/ui/client/src/inventories/manage/hosts/hosts.route.js
Normal file
50
awx/ui/client/src/inventories/manage/hosts/hosts.route.js
Normal file
@@ -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};
|
||||||
84
awx/ui/client/src/inventories/manage/hosts/hosts.service.js
Normal file
84
awx/ui/client/src/inventories/manage/hosts/hosts.service.js
Normal file
@@ -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'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -4,13 +4,11 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
import {ManageHostsAdd, ManageHostsEdit} from './manage-hosts.route';
|
import {ManageHostsAdd, ManageHostsEdit} from './hosts.route';
|
||||||
import service from './manage-hosts.service';
|
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('manageHosts', [])
|
angular.module('manageHosts', [])
|
||||||
.service('ManageHostsService', service)
|
.run(['$stateExtender', '$state', function($stateExtender, $state){
|
||||||
.run(['$stateExtender', function($stateExtender){
|
|
||||||
$stateExtender.addState(ManageHostsAdd);
|
$stateExtender.addState(ManageHostsAdd);
|
||||||
$stateExtender.addState(ManageHostsEdit);
|
$stateExtender.addState(ManageHostsEdit);
|
||||||
}]);
|
}]);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.InventoryManage-container{
|
||||||
|
margin-top: -40px;
|
||||||
|
}
|
||||||
@@ -3,532 +3,18 @@
|
|||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
export default
|
||||||
/**
|
['$scope', '$state', function($scope, $state){
|
||||||
* @ngdoc function
|
$scope.groupsSelected = false;
|
||||||
* @name controllers.function:Inventories
|
$scope.hostsSelected = false;
|
||||||
* @description This controller's for the Inventory page
|
$scope.hostsSelectedItems = [];
|
||||||
*/
|
$scope.groupsSelectedItems = [];
|
||||||
|
$scope.setAdhocPattern = function(){
|
||||||
function InventoriesManage($log, $scope, $rootScope, $location,
|
var pattern = _($scope.groupsSelectedItems)
|
||||||
$state, $compile, generateList, ClearScope, Empty, Wait, Rest, Alert,
|
.concat($scope.hostsSelectedItems)
|
||||||
GetBasePath, ProcessErrors, InventoryGroups,
|
.map(function(item){
|
||||||
InjectHosts, Find, HostsReload, SearchInit, PaginateInit, GetSyncStatusMsg,
|
return item.name;
|
||||||
GetHostsStatusMsg, GroupsEdit, InventoryUpdate, GroupsCancelUpdate,
|
}).value().join(':');
|
||||||
ViewUpdateStatus, GroupsDelete, Store, HostsEdit, HostsDelete,
|
$state.go('inventoryManage.adhoc', {pattern: pattern});
|
||||||
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 <em>' +
|
|
||||||
group.name + '</em> Click the <i class="fa fa-refresh"></i> 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
|
|
||||||
];
|
|
||||||
@@ -1,152 +1,10 @@
|
|||||||
<div class="tab-pane" id="inventory_edit">
|
<div class="tab-pane InventoryManage-container" id="inventory_edit">
|
||||||
<div ui-view></div>
|
<div ui-view="form"></div>
|
||||||
<div ng-cloak id="htmlTemplate">
|
<div ng-cloak id="htmlTemplate">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="groups-container" class="col-lg-6">
|
<div ui-view="groupsList" class="col-lg-6"></div>
|
||||||
<div id="group-list-container" class="Panel"></div>
|
<div ui-view="hostsList" class="col-lg-6"></div>
|
||||||
</div>
|
|
||||||
<div id="hosts-container" class="col-lg-6">
|
|
||||||
<div id="host-list-container" class="Panel"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="group-copy-dialog" style="display: none;">
|
|
||||||
<div id="copy-group-radio-container" class="well">
|
|
||||||
<div class="title"><span class="highlight">1.</span> Copy or move <span ng-bind="name"></span>?</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="copy_choice" value="copy"> Copy
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="copy_choice" value="move"> Move
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="copy-group-target-container" class="well">
|
|
||||||
<div class="title" ng-show="offer_root_group"><span class="highlight">2.</span> Select a target group below, OR choose the inventory root:
|
|
||||||
<div class="form-group">
|
|
||||||
<label><input type="checkbox" ng-model="use_root_group" ng-change="toggleUseRootGroup()"> Use the inventory root</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="title" ng-show="!offer_root_group"><span class="highlight">2.</span> Select a target group:</div>
|
|
||||||
<div id="copy-select-container" ng-show="!use_root_group"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="host-copy-dialog" style="display: none;">
|
|
||||||
<div id="copy-group-radio-container" class="well">
|
|
||||||
<div class="title"><span class="highlight">1.</span> Copy or move <span ng-bind="name"></span>?</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="copy_choice" value="copy"> Copy
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" ng-model="copy_choice" value="move"> Move
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="copy-group-target-container" class="well">
|
|
||||||
<div class="title"><span class="highlight">2.</span> Select a target group:</div>
|
|
||||||
<div id="copy-host-select-container"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="group-modal-dialog" style="display: none;">
|
|
||||||
<ul id="group_tabs" class="nav nav-tabs">
|
|
||||||
<li class="active"><a id="properties_link" ng-click="toggleTab($event, 'properties_link', 'group_tabs')"
|
|
||||||
href="#properties-tab" data-toggle="tab">Properties</a></li>
|
|
||||||
<li ng-show="showSourceTab"><a id="source_link" ng-click="toggleTab($event, 'source_link', 'group_tabs')"
|
|
||||||
href="#sources-tab" data-toggle="tab">Source</a></li>
|
|
||||||
<li ng-show="showSchedulesTab"><a id="schedules_link" ng-click="toggleTab($event, 'schedules_link', 'group_tabs')"
|
|
||||||
href="#schedules-tab" data-toggle="tab">Schedule</a></li>
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="tab-pane active" id="properties-tab"></div>
|
|
||||||
<div class="tab-pane" id="sources-tab"></div>
|
|
||||||
<div class="tab-pane" id="schedules-tab">
|
|
||||||
<div id="schedules-overlay"></div>
|
|
||||||
<div id="schedules-list"></div>
|
|
||||||
<div id="schedules-form-container">
|
|
||||||
<div id="schedules-title">
|
|
||||||
<h4 ng-bind="schedulesTitle"></h4>
|
|
||||||
<button type="button" class="close pull-right" ng-click="cancelScheduleForm()">x</button>
|
|
||||||
</div>
|
|
||||||
<div id="schedules-form-container-body">
|
|
||||||
<div id="schedules-form"></div>
|
|
||||||
<div id="schedules-detail"></div>
|
|
||||||
</div>
|
|
||||||
<div id="schedules-buttons">
|
|
||||||
<a id="schedules-flip-link" ng-show="formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-search-plus"></i> View Details</a>
|
|
||||||
<a id="schedules-flip-link" ng-show="!formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-arrow-circle-left"></i> Back to options</a>
|
|
||||||
<button type="button" class="btn btn-default btn-sm" id="reset-button" ng-click="cancelScheduleForm()"><i class="fa fa-times"></i> Cancel</button>
|
|
||||||
<button type="button" class="btn btn-primary btn-sm" id="save-button" ng-click="saveScheduleForm()"><i class="fa fa-check"></i> Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div>
|
|
||||||
|
|
||||||
<div id="group-delete-dialog" style="display: none;" class="dialog-content">
|
|
||||||
<div ng-show="groupsCount > 0 || hostsCount > 0">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<p>Deleting group <em>{{ group_name }}</em>.
|
|
||||||
<span ng-show="groupsCount > 0 && hostsCount > 0"> This group contains {{ groupsCount }} groups and {{ hostsCount }} hosts. </span>
|
|
||||||
<span ng-show="groupsCount == 0 && hostsCount > 0"> This group contains {{ hostsCount }} hosts. </span>
|
|
||||||
<span ng-show="groupsCopunt > 0 && hostsCount == 0"> This group contains {{ groupsCount }} groups. </span>
|
|
||||||
Delete or promote the group's children?</p>
|
|
||||||
<div style="width: 50%; margin: 15px auto;">
|
|
||||||
|
|
||||||
<div class="radio" ng-show="groupsCount > 0 && hostsCount > 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option1" value="preserve-all"> Promote groups and hosts
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="radio" ng-show="groupsCount > 0 && hostsCount > 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option1" value="delete-all"> Delete groups and hosts
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="radio" ng-show="groupsCount > 0 && hostsCount == 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option2" value="preserve-all"> Promote groups
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="radio" ng-show="groupsCount > 0 && hostsCount == 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option2" value="delete-all"> Delete groups
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="radio" ng-show="groupsCount == 0 && hostsCount > 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option3" value="preserve-all"> Promote hosts
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="radio" ng-show="groupsCount == 0 && hostsCount > 0">
|
|
||||||
<label>
|
|
||||||
<input type="radio" ng-model="deleteOption" name="delete_option3" value="delete-all"> Delete hosts
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="help-container" style="text-align:right;">
|
|
||||||
<a href="" id="awp-promote" href="" aw-pop-over="{{ helpText }}" aw-tool-tip="Click for help" aw-pop-over-watch="helpText" data-placement="top" data-container="body" data-title="Help" class="help-link"><i class="fa fa-question-circle"></i> click for help</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div ng-show="groupsCount == 0 && hostsCount == 0">
|
|
||||||
<div class="alert alert-info">Delete group <em>{{ group_name }}</em>?</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="inventory-edit-modal-dialog"></div>
|
|
||||||
|
|
||||||
<div ng-include="'/static/partials/logviewer.html'"></div>
|
<div ng-include="'/static/partials/logviewer.html'"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,18 +6,71 @@
|
|||||||
|
|
||||||
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
||||||
import InventoriesManage from './inventory-manage.controller';
|
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 {
|
export default {
|
||||||
name: 'inventoryManage',
|
name: 'inventoryManage',
|
||||||
url: '/inventories/:inventory_id/manage?groups',
|
url: '/inventories/:inventory_id/manage?{group:int}{failed}',
|
||||||
templateUrl: templateUrl('inventories/manage/inventory-manage'),
|
|
||||||
controller: InventoriesManage,
|
|
||||||
data: {
|
data: {
|
||||||
activityStream: true,
|
activityStream: true,
|
||||||
activityStreamTarget: 'inventory',
|
activityStreamTarget: 'inventory',
|
||||||
activityStreamId: 'inventory_id'
|
activityStreamId: 'inventory_id'
|
||||||
},
|
},
|
||||||
|
params:{
|
||||||
|
group:{
|
||||||
|
array: true
|
||||||
|
},
|
||||||
|
failed:{
|
||||||
|
value: 'false',
|
||||||
|
squash: true
|
||||||
|
}
|
||||||
|
},
|
||||||
ncyBreadcrumb: {
|
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: '<div id="hosts-list" class="Panel"></div>',
|
||||||
|
controller: HostsListController
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -1,21 +1,28 @@
|
|||||||
/*************************************************
|
/*************************************************
|
||||||
* Copyright (c) 2015 Ansible, Inc.
|
* Copyright (c) 2016 Ansible, Inc.
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
import route from './inventory-manage.route';
|
import route from './inventory-manage.route';
|
||||||
|
import InventoryManageService from './inventory-manage.service';
|
||||||
import manageHosts from './manage-hosts/main';
|
import HostManageService from './hosts/hosts.service';
|
||||||
import manageGroups from './manage-groups/main';
|
import GroupManageService from './groups/groups.service';
|
||||||
import copy from './copy/main';
|
import hosts from './hosts/main';
|
||||||
|
import groups from './groups/main';
|
||||||
|
import adhoc from './adhoc/main';
|
||||||
|
import copyMove from './copy-move/main';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('inventoryManage', [
|
angular.module('inventoryManage', [
|
||||||
manageHosts.name,
|
hosts.name,
|
||||||
manageGroups.name,
|
groups.name,
|
||||||
copy.name,
|
copyMove.name,
|
||||||
|
adhoc.name
|
||||||
])
|
])
|
||||||
|
.service('InventoryManageService', InventoryManageService)
|
||||||
|
.service('HostManageService', HostManageService)
|
||||||
|
.service('GroupManageService', GroupManageService)
|
||||||
.run(['$stateExtender', function($stateExtender) {
|
.run(['$stateExtender', function($stateExtender) {
|
||||||
$stateExtender.addState(route);
|
$stateExtender.addState(route);
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@@ -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 <em>' +
|
|
||||||
$filter('sanitize')($scope.summary_fields.group.name) + '</em>. 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
|
|
||||||
];
|
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div id="group-manage-panel">
|
|
||||||
<div id="properties-tab"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -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);
|
|
||||||
}]);
|
|
||||||
@@ -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'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -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};
|
|
||||||
@@ -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 });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
@@ -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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,22 +11,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default
|
export default
|
||||||
[ '$location', '$rootScope', '$filter', '$scope', '$compile',
|
[ '$location', '$rootScope', '$filter', '$scope', '$compile', '$stateParams', '$log', 'ClearScope',
|
||||||
'$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait',
|
'GetBasePath', 'Wait', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed', 'JobIsFinished',
|
||||||
'ProcessErrors', 'SelectPlay', 'SelectTask', 'GetElapsed',
|
'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun', 'LoadPlays', 'LoadTasks',
|
||||||
'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'InitiatePlaybookRun',
|
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'EditSchedule',
|
||||||
'LoadPlays', 'LoadTasks', 'HostsEdit',
|
'ParseTypeChange', 'JobDetailService',
|
||||||
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
|
|
||||||
'EditSchedule', 'ParseTypeChange', 'JobDetailService',
|
|
||||||
function(
|
function(
|
||||||
$location, $rootScope, $filter, $scope, $compile, $stateParams,
|
$location, $rootScope, $filter, $scope, $compile, $stateParams, $log, ClearScope,
|
||||||
$log, ClearScope, GetBasePath, Wait, ProcessErrors,
|
GetBasePath, Wait, ProcessErrors, SelectPlay, SelectTask, GetElapsed, JobIsFinished,
|
||||||
SelectPlay, SelectTask, GetElapsed,
|
SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, InitiatePlaybookRun, LoadPlays, LoadTasks,
|
||||||
JobIsFinished,
|
ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule,
|
||||||
SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob,
|
ParseTypeChange, JobDetailService
|
||||||
InitiatePlaybookRun, LoadPlays, LoadTasks,
|
|
||||||
HostsEdit, ParseVariableString, GetChoices, fieldChoices,
|
|
||||||
fieldLabels, EditSchedule, ParseTypeChange, JobDetailService
|
|
||||||
) {
|
) {
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
|||||||
@@ -9,41 +9,17 @@
|
|||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('GroupListDefinition', [])
|
angular.module('GroupListDefinition', [])
|
||||||
.value('GroupList', {
|
.value('CopyMoveGroupList', {
|
||||||
|
|
||||||
name: 'copy_groups',
|
name: 'groups',
|
||||||
iterator: 'copy_group',
|
iterator: 'group',
|
||||||
selectTitle: 'Copy Groups',
|
selectTitle: 'Copy Groups',
|
||||||
editTitle: 'Groups',
|
|
||||||
index: false,
|
index: false,
|
||||||
well: false,
|
well: false,
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
name: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Name'
|
label: 'Target Group 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'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default
|
|||||||
|
|
||||||
edit: {
|
edit: {
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
ngClick: 'editInventory(inventory.id)', //'editInventoryProperties(inventory.id)',
|
ngClick: 'editInventory(inventory.id)',
|
||||||
awToolTip: 'Edit inventory',
|
awToolTip: 'Edit inventory',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,18 +21,47 @@ export default
|
|||||||
multiSelect: true,
|
multiSelect: true,
|
||||||
|
|
||||||
fields: {
|
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: {
|
name: {
|
||||||
label: 'Groups',
|
label: 'Groups',
|
||||||
key: true,
|
key: true,
|
||||||
ngClick: "groupSelect(group.id)",
|
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: {
|
total_groups: {
|
||||||
nosort: true,
|
nosort: true,
|
||||||
label: '',
|
label: '',
|
||||||
type: 'badgeCount',
|
type: 'badgeCount',
|
||||||
ngHide: 'group.total_groups == 0',
|
ngHide: 'group.total_groups == 0',
|
||||||
|
noLink: true,
|
||||||
|
awToolTip: "{{group.name}} contains {{group.total_groups}} {{group.total_groups === 1 ? 'child' : 'children'}}",
|
||||||
|
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
label: 'Source',
|
label: 'Source',
|
||||||
@@ -100,8 +129,9 @@ export default
|
|||||||
},
|
},
|
||||||
launch: {
|
launch: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngShow: 'inventory.can_run_ad_hoc_commands',
|
// $scope.$parent is governed by InventoryManageController,
|
||||||
ngClick: 'populateAdhocForm()',
|
ngShow: '$parent.groupsSelected || $parent.hostsSelected',
|
||||||
|
ngClick: '$parent.setAdhocPattern()',
|
||||||
awToolTip: "Run a command on the selected inventory",
|
awToolTip: "Run a command on the selected inventory",
|
||||||
actionClass: 'btn List-buttonDefault',
|
actionClass: 'btn List-buttonDefault',
|
||||||
buttonContent: 'RUN COMMANDS'
|
buttonContent: 'RUN COMMANDS'
|
||||||
@@ -116,7 +146,7 @@ export default
|
|||||||
ngClick: "createGroup()",
|
ngClick: "createGroup()",
|
||||||
awToolTip: "Create a new group",
|
awToolTip: "Create a new group",
|
||||||
actionClass: 'btn List-buttonSubmit',
|
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',
|
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: {
|
group_update: {
|
||||||
//label: 'Sync',
|
//label: 'Sync',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'updateGroup(group.id)',
|
ngClick: 'updateGroup(group)',
|
||||||
awToolTip: "{{ group.launch_tooltip }}",
|
awToolTip: "{{ group.launch_tooltip }}",
|
||||||
dataTipWatch: "group.launch_tooltip",
|
dataTipWatch: "group.launch_tooltip",
|
||||||
ngShow: "group.status !== 'running' && group.status " +
|
ngShow: "group.status !== 'running' && group.status " +
|
||||||
"!== 'pending' && group.status !== 'updating'",
|
"!== 'pending' && group.status !== 'updating'",
|
||||||
ngClass: "group.launch_class",
|
ngClass: "group.launch_class",
|
||||||
dataPlacement: "top"
|
dataPlacement: "top",
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
//label: 'Cancel',
|
//label: 'Cancel',
|
||||||
@@ -159,11 +173,12 @@ export default
|
|||||||
'class': 'red-txt',
|
'class': 'red-txt',
|
||||||
ngShow: "group.status == 'running' || group.status == 'pending' " +
|
ngShow: "group.status == 'running' || group.status == 'pending' " +
|
||||||
"|| group.status == 'updating'",
|
"|| group.status == 'updating'",
|
||||||
dataPlacement: "top"
|
dataPlacement: "top",
|
||||||
|
iconClass: "fa fa-minus-circle"
|
||||||
},
|
},
|
||||||
copy: {
|
copy: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "copyGroup(group.id)",
|
ngClick: "copyMoveGroup(group.id)",
|
||||||
awToolTip: 'Copy or move group',
|
awToolTip: 'Copy or move group',
|
||||||
ngShow: "group.id > 0",
|
ngShow: "group.id > 0",
|
||||||
dataPlacement: "top"
|
dataPlacement: "top"
|
||||||
@@ -186,7 +201,7 @@ export default
|
|||||||
"delete": {
|
"delete": {
|
||||||
//label: 'Delete',
|
//label: 'Delete',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "deleteGroup(group.id)",
|
ngClick: "deleteGroup(group)",
|
||||||
awToolTip: 'Delete group',
|
awToolTip: 'Delete group',
|
||||||
dataPlacement: "top"
|
dataPlacement: "top"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,23 @@ export default
|
|||||||
multiSelect: true,
|
multiSelect: true,
|
||||||
|
|
||||||
fields: {
|
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: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Hosts',
|
label: 'Hosts',
|
||||||
@@ -29,7 +46,8 @@ export default
|
|||||||
ngClass: "{ 'host-disabled-label': !host.enabled }",
|
ngClass: "{ 'host-disabled-label': !host.enabled }",
|
||||||
columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7',
|
columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7',
|
||||||
dataHostId: "{{ host.id }}",
|
dataHostId: "{{ host.id }}",
|
||||||
dataType: "host"
|
dataType: "host",
|
||||||
|
class: 'InventoryManage-breakWord'
|
||||||
},
|
},
|
||||||
enabled: {
|
enabled: {
|
||||||
label: 'Disabled?',
|
label: 'Disabled?',
|
||||||
@@ -50,20 +68,9 @@ export default
|
|||||||
fieldActions: {
|
fieldActions: {
|
||||||
|
|
||||||
columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right',
|
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: {
|
copy: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "copyHost(host.id)",
|
ngClick: "copyMoveHost(host.id)",
|
||||||
awToolTip: 'Copy or move host to another group',
|
awToolTip: 'Copy or move host to another group',
|
||||||
dataPlacement: "top"
|
dataPlacement: "top"
|
||||||
},
|
},
|
||||||
@@ -85,15 +92,15 @@ export default
|
|||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
system_tracking: {
|
system_tracking: {
|
||||||
label: 'System Tracking',
|
buttonContent: 'System Tracking',
|
||||||
ngClick: 'systemTracking()', //'editInventoryProperties(inventory.id)',
|
ngClick: 'systemTracking()',
|
||||||
awToolTip: "{{ systemTrackingTooltip }}",
|
awToolTip: "{{ systemTrackingTooltip }}",
|
||||||
dataTipWatch: "systemTrackingTooltip",
|
dataTipWatch: "systemTrackingTooltip",
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
awFeature: 'system_tracking',
|
awFeature: 'system_tracking',
|
||||||
ngDisabled: 'systemTrackingDisabled',
|
|
||||||
actionClass: 'btn List-buttonDefault system-tracking',
|
actionClass: 'btn List-buttonDefault system-tracking',
|
||||||
ngShow: 'hostsSelected'
|
ngShow: 'hostsSelected',
|
||||||
|
ngDisabled: 'systemTrackingDisabled'
|
||||||
},
|
},
|
||||||
refresh: {
|
refresh: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
@@ -108,7 +115,7 @@ export default
|
|||||||
ngClick: "createHost()",
|
ngClick: "createHost()",
|
||||||
awToolTip: "Create a new host",
|
awToolTip: "Create a new host",
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD HOST'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ export default
|
|||||||
scope.isCurrentState = function(name){
|
scope.isCurrentState = function(name){
|
||||||
return $state.current.name === name;
|
return $state.current.name === name;
|
||||||
};
|
};
|
||||||
|
scope.includesCurrentState = function(name){
|
||||||
|
return $state.includes(name);
|
||||||
|
};
|
||||||
|
|
||||||
// set up the user tooltip
|
// set up the user tooltip
|
||||||
$rootScope.$on('current_user', function(user) {
|
$rootScope.$on('current_user', function(user) {
|
||||||
|
|||||||
@@ -52,19 +52,26 @@ export default
|
|||||||
controller: 'schedulerEditController'
|
controller: 'schedulerEditController'
|
||||||
});
|
});
|
||||||
$stateExtender.addState({
|
$stateExtender.addState({
|
||||||
name: 'inventoryManageSchedules',
|
name: 'inventoryManage.schedules',
|
||||||
route: '/inventory/:inventory_id/manage/:id/schedules',
|
route: '/schedules/:id',
|
||||||
templateUrl: templateUrl("scheduler/scheduler"),
|
views: {
|
||||||
controller: 'schedulerController'
|
'form@inventoryManage': {
|
||||||
|
templateUrl: templateUrl("scheduler/scheduler"),
|
||||||
|
controller: 'schedulerController'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ncyBreadcrumb: {
|
||||||
|
label: "{{name}} SCHEDULES"
|
||||||
|
},
|
||||||
});
|
});
|
||||||
$stateExtender.addState({
|
$stateExtender.addState({
|
||||||
name: 'inventoryManageSchedules.add',
|
name: 'inventoryManage.schedules.add',
|
||||||
route: '/add',
|
route: '/add',
|
||||||
templateUrl: templateUrl("scheduler/schedulerForm"),
|
templateUrl: templateUrl("scheduler/schedulerForm"),
|
||||||
controller: 'schedulerAddController'
|
controller: 'schedulerAddController'
|
||||||
});
|
});
|
||||||
$stateExtender.addState({
|
$stateExtender.addState({
|
||||||
name: 'inventoryManageSchedules.edit',
|
name: 'inventoryManage.schedules.edit',
|
||||||
route: '/:schedule_id',
|
route: '/:schedule_id',
|
||||||
templateUrl: templateUrl("scheduler/schedulerForm"),
|
templateUrl: templateUrl("scheduler/schedulerForm"),
|
||||||
controller: 'schedulerEditController'
|
controller: 'schedulerEditController'
|
||||||
|
|||||||
@@ -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 += "<div id=\"copy-prompt-modal\" class=\"modal fade\">\n";
|
|
||||||
html += "<div class=\"modal-dialog\">\n";
|
|
||||||
html += "<div class=\"modal-content\">\n";
|
|
||||||
html += "<div class=\"modal-header\">\n";
|
|
||||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
|
||||||
"data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n";
|
|
||||||
|
|
||||||
if (target.id === 1 || inbound.parent === 0) {
|
|
||||||
// We're moving the group to the top level, or we're moving a top level group down
|
|
||||||
html += "<h3>Move Group</h3>\n";
|
|
||||||
} else {
|
|
||||||
html += "<h3>Copy or Move?</h3>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-body\">\n";
|
|
||||||
|
|
||||||
if (target.id === 1) {
|
|
||||||
html += "<div class=\"alert alert-info\">Are you sure you want to move group " + inbound.name + " to the top level?</div>";
|
|
||||||
} else if (inbound.parent === 0) {
|
|
||||||
html += "<div class=\"alert alert-info\">Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " +
|
|
||||||
target.name + "?</div>";
|
|
||||||
} else {
|
|
||||||
html += "<div class=\"text-center\">\n";
|
|
||||||
html += "<p>Would you like to copy or move group <em>" + inbound.name + "</em> to group <em>" + target.name + "</em>?</p>\n";
|
|
||||||
html += "<div style=\"margin-top: 30px;\">\n";
|
|
||||||
html += "<a href=\"\" ng-click=\"moveGroup()\" class=\"btn btn-primary\" style=\"margin-right: 15px;\"><i class=\"fa fa-cut\"></i> Move</a>\n";
|
|
||||||
html += "<a href=\"\" ng-click=\"copyGroup()\" class=\"btn btn-primary\"><i class=\"fa fa-copy\"></i> Copy</a>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-footer\">\n";
|
|
||||||
html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">Cancel</a>\n";
|
|
||||||
|
|
||||||
if (target.id === 1 || inbound.parent === 0) {
|
|
||||||
// We're moving the group to the top level, or we're moving a top level group down
|
|
||||||
html += "<a href=\"\" data-target=\"#prompt-modal\" ng-click=\"moveGroup()\" class=\"btn btn-primary\">Yes</a>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div><!-- modal-content -->\n";
|
|
||||||
html += "</div><!-- modal-dialog -->\n";
|
|
||||||
html += "</div><!-- modal -->\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 += "<div id=\"copy-alert-modal\" class=\"modal fade\">\n";
|
|
||||||
html += "<div class=\"modal-dialog\">\n";
|
|
||||||
html += "<div class=\"modal-content\">\n";
|
|
||||||
html += "<div class=\"modal-header\">\n";
|
|
||||||
html += "<button type=\"button\" class=\"close\" ng-hide=\"disableButtons\" data-target=\"#copy-alert-modal\"\n";
|
|
||||||
html += "data-dismiss=\"modal\" class=\"modal\" aria-hidden=\"true\">×</button>\n";
|
|
||||||
html += "<h3>Already in Group</h3>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-body\">\n";
|
|
||||||
html += "<div class=\"alert alert-info\"><p>Host " + host.name + " is already in group " + target.name + ".</p></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-footer\">\n";
|
|
||||||
html += "<a href=\"#\" data-target=\"#copy-alert-modal\" data-dismiss=\"modal\" class=\"btn btn-primary\">OK</a>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\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 += "<div id=\"copy-prompt-modal\" class=\"modal fade\">\n";
|
|
||||||
html += "<div class=\"modal-dialog\">\n";
|
|
||||||
html += "<div class=\"modal-content\">\n";
|
|
||||||
html += "<div class=\"modal-header\">\n";
|
|
||||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
|
||||||
"data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n";
|
|
||||||
html += "<h3>Copy Host</h3>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-body\">\n";
|
|
||||||
html += "<div class=\"alert alert-info\">Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?</div>';
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "<div class=\"modal-footer\">\n";
|
|
||||||
html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">No</a>\n";
|
|
||||||
html += "<a href=\"\" data-target=\"#prompt-modal\" ng-click=\"copyHost()\" class=\"btn btn-primary\">Yes</a>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div><!-- modal-content -->\n";
|
|
||||||
html += "</div><!-- modal-dialog -->\n";
|
|
||||||
html += "</div><!-- modal -->\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 });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@@ -277,10 +277,14 @@ angular.module('GeneratorHelpers', [systemStatus.name])
|
|||||||
html = "<td class=\"" + fld + "-column";
|
html = "<td class=\"" + fld + "-column";
|
||||||
html += (field.columnClass) ? " " + field.columnClass : "";
|
html += (field.columnClass) ? " " + field.columnClass : "";
|
||||||
html += "\">\n";
|
html += "\">\n";
|
||||||
html += "<a ng-href=\"" + field.ngHref + "\" aw-tool-tip=\"" + field.awToolTip + "\"";
|
if (!field.noLink){
|
||||||
|
html += "<a ng-href=\"" + field.ngHref + "\" aw-tool-tip=\"" + field.awToolTip + "\"";
|
||||||
|
html += (field.dataPlacement) ? " data-placement=\"" + field.dataPlacement + "\"" : "";
|
||||||
|
html += ">";
|
||||||
|
}
|
||||||
|
html += "<span class=\"badge\"";
|
||||||
|
html += " aw-tool-tip=\"" + field.awToolTip + "\"";
|
||||||
html += (field.dataPlacement) ? " data-placement=\"" + field.dataPlacement + "\"" : "";
|
html += (field.dataPlacement) ? " data-placement=\"" + field.dataPlacement + "\"" : "";
|
||||||
html += ">";
|
|
||||||
html += "<span class=\"badge";
|
|
||||||
html += (field['class']) ? " " + field['class'] : "";
|
html += (field['class']) ? " " + field['class'] : "";
|
||||||
html += (field.ngHide) ? "\" ng-hide=\"" + field.ngHide : "";
|
html += (field.ngHide) ? "\" ng-hide=\"" + field.ngHide : "";
|
||||||
html += "\">";
|
html += "\">";
|
||||||
|
|||||||
@@ -439,6 +439,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
|
|||||||
innerTable += "ng-class-odd=\"'List-tableRow--oddRow'\" ";
|
innerTable += "ng-class-odd=\"'List-tableRow--oddRow'\" ";
|
||||||
innerTable += "ng-class-even=\"'List-tableRow--evenRow'\" ";
|
innerTable += "ng-class-even=\"'List-tableRow--evenRow'\" ";
|
||||||
innerTable += "ng-repeat=\"" + list.iterator + " in " + list.name;
|
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.orderBy) ? " | orderBy:'" + list.orderBy + "'" : "";
|
||||||
innerTable += (list.filterBy) ? " | filter: " + list.filterBy : "";
|
innerTable += (list.filterBy) ? " | filter: " + list.filterBy : "";
|
||||||
innerTable += "\">\n";
|
innerTable += "\">\n";
|
||||||
@@ -459,7 +460,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
|
|||||||
"ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" /></td>";
|
"ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" /></td>";
|
||||||
}
|
}
|
||||||
else { // its assumed that options.input_type = checkbox
|
else { // its assumed that options.input_type = checkbox
|
||||||
innerTable += "<td class=\"List-tableCell\"><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_" + list.iterator + "_{{" +
|
innerTable += "<td class=\"List-tableCell select-column List-staticColumn--smallStatus\"><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_{{" +
|
||||||
list.iterator + ".id }}\" ng-click=\"toggle_" + list.iterator + "(" + list.iterator + ".id, true)\" ng-true-value=\"1\" " +
|
list.iterator + ".id }}\" ng-click=\"toggle_" + list.iterator + "(" + list.iterator + ".id, true)\" ng-true-value=\"1\" " +
|
||||||
"ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" /></td>";
|
"ng-false-value=\"0\" id=\"check_" + list.iterator + "_{{" + list.iterator + ".id}}\" /></td>";
|
||||||
}
|
}
|
||||||
@@ -619,7 +620,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate
|
|||||||
html += buildSelectAll().prop('outerHTML');
|
html += buildSelectAll().prop('outerHTML');
|
||||||
}
|
}
|
||||||
else if (options.mode === 'lookup') {
|
else if (options.mode === 'lookup') {
|
||||||
html += "<th class=\"List-tableHeader List-staticColumn--smallStatus col-lg-1 col-md-1 col-sm-2 col-xs-2\"></th>";
|
html += "<th class=\"List-tableHeader select-column List-staticColumn--smallStatus\"></th>";
|
||||||
}
|
}
|
||||||
for (fld in list.fields) {
|
for (fld in list.fields) {
|
||||||
if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) &&
|
if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) &&
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import '../support/node';
|
import '../support/node';
|
||||||
|
|
||||||
import adhocModule from 'adhoc/main';
|
import adhocModule from 'inventories/manage/adhoc/main';
|
||||||
import RestStub from '../support/rest-stub';
|
import RestStub from '../support/rest-stub';
|
||||||
|
|
||||||
describe("adhoc.controller", function() {
|
describe("adhoc.controller", function() {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<include-svg href="{{ STATIC_URL }}assets/icons.svg"></include-svg>
|
<include-svg href="{{ STATIC_URL }}assets/icons.svg"></include-svg>
|
||||||
|
|
||||||
<main-menu></main-menu>
|
<main-menu></main-menu>
|
||||||
<bread-crumb></bread-crumb>
|
<bread-crumb ng-if="!includesCurrentState('inventoryManage')"></bread-crumb><div ui-view="groupBreadcrumbs" ng-if="includesCurrentState('inventoryManage')"></div>
|
||||||
<toast></toast>
|
<toast></toast>
|
||||||
|
|
||||||
<div class="container-fluid" id="content-container">
|
<div class="container-fluid" id="content-container">
|
||||||
|
|||||||
Reference in New Issue
Block a user