mirror of
https://github.com/ansible/awx.git
synced 2024-10-31 06:51:10 +03:00
Implement adhoc commands for normal inventories
This commit is contained in:
parent
0fa9aa6bcb
commit
8734ad738f
@ -203,7 +203,7 @@ table, tbody {
|
||||
.List-buttonDefault {
|
||||
background-color: @btn-bg;
|
||||
color: @btn-txt;
|
||||
border-color: @btn-bord;
|
||||
border-color: @b7grey;
|
||||
}
|
||||
|
||||
.List-buttonDefault:hover,
|
||||
@ -212,6 +212,11 @@ table, tbody {
|
||||
color: @btn-txt;
|
||||
}
|
||||
|
||||
.List-buttonDefault[disabled] {
|
||||
color: @d7grey;
|
||||
border-color: @d7grey;
|
||||
}
|
||||
|
||||
.List-searchDropdown {
|
||||
border-top-left-radius: 5px!important;
|
||||
border-bottom-left-radius: 5px!important;
|
||||
|
308
awx/ui/client/src/inventories/adhoc/adhoc.controller.js
Normal file
308
awx/ui/client/src/inventories/adhoc/adhoc.controller.js
Normal file
@ -0,0 +1,308 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:Adhoc
|
||||
* @description This controller controls the adhoc form creation, command launching and navigating to standard out after command has been succesfully ran.
|
||||
*/
|
||||
function adhocController($q, $scope, $stateParams,
|
||||
$state, CheckPasswords, PromptForPasswords, CreateLaunchDialog, CreateSelect2, adhocForm,
|
||||
GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices,
|
||||
KindChange, Wait, ParseTypeChange) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
// this is done so that we can access private functions for testing, but
|
||||
// we don't want to populate the "public" scope with these internal
|
||||
// functions
|
||||
var privateFn = {};
|
||||
this.privateFn = privateFn;
|
||||
|
||||
var id = $stateParams.inventory_id,
|
||||
hostPattern = $stateParams.pattern;
|
||||
|
||||
// note: put any urls that the controller will use in here!!!!
|
||||
privateFn.setAvailableUrls = function() {
|
||||
return {
|
||||
adhocUrl: GetBasePath('inventory') + id + '/ad_hoc_commands/',
|
||||
inventoryUrl: GetBasePath('inventory') + id + '/',
|
||||
machineCredentialUrl: GetBasePath('credentials') + '?kind=ssh'
|
||||
};
|
||||
};
|
||||
|
||||
var urls = privateFn.setAvailableUrls();
|
||||
|
||||
// set the default options for the selects of the adhoc form
|
||||
privateFn.setFieldDefaults = function(verbosity_options, forks_default) {
|
||||
var verbosity;
|
||||
for (verbosity in verbosity_options) {
|
||||
if (verbosity_options[verbosity].isDefault) {
|
||||
$scope.verbosity = verbosity_options[verbosity];
|
||||
}
|
||||
}
|
||||
$("#forks-number").spinner("value", forks_default);
|
||||
$scope.forks = forks_default;
|
||||
};
|
||||
|
||||
// set when "working" starts and stops
|
||||
privateFn.setLoadingStartStop = function() {
|
||||
var asyncHelper = {},
|
||||
formReadyPromise = 0;
|
||||
|
||||
Wait('start');
|
||||
|
||||
if (asyncHelper.removeChoicesReady) {
|
||||
asyncHelper.removeChoicesReady();
|
||||
}
|
||||
asyncHelper.removeChoicesReady = $scope.$on('adhocFormReady',
|
||||
isFormDone);
|
||||
|
||||
// check to see if all requests have completed
|
||||
function isFormDone() {
|
||||
formReadyPromise++;
|
||||
|
||||
if (formReadyPromise === 2) {
|
||||
privateFn.setFieldDefaults($scope.adhoc_verbosity_options,
|
||||
$scope.forks_field.default);
|
||||
|
||||
CreateSelect2({
|
||||
element: '#adhoc_module_name',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#adhoc_verbosity',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
Wait('stop');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// set the arguments help to watch on change of the module
|
||||
privateFn.instantiateArgumentHelp = function() {
|
||||
$scope.$watch('module_name', function(val) {
|
||||
if (val) {
|
||||
// give the docs for the selected module in the popover
|
||||
$scope.argsPopOver = '<p>These arguments are used with the ' +
|
||||
'specified module. You can find information about the ' +
|
||||
val.value + ' module <a ' +
|
||||
'id=\"adhoc_module_arguments_docs_link_for_module_' +
|
||||
val.value + '\" href=\"http://docs.ansible.com/' +
|
||||
val.value + '_module.html\" ' +
|
||||
'target=\"_blank\">here</a>.</p>';
|
||||
} else {
|
||||
// no module selected
|
||||
$scope.argsPopOver = "<p>These arguments are used with the" +
|
||||
" specified module.</p>";
|
||||
}
|
||||
}, true);
|
||||
|
||||
// initially set to the same as no module selected
|
||||
$scope.argsPopOver = "<p>These arguments are used with the " +
|
||||
"specified module.</p>";
|
||||
};
|
||||
|
||||
// pre-populate host patterns from the inventory page and
|
||||
// delete the value off of rootScope
|
||||
privateFn.instantiateHostPatterns = function(hostPattern) {
|
||||
$scope.limit = hostPattern;
|
||||
$scope.providedHostPatterns = $scope.limit;
|
||||
};
|
||||
|
||||
// call helpers to initialize lookup and select fields through get
|
||||
// requests
|
||||
privateFn.initializeFields = function(machineCredentialUrl, adhocUrl) {
|
||||
|
||||
// setup module name select
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: adhocUrl,
|
||||
field: 'module_name',
|
||||
variable: 'adhoc_module_options',
|
||||
callback: 'adhocFormReady'
|
||||
});
|
||||
|
||||
// setup verbosity options select
|
||||
GetChoices({
|
||||
scope: $scope,
|
||||
url: adhocUrl,
|
||||
field: 'verbosity',
|
||||
variable: 'adhoc_verbosity_options',
|
||||
callback: 'adhocFormReady'
|
||||
});
|
||||
};
|
||||
|
||||
// instantiate all variables on scope for display in the partial
|
||||
privateFn.initializeForm = function(id, urls, hostPattern) {
|
||||
// inject the adhoc command form
|
||||
GenerateForm.inject(adhocForm,
|
||||
{ mode: 'add', related: true, scope: $scope });
|
||||
|
||||
// set when "working" starts and stops
|
||||
privateFn.setLoadingStartStop();
|
||||
|
||||
// put the inventory id on scope for the partial to use
|
||||
$scope.inv_id = id;
|
||||
|
||||
// set the arguments help to watch on change of the module
|
||||
privateFn.instantiateArgumentHelp();
|
||||
|
||||
// pre-populate host patterns from the inventory page and
|
||||
// delete the value off of rootScope
|
||||
privateFn.instantiateHostPatterns(hostPattern);
|
||||
|
||||
privateFn.initializeFields(urls.machineCredentialUrl, urls.adhocUrl);
|
||||
};
|
||||
|
||||
privateFn.initializeForm(id, urls, hostPattern);
|
||||
|
||||
// init codemirror
|
||||
$scope.extra_vars = '---';
|
||||
$scope.parseType = 'yaml';
|
||||
$scope.envParseType = 'yaml';
|
||||
ParseTypeChange({ scope: $scope, field_id: 'adhoc_extra_vars' , variable: "extra_vars"});
|
||||
|
||||
$scope.formCancel = function(){
|
||||
$state.go('inventoryManage');
|
||||
};
|
||||
|
||||
// remove all data input into the form and reset the form back to defaults
|
||||
$scope.formReset = function () {
|
||||
GenerateForm.reset();
|
||||
|
||||
// pre-populate host patterns from the inventory page and
|
||||
// delete the value off of rootScope
|
||||
privateFn.instantiateHostPatterns($scope.providedHostPatterns);
|
||||
|
||||
KindChange({ scope: $scope, form: adhocForm, reset: false });
|
||||
|
||||
// set the default options for the selects of the adhoc form
|
||||
privateFn.setFieldDefaults($scope.adhoc_verbosity_options,
|
||||
$scope.forks_default);
|
||||
};
|
||||
|
||||
// launch the job with the provided form data
|
||||
$scope.launchJob = function () {
|
||||
var adhocUrl = GetBasePath('inventory') + $stateParams.inventory_id +
|
||||
'/ad_hoc_commands/', fld, data={}, html;
|
||||
|
||||
html = '<form class="ng-valid ng-valid-required" ' +
|
||||
'name="job_launch_form" id="job_launch_form" autocomplete="off" ' +
|
||||
'nonvalidate>';
|
||||
|
||||
// stub the payload with defaults from DRF
|
||||
data = {
|
||||
"job_type": "run",
|
||||
"limit": "",
|
||||
"credential": "",
|
||||
"module_name": "command",
|
||||
"module_args": "",
|
||||
"forks": 0,
|
||||
"verbosity": 0,
|
||||
"extra_vars": "",
|
||||
"privilege_escalation": ""
|
||||
};
|
||||
|
||||
GenerateForm.clearApiErrors($scope);
|
||||
|
||||
// populate data with the relevant form values
|
||||
for (fld in adhocForm.fields) {
|
||||
if (adhocForm.fields[fld].type === 'select') {
|
||||
data[fld] = $scope[fld].value;
|
||||
} else if ($scope[fld]) {
|
||||
data[fld] = $scope[fld];
|
||||
}
|
||||
}
|
||||
|
||||
Wait('start');
|
||||
|
||||
if ($scope.removeStartAdhocRun) {
|
||||
$scope.removeStartAdhocRun();
|
||||
}
|
||||
$scope.removeStartAdhocRun = $scope.$on('StartAdhocRun', function() {
|
||||
var password;
|
||||
for (password in $scope.passwords) {
|
||||
data[$scope.passwords[password]] = $scope[
|
||||
$scope.passwords[password]
|
||||
];
|
||||
}
|
||||
// Launch the adhoc job
|
||||
Rest.setUrl(GetBasePath('inventory') +
|
||||
$stateParams.inventory_id + '/ad_hoc_commands/');
|
||||
Rest.post(data)
|
||||
.success(function (data) {
|
||||
Wait('stop');
|
||||
$state.go('adHocJobStdout', {id: data.id});
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, adhocForm, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to launch adhoc command. POST ' +
|
||||
'returned status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeCreateLaunchDialog) {
|
||||
$scope.removeCreateLaunchDialog();
|
||||
}
|
||||
$scope.removeCreateLaunchDialog = $scope.$on('CreateLaunchDialog',
|
||||
function(e, html, url) {
|
||||
CreateLaunchDialog({
|
||||
scope: $scope,
|
||||
html: html,
|
||||
url: url,
|
||||
callback: 'StartAdhocRun'
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removePromptForPasswords) {
|
||||
$scope.removePromptForPasswords();
|
||||
}
|
||||
$scope.removePromptForPasswords = $scope.$on('PromptForPasswords',
|
||||
function(e, passwords_needed_to_start,html, url) {
|
||||
PromptForPasswords({ scope: $scope,
|
||||
passwords: passwords_needed_to_start,
|
||||
callback: 'CreateLaunchDialog',
|
||||
html: html,
|
||||
url: url
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeContinueCred) {
|
||||
$scope.removeContinueCred();
|
||||
}
|
||||
$scope.removeContinueCred = $scope.$on('ContinueCred', function(e,
|
||||
passwords) {
|
||||
if(passwords.length>0){
|
||||
$scope.passwords_needed_to_start = passwords;
|
||||
// only go through the password prompting steps if there are
|
||||
// passwords to prompt for
|
||||
$scope.$emit('PromptForPasswords', passwords, html, adhocUrl);
|
||||
} else {
|
||||
// if not, go straight to trying to run the job.
|
||||
$scope.$emit('StartAdhocRun', adhocUrl);
|
||||
}
|
||||
});
|
||||
|
||||
// start adhoc launching routine
|
||||
CheckPasswords({
|
||||
scope: $scope,
|
||||
credential: $scope.credential,
|
||||
callback: 'ContinueCred'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default ['$q', '$scope', '$stateParams',
|
||||
'$state', 'CheckPasswords', 'PromptForPasswords', 'CreateLaunchDialog', 'CreateSelect2',
|
||||
'adhocForm', 'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope', 'GetBasePath',
|
||||
'GetChoices', 'KindChange', 'Wait', 'ParseTypeChange',
|
||||
adhocController];
|
159
awx/ui/client/src/inventories/adhoc/adhoc.form.js
Normal file
159
awx/ui/client/src/inventories/adhoc/adhoc.form.js
Normal file
@ -0,0 +1,159 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name forms.function:Adhoc
|
||||
* @description This form is for executing an adhoc command
|
||||
*/
|
||||
|
||||
export default ['i18n', function(i18n) {
|
||||
return {
|
||||
addTitle: 'EXECUTE COMMAND',
|
||||
name: 'adhoc',
|
||||
well: true,
|
||||
forceListeners: true,
|
||||
|
||||
fields: {
|
||||
module_name: {
|
||||
label: 'Module',
|
||||
excludeModal: true,
|
||||
type: 'select',
|
||||
ngOptions: 'module.label for module in adhoc_module_options' +
|
||||
' track by module.value',
|
||||
ngChange: 'moduleChange()',
|
||||
required: true,
|
||||
awPopOver:'<p>These are the modules that Tower supports ' +
|
||||
'running commands against.',
|
||||
dataTitle: 'Module',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
},
|
||||
module_args: {
|
||||
label: 'Arguments',
|
||||
type: 'text',
|
||||
awPopOverWatch: 'argsPopOver',
|
||||
awPopOver: '{{ argsPopOver }}',
|
||||
dataTitle: 'Arguments',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
autocomplete: false
|
||||
},
|
||||
limit: {
|
||||
label: 'Limit',
|
||||
type: 'text',
|
||||
|
||||
awPopOver: '<p>The pattern used to target hosts in the ' +
|
||||
'inventory. Leaving the field blank, all, and * will ' +
|
||||
'all target all hosts in the inventory. You can find ' +
|
||||
'more information about Ansible\'s host patterns ' +
|
||||
'<a id=\"adhoc_form_hostpatterns_doc_link\"' +
|
||||
'href=\"http://docs.ansible.com/intro_patterns.html\" ' +
|
||||
'target=\"_blank\">here</a>.</p>',
|
||||
dataTitle: 'Limit',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
},
|
||||
credential: {
|
||||
label: 'Machine Credential',
|
||||
type: 'lookup',
|
||||
list: 'CredentialList',
|
||||
basePath: 'credentials',
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
class: 'squeeze',
|
||||
awPopOver: '<p>Select the credential you want to use when ' +
|
||||
'accessing the remote hosts to run the command. ' +
|
||||
'Choose the credential containing ' +
|
||||
'the username and SSH key or password that Ansbile ' +
|
||||
'will need to log into the remote hosts.</p>',
|
||||
dataTitle: 'Credential',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
awRequiredWhen: {
|
||||
reqExpression: 'credRequired',
|
||||
init: 'false'
|
||||
}
|
||||
},
|
||||
become_enabled: {
|
||||
label: 'Enable Privilege Escalation',
|
||||
type: 'checkbox',
|
||||
|
||||
column: 2,
|
||||
awPopOver: "<p>If enabled, run this playbook as an administrator. This is the equivalent of passing the<code> --become</code> option to the <code> ansible</code> command. </p>",
|
||||
dataPlacement: 'right',
|
||||
dataTitle: 'Become Privilege Escalation',
|
||||
dataContainer: "body"
|
||||
},
|
||||
verbosity: {
|
||||
label: 'Verbosity',
|
||||
excludeModal: true,
|
||||
type: 'select',
|
||||
ngOptions: 'verbosity.label for verbosity in ' +
|
||||
'adhoc_verbosity_options ' +
|
||||
'track by verbosity.value',
|
||||
required: true,
|
||||
awPopOver:'<p>These are the verbosity levels for standard ' +
|
||||
'out of the command run that are supported.',
|
||||
dataTitle: 'Verbosity',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
"default": 1
|
||||
},
|
||||
forks: {
|
||||
label: 'Forks',
|
||||
id: 'forks-number',
|
||||
type: 'number',
|
||||
integer: true,
|
||||
min: 0,
|
||||
spinner: true,
|
||||
"default": 0,
|
||||
required: true,
|
||||
'class': "input-small",
|
||||
column: 1,
|
||||
awPopOver: '<p>The number of parallel or simultaneous processes to use while executing the command. 0 signifies ' +
|
||||
'the default value from the <a id="ansible_forks_docs" href=\"http://docs.ansible.com/intro_configuration.html#the-ansible-configuration-file\" ' +
|
||||
' target=\"_blank\">ansible configuration file</a>.</p>',
|
||||
dataTitle: 'Forks',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
extra_vars: {
|
||||
label: i18n._('Extra Variables'),
|
||||
type: 'textarea',
|
||||
class: 'Form-textAreaLabel Form-formGroup--fullWidth',
|
||||
rows: 6,
|
||||
"default": "---",
|
||||
column: 2,
|
||||
awPopOver: "<p>" + i18n.sprintf(i18n._("Pass extra command line variables. This is the %s or %s command line parameter " +
|
||||
"for %s. Provide key/value pairs using either YAML or JSON."), '<code>-e</code>', '<code>--extra-vars</code>', '<code>ansible</code>') + "</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",
|
||||
dataTitle: i18n._('Extra Variables'),
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
}
|
||||
},
|
||||
buttons: {
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true,
|
||||
label: 'Reset',
|
||||
'class': 'btn btn-sm Form-cancelButton'
|
||||
},
|
||||
launch: {
|
||||
label: 'Save',
|
||||
ngClick: 'launchJob()',
|
||||
ngDisabled: true,
|
||||
'class': 'btn btn-sm List-buttonSubmit launchButton'
|
||||
}
|
||||
},
|
||||
|
||||
related: {}
|
||||
};
|
||||
}];
|
1
awx/ui/client/src/inventories/adhoc/adhoc.partial.html
Normal file
1
awx/ui/client/src/inventories/adhoc/adhoc.partial.html
Normal file
@ -0,0 +1 @@
|
||||
<div ng-cloak id="htmlTemplate"></div>
|
28
awx/ui/client/src/inventories/adhoc/adhoc.route.js
Normal file
28
awx/ui/client/src/inventories/adhoc/adhoc.route.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2015 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import {templateUrl} from '../../shared/template-url/template-url.factory';
|
||||
import { N_ } from '../../i18n';
|
||||
|
||||
export default {
|
||||
url: '/adhoc',
|
||||
params:{
|
||||
pattern: {
|
||||
value: 'all',
|
||||
squash: true
|
||||
}
|
||||
},
|
||||
name: 'inventories.edit.adhoc',
|
||||
views: {
|
||||
'adhocForm@inventories': {
|
||||
templateUrl: templateUrl('inventories/adhoc/adhoc'),
|
||||
controller: 'adhocController'
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: N_("RUN COMMAND")
|
||||
}
|
||||
};
|
7
awx/ui/client/src/inventories/adhoc/main.js
Normal file
7
awx/ui/client/src/inventories/adhoc/main.js
Normal file
@ -0,0 +1,7 @@
|
||||
import adhocController from './adhoc.controller';
|
||||
import form from './adhoc.form';
|
||||
|
||||
export default
|
||||
angular.module('adhoc', [])
|
||||
.controller('adhocController', adhocController)
|
||||
.factory('adhocForm', form);
|
@ -48,9 +48,8 @@ export default {
|
||||
},
|
||||
launch: {
|
||||
mode: 'all',
|
||||
// $scope.$parent is governed by InventoryManageController,
|
||||
ngDisabled: '!$parent.groupsSelected && !$parent.hostsSelected',
|
||||
ngClick: '$parent.setAdhocPattern()',
|
||||
ngDisabled: '!groupsSelected',
|
||||
ngClick: 'setAdhocPattern()',
|
||||
awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups.",
|
||||
dataTipWatch: "adhocCommandTooltip",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
|
@ -16,14 +16,14 @@
|
||||
init();
|
||||
|
||||
function init(){
|
||||
$scope.inventory_id = $stateParams.inventory_id;
|
||||
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
|
||||
$scope.canAdd = false;
|
||||
$scope.inventory_id = $stateParams.inventory_id;
|
||||
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
|
||||
$scope.canAdd = false;
|
||||
|
||||
rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups")
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups")
|
||||
.then(function(canAdd) {
|
||||
$scope.canAdd = canAdd;
|
||||
});
|
||||
|
||||
// Search init
|
||||
$scope.list = list;
|
||||
@ -43,6 +43,22 @@
|
||||
$scope.inventory_id = $stateParams.inventory_id;
|
||||
_.forEach($scope[list.name], buildStatusIndicators);
|
||||
|
||||
$scope.$on('selectedOrDeselected', function(e, value) {
|
||||
let item = value.value;
|
||||
|
||||
if (value.isSelected) {
|
||||
if(!$scope.groupsSelected) {
|
||||
$scope.groupsSelected = [];
|
||||
}
|
||||
$scope.groupsSelected.push(item);
|
||||
} else {
|
||||
_.remove($scope.groupsSelected, { id: item.id });
|
||||
if($scope.groupsSelected.length === 0) {
|
||||
$scope.groupsSelected = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function buildStatusIndicators(group){
|
||||
@ -195,11 +211,6 @@
|
||||
groupsArr.push(id);
|
||||
$state.go('inventoryManage.editGroup.schedules', {group_id: id, group: groupsArr}, {reload: true});
|
||||
};
|
||||
// $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.copyMoveGroup = function(id){
|
||||
$state.go('inventoryManage.copyMoveGroup', {group_id: id, groups: $stateParams.groups});
|
||||
@ -221,4 +232,13 @@
|
||||
cleanUpStateChangeListener();
|
||||
});
|
||||
|
||||
$scope.setAdhocPattern = function(){
|
||||
var pattern = _($scope.groupsSelected)
|
||||
.map(function(item){
|
||||
return item.name;
|
||||
}).value().join(':');
|
||||
|
||||
$state.go('^.adhoc', {pattern: pattern});
|
||||
};
|
||||
|
||||
}];
|
||||
|
@ -221,4 +221,13 @@
|
||||
cleanUpStateChangeListener();
|
||||
});
|
||||
|
||||
$scope.setAdhocPattern = function(){
|
||||
var pattern = _($scope.groupsSelected)
|
||||
.map(function(item){
|
||||
return item.name;
|
||||
}).value().join(':');
|
||||
|
||||
$state.go('^.adhoc', {pattern: pattern});
|
||||
};
|
||||
|
||||
}];
|
||||
|
@ -50,9 +50,8 @@ export default {
|
||||
},
|
||||
launch: {
|
||||
mode: 'all',
|
||||
// $scope.$parent is governed by InventoryManageController,
|
||||
ngDisabled: '!$parent.groupsSelected && !$parent.hostsSelected',
|
||||
ngClick: '$parent.setAdhocPattern()',
|
||||
ngDisabled: '!groupsSelected',
|
||||
ngClick: 'setAdhocPattern()',
|
||||
awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups.",
|
||||
dataTipWatch: "adhocCommandTooltip",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
|
@ -1,4 +1,5 @@
|
||||
<div class="tab-pane" id="inventories-panel">
|
||||
<div ui-view="adhocForm"></div>
|
||||
<div ui-view="groupForm"></div>
|
||||
<div ui-view="hostForm"></div>
|
||||
<div ui-view="sourcesForm"></div>
|
||||
|
@ -4,6 +4,7 @@
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import adhoc from './adhoc/main';
|
||||
import host from './hosts/main';
|
||||
import group from './groups/main';
|
||||
import sources from './sources/main';
|
||||
@ -17,8 +18,10 @@ import { N_ } from '../i18n';
|
||||
import InventoryList from './inventory.list';
|
||||
import InventoryForm from './inventory.form';
|
||||
import InventoryManageService from './inventory-manage.service';
|
||||
import adHocRoute from './adhoc/adhoc.route';
|
||||
export default
|
||||
angular.module('inventory', [
|
||||
adhoc.name,
|
||||
host.name,
|
||||
group.name,
|
||||
sources.name,
|
||||
@ -81,6 +84,60 @@ angular.module('inventory', [
|
||||
}
|
||||
});
|
||||
|
||||
let adhocCredentialLookup = {
|
||||
searchPrefix: 'credential',
|
||||
name: 'inventories.edit.adhoc.credential',
|
||||
url: '/credential',
|
||||
data: {
|
||||
formChildState: true
|
||||
},
|
||||
params: {
|
||||
credential_search: {
|
||||
value: {
|
||||
page_size: '5'
|
||||
},
|
||||
squash: true,
|
||||
dynamic: true
|
||||
}
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
skip: true
|
||||
},
|
||||
views: {
|
||||
'related': {
|
||||
templateProvider: function(ListDefinition, generateList) {
|
||||
let list_html = generateList.build({
|
||||
mode: 'lookup',
|
||||
list: ListDefinition,
|
||||
input_type: 'radio'
|
||||
});
|
||||
return `<lookup-modal>${list_html}</lookup-modal>`;
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
ListDefinition: ['CredentialList', function(CredentialList) {
|
||||
let list = _.cloneDeep(CredentialList);
|
||||
list.lookupConfirmText = 'SELECT';
|
||||
return list;
|
||||
}],
|
||||
Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath',
|
||||
(list, qs, $stateParams, GetBasePath) => {
|
||||
let path = GetBasePath(list.name) || GetBasePath(list.basePath);
|
||||
return qs.search(path, $stateParams[`${list.iterator}_search`]);
|
||||
}
|
||||
]
|
||||
},
|
||||
onExit: function($state) {
|
||||
if ($state.transition) {
|
||||
$('#form-modal').modal('hide');
|
||||
$('.modal-backdrop').remove();
|
||||
$('body').removeClass('modal-open');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
basicInventoryAdd,
|
||||
basicInventoryEdit,
|
||||
@ -121,7 +178,9 @@ angular.module('inventory', [
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
}),
|
||||
stateExtender.buildDefinition(adHocRoute),
|
||||
stateExtender.buildDefinition(adhocCredentialLookup)
|
||||
])
|
||||
};
|
||||
});
|
||||
|
@ -143,8 +143,17 @@ export default ['$scope', 'RelatedHostsListDefinition', '$rootScope', 'GetBasePa
|
||||
var hostIds = _.map($scope.hostsSelected, (host) => host.id);
|
||||
$state.go('systemTracking', {
|
||||
inventoryId: $state.params.inventory_id,
|
||||
hosts: $scope.$parent.hostsSelectedItems,
|
||||
hosts: $scope.hostsSelected,
|
||||
hostIds: hostIds
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setAdhocPattern = function(){
|
||||
var pattern = _($scope.hostsSelected)
|
||||
.map(function(item){
|
||||
return item.name;
|
||||
}).value().join(':');
|
||||
|
||||
$state.go('^.adhoc', {pattern: pattern});
|
||||
};
|
||||
}];
|
||||
|
@ -83,6 +83,19 @@ export default {
|
||||
},
|
||||
|
||||
actions: {
|
||||
launch: {
|
||||
mode: 'all',
|
||||
ngDisabled: '!hostsSelected',
|
||||
ngClick: 'setAdhocPattern()',
|
||||
awToolTip: "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups.",
|
||||
dataTipWatch: "adhocCommandTooltip",
|
||||
actionClass: 'btn List-buttonDefault',
|
||||
buttonContent: 'RUN COMMANDS',
|
||||
showTipWhenDisabled: true,
|
||||
tooltipInnerClass: "Tooltip-wide",
|
||||
// TODO: we don't always want to show this
|
||||
ngShow: true
|
||||
},
|
||||
system_tracking: {
|
||||
buttonContent: 'System Tracking',
|
||||
ngClick: 'systemTracking()',
|
||||
|
Loading…
Reference in New Issue
Block a user