mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 09:27:36 -02:30
UI support for adhoc commands
This commit is contained in:
@@ -40,6 +40,7 @@ import {ScheduleEditController} from 'tower/controllers/Schedules';
|
|||||||
import {ProjectsList, ProjectsAdd, ProjectsEdit} from 'tower/controllers/Projects';
|
import {ProjectsList, ProjectsAdd, ProjectsEdit} from 'tower/controllers/Projects';
|
||||||
import {OrganizationsList, OrganizationsAdd, OrganizationsEdit} from 'tower/controllers/Organizations';
|
import {OrganizationsList, OrganizationsAdd, OrganizationsEdit} from 'tower/controllers/Organizations';
|
||||||
import {InventoriesList, InventoriesAdd, InventoriesEdit, InventoriesManage} from 'tower/controllers/Inventories';
|
import {InventoriesList, InventoriesAdd, InventoriesEdit, InventoriesManage} from 'tower/controllers/Inventories';
|
||||||
|
import {AdhocForm} from 'tower/controllers/Adhoc';
|
||||||
import {AdminsList} from 'tower/controllers/Admins';
|
import {AdminsList} from 'tower/controllers/Admins';
|
||||||
import {UsersList, UsersAdd, UsersEdit} from 'tower/controllers/Users';
|
import {UsersList, UsersAdd, UsersEdit} from 'tower/controllers/Users';
|
||||||
import {TeamsList, TeamsAdd, TeamsEdit} from 'tower/controllers/Teams';
|
import {TeamsList, TeamsAdd, TeamsEdit} from 'tower/controllers/Teams';
|
||||||
@@ -88,6 +89,7 @@ var tower = angular.module('Tower', [
|
|||||||
'AdminListDefinition',
|
'AdminListDefinition',
|
||||||
'CustomInventoryListDefinition',
|
'CustomInventoryListDefinition',
|
||||||
'AWDirectives',
|
'AWDirectives',
|
||||||
|
'AdhocFormDefinition',
|
||||||
'InventoriesListDefinition',
|
'InventoriesListDefinition',
|
||||||
'InventoryFormDefinition',
|
'InventoryFormDefinition',
|
||||||
'InventoryHelper',
|
'InventoryHelper',
|
||||||
@@ -168,7 +170,8 @@ var tower = angular.module('Tower', [
|
|||||||
'ConfigureTowerHelper',
|
'ConfigureTowerHelper',
|
||||||
'ConfigureTowerJobsListDefinition',
|
'ConfigureTowerJobsListDefinition',
|
||||||
'CreateCustomInventoryHelper',
|
'CreateCustomInventoryHelper',
|
||||||
'CustomInventoryListDefinition'
|
'CustomInventoryListDefinition',
|
||||||
|
'AdhocHelper'
|
||||||
])
|
])
|
||||||
|
|
||||||
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
|
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
|
||||||
@@ -200,6 +203,11 @@ var tower = angular.module('Tower', [
|
|||||||
controller: JobStdoutController
|
controller: JobStdoutController
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
when('/ad_hoc_commands/:id', {
|
||||||
|
templateUrl: urlPrefix + 'partials/job_stdout_adhoc.html',
|
||||||
|
controller: JobStdoutController
|
||||||
|
}).
|
||||||
|
|
||||||
when('/job_templates', {
|
when('/job_templates', {
|
||||||
templateUrl: urlPrefix + 'partials/job_templates.html',
|
templateUrl: urlPrefix + 'partials/job_templates.html',
|
||||||
controller: JobTemplatesList
|
controller: JobTemplatesList
|
||||||
@@ -280,6 +288,11 @@ var tower = angular.module('Tower', [
|
|||||||
controller: InventoriesManage
|
controller: InventoriesManage
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
when('/inventories/:inventory_id/adhoc', {
|
||||||
|
templateUrl: urlPrefix + 'partials/adhoc.html',
|
||||||
|
controller: AdhocForm
|
||||||
|
}).
|
||||||
|
|
||||||
when('/organizations', {
|
when('/organizations', {
|
||||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
templateUrl: urlPrefix + 'partials/organizations.html',
|
||||||
controller: OrganizationsList
|
controller: OrganizationsList
|
||||||
|
|||||||
171
awx/ui/static/js/controllers/Adhoc.js
Normal file
171
awx/ui/static/js/controllers/Adhoc.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2015 AnsibleWorks, Inc.
|
||||||
|
*
|
||||||
|
* Adhoc.js
|
||||||
|
*
|
||||||
|
* Controller functions for the Adhoc model.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
export function AdhocForm($scope, $rootScope, $location, $routeParams,
|
||||||
|
AdhocForm, GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath,
|
||||||
|
GetChoices, KindChange, LookUpInit, CredentialList, Empty, OwnerChange,
|
||||||
|
LoginMethodChange, Wait) {
|
||||||
|
|
||||||
|
ClearScope();
|
||||||
|
|
||||||
|
var url = GetBasePath('inventory') + $routeParams.inventory_id
|
||||||
|
+ '/ad_hoc_commands/',
|
||||||
|
generator = GenerateForm,
|
||||||
|
form = AdhocForm,
|
||||||
|
master = {},
|
||||||
|
id = $routeParams.inventory_id;
|
||||||
|
|
||||||
|
// inject the adhoc command form
|
||||||
|
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
||||||
|
generator.reset();
|
||||||
|
|
||||||
|
// BEGIN: populate scope with the things needed to make the adhoc form
|
||||||
|
// display
|
||||||
|
Wait('start');
|
||||||
|
$scope.id = id;
|
||||||
|
$scope.argsPopOver = "<p>These arguments are used with the"
|
||||||
|
+ " specified module.</p>";
|
||||||
|
// fix arguments help popover based on the module selected
|
||||||
|
$scope.moduleChange = function () {
|
||||||
|
// NOTE: for selenium testing link -
|
||||||
|
// link will be displayed with id adhoc_module_arguments_docs_link
|
||||||
|
// only when a module is selected
|
||||||
|
if ($scope.module_name) {
|
||||||
|
// give the docs for the selected module
|
||||||
|
$scope.argsPopOver = "<p>These arguments are used with the"
|
||||||
|
+ " specified module. You can find information about the "
|
||||||
|
+ $scope.module_name.value
|
||||||
|
+ " <a id=\"adhoc_module_arguments_docs_link_for_module_"
|
||||||
|
+ $scope.module_name.value
|
||||||
|
+ "\""
|
||||||
|
+ " href=\"http://docs.ansible.com/" + $scope.module_name.value
|
||||||
|
+ "_module.html\" target=\"_blank\">here</a>.</p>";
|
||||||
|
} else {
|
||||||
|
// no module selected
|
||||||
|
$scope.argsPopOver = "<p>These arguments are used with the"
|
||||||
|
+ " specified module.</p>";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// pre-populate hostPatterns from the inventory page and
|
||||||
|
// delete the value off of rootScope
|
||||||
|
$scope.limit = $rootScope.hostPatterns || "all";
|
||||||
|
delete $rootScope.hostPatterns;
|
||||||
|
|
||||||
|
if ($scope.removeChoicesReady) {
|
||||||
|
$scope.removeChoicesReady();
|
||||||
|
}
|
||||||
|
$scope.removeChoicesReady = $scope.$on('choicesReadyAdhoc', function () {
|
||||||
|
LookUpInit({
|
||||||
|
scope: $scope,
|
||||||
|
form: form,
|
||||||
|
current_item: (!Empty($scope.credential_id)) ? $scope.credential_id : null,
|
||||||
|
list: CredentialList,
|
||||||
|
field: 'credential',
|
||||||
|
input_type: 'radio'
|
||||||
|
});
|
||||||
|
|
||||||
|
OwnerChange({ scope: $scope });
|
||||||
|
LoginMethodChange({ scope: $scope });
|
||||||
|
|
||||||
|
Wait('stop'); // END: form population
|
||||||
|
});
|
||||||
|
|
||||||
|
// setup Machine Credential lookup
|
||||||
|
GetChoices({
|
||||||
|
scope: $scope,
|
||||||
|
url: url,
|
||||||
|
field: 'module_name',
|
||||||
|
variable: 'adhoc_module_options',
|
||||||
|
callback: 'choicesReadyAdhoc'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Owner change
|
||||||
|
$scope.ownerChange = function () {
|
||||||
|
OwnerChange({ scope: $scope });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle Login Method change
|
||||||
|
$scope.loginMethodChange = function () {
|
||||||
|
LoginMethodChange({ scope: $scope });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle Kind change
|
||||||
|
$scope.kindChange = function () {
|
||||||
|
KindChange({ scope: $scope, form: form, reset: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
// launch the job with the provided form data
|
||||||
|
$scope.launchJob = function () {
|
||||||
|
var fld, data={};
|
||||||
|
|
||||||
|
// stub the payload with defaults from DRF
|
||||||
|
data = {
|
||||||
|
"job_type": "run",
|
||||||
|
"limit": "",
|
||||||
|
"credential": null,
|
||||||
|
"module_name": "command",
|
||||||
|
"module_args": "",
|
||||||
|
"forks": 0,
|
||||||
|
"verbosity": 0,
|
||||||
|
"privilege_escalation": ""
|
||||||
|
};
|
||||||
|
|
||||||
|
generator.clearApiErrors();
|
||||||
|
|
||||||
|
// populate data with the relevant form values
|
||||||
|
for (fld in form.fields) {
|
||||||
|
if (form.fields[fld].type === 'select') {
|
||||||
|
data[fld] = $scope[fld].value
|
||||||
|
} else {
|
||||||
|
data[fld] = $scope[fld];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Wait('start');
|
||||||
|
|
||||||
|
// Launch the adhoc job
|
||||||
|
Rest.setUrl(url);
|
||||||
|
Rest.post(data)
|
||||||
|
.success(function (data) {
|
||||||
|
Wait('stop');
|
||||||
|
$location.path("/ad_hoc_commands/" + data.id);
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
|
||||||
|
msg: 'Failed to launch adhoc command. POST returned status: '
|
||||||
|
+ status });
|
||||||
|
// TODO: still need to implement popping up a password prompt
|
||||||
|
// if the credential requires it. The way that the current end-
|
||||||
|
// point works is that I find out if I need to ask for a
|
||||||
|
// password from POST, thus I get an error response.
|
||||||
|
$scope.formReset();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove all data input into the form
|
||||||
|
$scope.formReset = function () {
|
||||||
|
generator.reset();
|
||||||
|
for (var fld in master) {
|
||||||
|
$scope[fld] = master[fld];
|
||||||
|
}
|
||||||
|
KindChange({ scope: $scope, form: form, reset: false });
|
||||||
|
OwnerChange({ scope: $scope });
|
||||||
|
LoginMethodChange({ scope: $scope });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
AdhocForm.$inject = ['$scope', '$rootScope', '$location', '$routeParams',
|
||||||
|
'AdhocForm', 'GenerateForm', 'Rest', 'ProcessErrors', 'ClearScope',
|
||||||
|
'GetBasePath', 'GetChoices', 'KindChange', 'LookUpInit', 'CredentialList',
|
||||||
|
'Empty', 'OwnerChange', 'LoginMethodChange', 'Wait'];
|
||||||
@@ -870,6 +870,53 @@ export function InventoriesManage ($log, $scope, $rootScope, $location,
|
|||||||
show_failures: false
|
show_failures: false
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
if (selection.length > 0) {
|
||||||
|
$scope.hostsSelected = true;
|
||||||
|
// $scope.adhocButtonTipContents = "Launch adhoc command for the "
|
||||||
|
// + "selected groups and hosts.";
|
||||||
|
} else {
|
||||||
|
$scope.hostsSelected = false;
|
||||||
|
// $scope.adhocButtonTipContents = "Launch adhoc command for the "
|
||||||
|
// + "inventory.";
|
||||||
|
}
|
||||||
|
$scope.hostsSelectedItems = selection.selectedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
// populates host patterns based on selected hosts/groups
|
||||||
|
$scope.populateAdhocForm = function() {
|
||||||
|
var host_patterns = "all";
|
||||||
|
if ($scope.hostsSelected || $scope.groupsSelected) {
|
||||||
|
var allSelectedItems = $scope.groupsSelectedItems.concat($scope.hostsSelectedItems)
|
||||||
|
host_patterns = _.pluck(allSelectedItems, "name").join(":");
|
||||||
|
}
|
||||||
|
$rootScope.hostPatterns = host_patterns;
|
||||||
|
$location.path('/inventories/' + $scope.inventory.id + '/adhoc');
|
||||||
|
}
|
||||||
|
|
||||||
$scope.refreshHostsOnGroupRefresh = false;
|
$scope.refreshHostsOnGroupRefresh = false;
|
||||||
$scope.selected_group_id = null;
|
$scope.selected_group_id = null;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export function JobStdoutController ($log, $rootScope, $scope, $compile, $routeParams, ClearScope, GetBasePath, Wait, Rest, ProcessErrors, Socket) {
|
export function JobStdoutController ($location, $log, $rootScope, $scope, $compile, $routeParams, ClearScope, GetBasePath, Wait, Rest, ProcessErrors, Socket) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
@@ -170,7 +170,9 @@ export function JobStdoutController ($log, $rootScope, $scope, $compile, $routeP
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Rest.setUrl(GetBasePath('jobs') + job_id + '/');
|
// Note: could be ad_hoc_commands or jobs
|
||||||
|
var jobType = $location.path().replace(/^\//, '').split('/')[0];
|
||||||
|
Rest.setUrl(GetBasePath(jobType) + job_id + '/');
|
||||||
Rest.get()
|
Rest.get()
|
||||||
.success(function(data) {
|
.success(function(data) {
|
||||||
$scope.job = data;
|
$scope.job = data;
|
||||||
@@ -270,6 +272,5 @@ export function JobStdoutController ($log, $rootScope, $scope, $compile, $routeP
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JobStdoutController.$inject = [ '$log', '$rootScope', '$scope', '$compile', '$routeParams', 'ClearScope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors',
|
JobStdoutController.$inject = [ '$location', '$log', '$rootScope', '$scope', '$compile', '$routeParams', 'ClearScope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors',
|
||||||
'Socket' ];
|
'Socket' ];
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ export function PermissionsList($scope, $rootScope, $location, $log, $routeParam
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if the permission includes adhoc (and is not admin), display that
|
||||||
|
$scope.getPermissionText = function () {
|
||||||
|
if (this.permission.permission_type !== "admin" && this.permission.run_ad_hoc_commands) {
|
||||||
|
return this.permission.permission_type + " + ad hoc";
|
||||||
|
} else {
|
||||||
|
return this.permission.permission_type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$scope.editPermission = function (id) {
|
$scope.editPermission = function (id) {
|
||||||
$location.path($location.path() + '/' + id);
|
$location.path($location.path() + '/' + id);
|
||||||
};
|
};
|
||||||
@@ -156,6 +165,11 @@ export function PermissionsAdd($scope, $rootScope, $compile, $location, $log, $r
|
|||||||
for (fld in form.fields) {
|
for (fld in form.fields) {
|
||||||
data[fld] = $scope[fld];
|
data[fld] = $scope[fld];
|
||||||
}
|
}
|
||||||
|
// job template (or deploy) based permissions do not have the run
|
||||||
|
// ad hoc commands parameter
|
||||||
|
if (data.category === "Deploy") {
|
||||||
|
data.run_ad_hoc_commands = false;
|
||||||
|
}
|
||||||
url = (base === 'teams') ? GetBasePath('teams') + id + '/permissions/' : GetBasePath('users') + id + '/permissions/';
|
url = (base === 'teams') ? GetBasePath('teams') + id + '/permissions/' : GetBasePath('users') + id + '/permissions/';
|
||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
Rest.post(data)
|
Rest.post(data)
|
||||||
@@ -305,6 +319,11 @@ export function PermissionsEdit($scope, $rootScope, $compile, $location, $log, $
|
|||||||
for (fld in form.fields) {
|
for (fld in form.fields) {
|
||||||
data[fld] = $scope[fld];
|
data[fld] = $scope[fld];
|
||||||
}
|
}
|
||||||
|
// job template (or deploy) based permissions do not have the run
|
||||||
|
// ad hoc commands parameter
|
||||||
|
if (data.category === "Deploy") {
|
||||||
|
data.run_ad_hoc_commands = false;
|
||||||
|
}
|
||||||
Rest.setUrl(defaultUrl);
|
Rest.setUrl(defaultUrl);
|
||||||
if($scope.category === "Inventory"){
|
if($scope.category === "Inventory"){
|
||||||
delete data.project;
|
delete data.project;
|
||||||
|
|||||||
@@ -294,6 +294,15 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP
|
|||||||
$routeParams.id + '. GET status: ' + status });
|
$routeParams.id + '. GET status: ' + status });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if the permission includes adhoc (and is not admin), display that
|
||||||
|
$scope.getPermissionText = function () {
|
||||||
|
if (this.permission.permission_type !== "admin" && this.permission.run_ad_hoc_commands) {
|
||||||
|
return this.permission.permission_type + " + ad hoc";
|
||||||
|
} else {
|
||||||
|
return this.permission.permission_type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Save changes to the parent
|
// Save changes to the parent
|
||||||
$scope.formSave = function () {
|
$scope.formSave = function () {
|
||||||
var data = {}, fld;
|
var data = {}, fld;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import ActivityDetail from "tower/forms/ActivityDetail";
|
import ActivityDetail from "tower/forms/ActivityDetail";
|
||||||
import Credentials from "tower/forms/Credentials";
|
import Credentials from "tower/forms/Credentials";
|
||||||
|
import Adhoc from "tower/forms/Adhoc";
|
||||||
import CustomInventory from "tower/forms/CustomInventory";
|
import CustomInventory from "tower/forms/CustomInventory";
|
||||||
import EventsViewer from "tower/forms/EventsViewer";
|
import EventsViewer from "tower/forms/EventsViewer";
|
||||||
import Groups from "tower/forms/Groups";
|
import Groups from "tower/forms/Groups";
|
||||||
@@ -30,6 +31,7 @@ import Users from "tower/forms/Users";
|
|||||||
export
|
export
|
||||||
{ ActivityDetail,
|
{ ActivityDetail,
|
||||||
Credentials,
|
Credentials,
|
||||||
|
Adhoc,
|
||||||
CustomInventory,
|
CustomInventory,
|
||||||
EventsViewer,
|
EventsViewer,
|
||||||
Groups,
|
Groups,
|
||||||
|
|||||||
98
awx/ui/static/js/forms/Adhoc.js
Normal file
98
awx/ui/static/js/forms/Adhoc.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*********************************************
|
||||||
|
* Copyright (c) 2015 AnsibleWorks, Inc.
|
||||||
|
*
|
||||||
|
* Adhoc.js
|
||||||
|
* Form definition for the Adhoc model.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @ngdoc function
|
||||||
|
* @name forms.function:Adhoc
|
||||||
|
* @description This form is for executing an adhoc command
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('AdhocFormDefinition', [])
|
||||||
|
.value('AdhocForm', {
|
||||||
|
editTitle: '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()',
|
||||||
|
editRequired: 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: 'See adhoc controller...set as argsPopOver',
|
||||||
|
dataTitle: 'Arguments',
|
||||||
|
dataPlacement: 'right',
|
||||||
|
dataContainer: 'body',
|
||||||
|
editRequired: false,
|
||||||
|
autocomplete: false
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
label: 'Host Pattern',
|
||||||
|
type: 'text',
|
||||||
|
addRequired: false,
|
||||||
|
editRequired: false,
|
||||||
|
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: 'Host Pattern',
|
||||||
|
dataPlacement: 'right',
|
||||||
|
dataContainer: 'body'
|
||||||
|
},
|
||||||
|
credential: {
|
||||||
|
label: 'Machine Credential',
|
||||||
|
type: 'lookup',
|
||||||
|
sourceModel: 'credential',
|
||||||
|
sourceField: 'name',
|
||||||
|
ngClick: 'lookUpCredential()',
|
||||||
|
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: {
|
||||||
|
variable: 'credRequired',
|
||||||
|
init: 'false'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
buttons: {
|
||||||
|
launch: {
|
||||||
|
label: 'Launch',
|
||||||
|
ngClick: 'launchJob()',
|
||||||
|
ngDisabled: true
|
||||||
|
},
|
||||||
|
reset: {
|
||||||
|
ngClick: 'formReset()',
|
||||||
|
ngDisabled: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
related: {}
|
||||||
|
});
|
||||||
@@ -96,6 +96,7 @@ export default
|
|||||||
label: 'Permission',
|
label: 'Permission',
|
||||||
labelClass: 'prepend-asterisk',
|
labelClass: 'prepend-asterisk',
|
||||||
type: 'radio_group',
|
type: 'radio_group',
|
||||||
|
class: 'squeeze',
|
||||||
options: [{
|
options: [{
|
||||||
label: 'Read',
|
label: 'Read',
|
||||||
value: 'read',
|
value: 'read',
|
||||||
@@ -121,11 +122,26 @@ export default
|
|||||||
value: 'check',
|
value: 'check',
|
||||||
ngShow: "category == 'Deploy'"
|
ngShow: "category == 'Deploy'"
|
||||||
}],
|
}],
|
||||||
|
// hack: attach helpCollapse here if the permissions
|
||||||
|
// category is deploy
|
||||||
|
helpCollapse: [{
|
||||||
|
hdr: 'Permission',
|
||||||
|
ngBind: 'permissionTypeHelp',
|
||||||
|
ngHide: "category == 'Inventory'"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
run_ad_hoc_commands: {
|
||||||
|
label: 'Execute commands',
|
||||||
|
type: 'checkbox',
|
||||||
|
// hack: attach helpCollapse here if the permissions
|
||||||
|
// category is inventory
|
||||||
helpCollapse: [{
|
helpCollapse: [{
|
||||||
hdr: 'Permission',
|
hdr: 'Permission',
|
||||||
ngBind: 'permissionTypeHelp'
|
ngBind: 'permissionTypeHelp'
|
||||||
}]
|
}],
|
||||||
}
|
ngShow: "category == 'Inventory'",
|
||||||
|
associated: 'permission_type'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
|
|||||||
@@ -211,9 +211,9 @@ export default
|
|||||||
ngBind: 'permission.summary_fields.project.name'
|
ngBind: 'permission.summary_fields.project.name'
|
||||||
},
|
},
|
||||||
permission_type: {
|
permission_type: {
|
||||||
label: 'Permission'
|
label: 'Permission',
|
||||||
|
ngBind: 'getPermissionText()'
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fieldActions: {
|
fieldActions: {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import Refresh from "tower/helpers/refresh";
|
|||||||
import RelatedSearch from "tower/helpers/related-search";
|
import RelatedSearch from "tower/helpers/related-search";
|
||||||
import Search from "tower/helpers/search";
|
import Search from "tower/helpers/search";
|
||||||
import Teams from "tower/helpers/teams";
|
import Teams from "tower/helpers/teams";
|
||||||
|
import AdhocHelper from "tower/helpers/Adhoc";
|
||||||
|
|
||||||
export
|
export
|
||||||
{ AboutAnsible,
|
{ AboutAnsible,
|
||||||
@@ -78,5 +79,6 @@ export
|
|||||||
Refresh,
|
Refresh,
|
||||||
RelatedSearch,
|
RelatedSearch,
|
||||||
Search,
|
Search,
|
||||||
Teams
|
Teams,
|
||||||
|
AdhocHelper
|
||||||
};
|
};
|
||||||
|
|||||||
147
awx/ui/static/js/helpers/Adhoc.js
Normal file
147
awx/ui/static/js/helpers/Adhoc.js
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*********************************************
|
||||||
|
* Copyright (c) 2015 AnsibleWorks, Inc.
|
||||||
|
*
|
||||||
|
* AdhocHelper
|
||||||
|
*
|
||||||
|
* Routines shared by adhoc related controllers:
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @ngdoc function
|
||||||
|
* @name helpers.function:Adhoc
|
||||||
|
* @description routines shared by adhoc related controllers
|
||||||
|
* AdhocRun is currently only used for _relaunching_ an adhoc command
|
||||||
|
* from the Jobs page.
|
||||||
|
* TODO: once the API endpoint is figured out for running an adhoc command
|
||||||
|
* from the form is figured out, the rest work should probably be excised from
|
||||||
|
* the controller and moved into here. See the todo statements in the
|
||||||
|
* controller for more information about this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('AdhocHelper', ['RestServices', 'Utilities',
|
||||||
|
'CredentialFormDefinition', 'CredentialsListDefinition', 'LookUpHelper',
|
||||||
|
'JobSubmissionHelper', 'JobTemplateFormDefinition', 'ModalDialog',
|
||||||
|
'FormGenerator', 'JobVarsPromptFormDefinition'])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name helpers.function:JobSubmission#AdhocRun
|
||||||
|
* @methodOf helpers.function:JobSubmission
|
||||||
|
* @description The adhoc Run function is run when the user clicks the relaunch button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// Submit request to run an adhoc comamand
|
||||||
|
.factory('AdhocRun', ['$location','$routeParams', 'LaunchJob',
|
||||||
|
'PromptForPasswords', 'Rest', 'GetBasePath', 'Alert', 'ProcessErrors',
|
||||||
|
'Wait', 'Empty', 'PromptForCredential', 'PromptForVars',
|
||||||
|
'PromptForSurvey' , 'CreateLaunchDialog',
|
||||||
|
function ($location, $routeParams, LaunchJob, PromptForPasswords,
|
||||||
|
Rest, GetBasePath, Alert, ProcessErrors, Wait, Empty,
|
||||||
|
PromptForCredential, PromptForVars, PromptForSurvey,
|
||||||
|
CreateLaunchDialog) {
|
||||||
|
return function (params) {
|
||||||
|
var id = params.project_id,
|
||||||
|
scope = params.scope.$new(),
|
||||||
|
new_job_id,
|
||||||
|
launch_url,
|
||||||
|
html,
|
||||||
|
url;
|
||||||
|
|
||||||
|
// this is used to cancel a running adhoc command from
|
||||||
|
// the jobs page
|
||||||
|
if (scope.removeCancelJob) {
|
||||||
|
scope.removeCancelJob();
|
||||||
|
}
|
||||||
|
scope.removeCancelJob = scope.$on('CancelJob', function() {
|
||||||
|
// Delete the job
|
||||||
|
Wait('start');
|
||||||
|
Rest.setUrl(GetBasePath('ad_hoc_commands') + new_job_id + '/');
|
||||||
|
Rest.destroy()
|
||||||
|
.success(function() {
|
||||||
|
Wait('stop');
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors(scope, data, status,
|
||||||
|
null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url
|
||||||
|
+ ' failed. DELETE returned status: '
|
||||||
|
+ status });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scope.removeAdhocLaunchFinished) {
|
||||||
|
scope.removeAdhocLaunchFinished();
|
||||||
|
}
|
||||||
|
scope.removeAdhocLaunchFinished = scope.$on('AdhocLaunchFinished',
|
||||||
|
function(e, data) {
|
||||||
|
$location.path('/ad_hoc_commands/' + data.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scope.removeStartAdhocRun) {
|
||||||
|
scope.removeStartAdhocRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.removeStartAdhocRun = scope.$on('StartAdhocRun', function() {
|
||||||
|
LaunchJob({
|
||||||
|
scope: scope,
|
||||||
|
url: url,
|
||||||
|
callback: 'AdhocLaunchFinished' // send to the adhoc
|
||||||
|
// standard out page
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// start routine only if passwords need to be prompted
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}); // end password prompting routine
|
||||||
|
|
||||||
|
// start the adhoc relaunch routine
|
||||||
|
Wait('start');
|
||||||
|
url = GetBasePath('ad_hoc_commands') + id + '/relaunch/';
|
||||||
|
Rest.setUrl(url);
|
||||||
|
Rest.get()
|
||||||
|
.success(function (data) {
|
||||||
|
var new_job_id = data.id,
|
||||||
|
launch_url = url;
|
||||||
|
|
||||||
|
scope.passwords_needed_to_start = data.passwords_needed_to_start;
|
||||||
|
if (!Empty(data.passwords_needed_to_start) &&
|
||||||
|
data.passwords_needed_to_start.length > 0) {
|
||||||
|
// go through the password prompt routine before
|
||||||
|
// starting the adhoc run
|
||||||
|
scope.$emit('PromptForPasswords', data.passwords_needed_to_start, html, url);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no prompting of passwords needed
|
||||||
|
scope.$emit('StartAdhocRun');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Failed to get job template details. GET returned status: ' + status });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}]);
|
||||||
@@ -70,6 +70,8 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
|||||||
scope.example_template_id = 'N';
|
scope.example_template_id = 'N';
|
||||||
scope.setCallbackHelp();
|
scope.setCallbackHelp();
|
||||||
|
|
||||||
|
// this fills the job template form both on copy of the job template
|
||||||
|
// and on edit
|
||||||
scope.fillJobTemplate = function(){
|
scope.fillJobTemplate = function(){
|
||||||
// id = id || $rootScope.copy.id;
|
// id = id || $rootScope.copy.id;
|
||||||
// Retrieve detail record and prepopulate the form
|
// Retrieve detail record and prepopulate the form
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import listGenerator from 'tower/shared/list-generator/main';
|
|||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper', 'GeneratorHelpers',
|
angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper', 'GeneratorHelpers',
|
||||||
'JobSubmissionHelper', 'LogViewerHelper', 'SearchHelper', 'PaginationHelpers', listGenerator.name])
|
'JobSubmissionHelper', 'LogViewerHelper', 'SearchHelper', 'PaginationHelpers', 'AdhocHelper', listGenerator.name])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JobsControllerInit({ scope: $scope });
|
* JobsControllerInit({ scope: $scope });
|
||||||
@@ -62,7 +62,7 @@ export default
|
|||||||
else if (job.type === 'project_update') {
|
else if (job.type === 'project_update') {
|
||||||
typeId = job.project;
|
typeId = job.project;
|
||||||
}
|
}
|
||||||
else if (job.type === 'job' || job.type === "system_job") {
|
else if (job.type === 'job' || job.type === "system_job" || job.type === 'ad_hoc_command') {
|
||||||
typeId = job.id;
|
typeId = job.id;
|
||||||
}
|
}
|
||||||
RelaunchJob({ scope: scope, id: typeId, type: job.type, name: job.name });
|
RelaunchJob({ scope: scope, id: typeId, type: job.type, name: job.name });
|
||||||
@@ -112,8 +112,8 @@ export default
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
.factory('RelaunchJob', ['RelaunchInventory', 'RelaunchPlaybook', 'RelaunchSCM',
|
.factory('RelaunchJob', ['RelaunchInventory', 'RelaunchPlaybook', 'RelaunchSCM', 'RelaunchAdhoc',
|
||||||
function(RelaunchInventory, RelaunchPlaybook, RelaunchSCM) {
|
function(RelaunchInventory, RelaunchPlaybook, RelaunchSCM, RelaunchAdhoc) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
id = params.id,
|
id = params.id,
|
||||||
@@ -122,6 +122,9 @@ export default
|
|||||||
if (type === 'inventory_update') {
|
if (type === 'inventory_update') {
|
||||||
RelaunchInventory({ scope: scope, id: id});
|
RelaunchInventory({ scope: scope, id: id});
|
||||||
}
|
}
|
||||||
|
else if (type === 'ad_hoc_command') {
|
||||||
|
RelaunchAdhoc({ scope: scope, id: id, name: name });
|
||||||
|
}
|
||||||
else if (type === 'job' || type === 'system_job') {
|
else if (type === 'job' || type === 'system_job') {
|
||||||
RelaunchPlaybook({ scope: scope, id: id, name: name });
|
RelaunchPlaybook({ scope: scope, id: id, name: name });
|
||||||
}
|
}
|
||||||
@@ -595,4 +598,12 @@ export default
|
|||||||
id = params.id;
|
id = params.id;
|
||||||
ProjectUpdate({ scope: scope, project_id: id });
|
ProjectUpdate({ scope: scope, project_id: id });
|
||||||
};
|
};
|
||||||
|
}])
|
||||||
|
|
||||||
|
.factory('RelaunchAdhoc', ['AdhocRun', function(AdhocRun) {
|
||||||
|
return function(params) {
|
||||||
|
var scope = params.scope,
|
||||||
|
id = params.id;
|
||||||
|
AdhocRun({ scope: scope, project_id: id, relaunch: true });
|
||||||
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@@ -26,30 +26,52 @@ export default
|
|||||||
scope.projectrequired = false;
|
scope.projectrequired = false;
|
||||||
html = "<dl>\n" +
|
html = "<dl>\n" +
|
||||||
"<dt>Read</dt>\n" +
|
"<dt>Read</dt>\n" +
|
||||||
"<dd>Only allow the user or team to view the inventory.</dd>\n" +
|
"<dd>Only allow the user or team to view the inventory."
|
||||||
|
+ "</dd>\n" +
|
||||||
"<dt>Write</dt>\n" +
|
"<dt>Write</dt>\n" +
|
||||||
"<dd>Allow the user or team to modify hosts and groups contained in the inventory, add new hosts and groups, and perform inventory sync operations.\n" +
|
"<dd>Allow the user or team to modify hosts and groups "
|
||||||
|
+ "contained in the inventory, add new hosts and groups"
|
||||||
|
+ ", and perform inventory sync operations.\n" +
|
||||||
"<dt>Admin</dt>\n" +
|
"<dt>Admin</dt>\n" +
|
||||||
"<dd>Allow the user or team full access to the inventory. This includes reading, writing, deletion of the inventory and inventory sync operations.</dd>\n" +
|
"<dd>Allow the user or team full access to the "
|
||||||
|
+ "inventory. This includes reading, writing, deletion "
|
||||||
|
+ "of the inventory, inventory sync operations, and "
|
||||||
|
+ "the ability to execute commands on the inventory."
|
||||||
|
+ "</dd>\n" +
|
||||||
|
"<dt>Execute commands</dt>\n" +
|
||||||
|
"<dd>Allow the user to execute commands on the "
|
||||||
|
+ "inventory.</dd>\n" +
|
||||||
"</dl>\n";
|
"</dl>\n";
|
||||||
scope.permissionTypeHelp = $sce.trustAsHtml(html);
|
scope.permissionTypeHelp = $sce.trustAsHtml(html);
|
||||||
} else {
|
} else {
|
||||||
scope.projectrequired = true;
|
scope.projectrequired = true;
|
||||||
html = "<dl>\n" +
|
html = "<dl>\n" +
|
||||||
"<dt>Create</dt>\n" +
|
"<dt>Create</dt>\n" +
|
||||||
"<dd>Allow the user or team to create job templates. This implies that they have the Run and Check permissions.</dd>\n" +
|
"<dd>Allow the user or team to create job templates. "
|
||||||
|
+ "This implies that they have the Run and Check "
|
||||||
|
+ "permissions.</dd>\n" +
|
||||||
"<dt>Run</dt>\n" +
|
"<dt>Run</dt>\n" +
|
||||||
"<dd>Allow the user or team to run a job template from the project against the inventory. In Run mode modules will " +
|
"<dd>Allow the user or team to run a job template from "
|
||||||
"be executed, and changes to the inventory will occur.</dd>\n" +
|
+ "the project against the inventory. In Run mode "
|
||||||
|
+ "modules will " +
|
||||||
|
"be executed, and changes to the inventory will occur."
|
||||||
|
+ "</dd>\n" +
|
||||||
"<dt>Check</dt>\n" +
|
"<dt>Check</dt>\n" +
|
||||||
"<dd>Only allow the user or team to run the project against the inventory as a dry-run operation. In Check mode, module operations " +
|
"<dd>Only allow the user or team to run the project "
|
||||||
"will only be simulated. No changes will occur.</dd>\n" +
|
+ "against the inventory as a dry-run operation. In "
|
||||||
|
+ "Check mode, module operations " +
|
||||||
|
"will only be simulated. No changes will occur."
|
||||||
|
+ "</dd>\n" +
|
||||||
"</dl>\n";
|
"</dl>\n";
|
||||||
scope.permissionTypeHelp = $sce.trustAsHtml(html);
|
scope.permissionTypeHelp = $sce.trustAsHtml(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reset) {
|
if (reset) {
|
||||||
scope.permission_type = (scope.category === 'Inventory') ? 'read' : 'run'; //default to the first option
|
if (scope.category === "Inventory") {
|
||||||
|
scope.permission_type = "read";
|
||||||
|
} else {
|
||||||
|
scope.permission_type = "run";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default
|
|||||||
index: false,
|
index: false,
|
||||||
hover: true,
|
hover: true,
|
||||||
'class': 'table-no-border',
|
'class': 'table-no-border',
|
||||||
|
multiSelect: true,
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
name: {
|
name: {
|
||||||
@@ -78,6 +79,17 @@ export default
|
|||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
launch: {
|
||||||
|
mode: 'all',
|
||||||
|
// TODO: ngShow permissions
|
||||||
|
ngClick: 'populateAdhocForm()',
|
||||||
|
awToolTip: "Run a command on this inventory"
|
||||||
|
// TODO: set up a tip watcher and change text based on when
|
||||||
|
// things are selected/not selected. This is started and
|
||||||
|
// commented out in the inventory controller within the watchers.
|
||||||
|
// awToolTip: "{{ adhocButtonTipContents }}",
|
||||||
|
// dataTipWatch: "adhocButtonTipContents"
|
||||||
|
},
|
||||||
create: {
|
create: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "createGroup()",
|
ngClick: "createGroup()",
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ export default
|
|||||||
ngBind: 'permission.summary_fields.project.name'
|
ngBind: 'permission.summary_fields.project.name'
|
||||||
},
|
},
|
||||||
permission_type: {
|
permission_type: {
|
||||||
label: 'Permission'
|
label: 'Permission',
|
||||||
|
ngBind: 'getPermissionText()'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -609,6 +609,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
params.content = collapse_array[i].content;
|
params.content = collapse_array[i].content;
|
||||||
params.idx = this.accordion_count++;
|
params.idx = this.accordion_count++;
|
||||||
params.show = (collapse_array[i].show) ? collapse_array[i].show : null;
|
params.show = (collapse_array[i].show) ? collapse_array[i].show : null;
|
||||||
|
params.ngHide = (collapse_array[i].ngHide) ? collapse_array[i].ngHide : null;
|
||||||
params.bind = (collapse_array[i].ngBind) ? collapse_array[i].ngBind : null;
|
params.bind = (collapse_array[i].ngBind) ? collapse_array[i].ngBind : null;
|
||||||
html += HelpCollapse(params);
|
html += HelpCollapse(params);
|
||||||
}
|
}
|
||||||
@@ -676,6 +677,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += Attr(field, 'type');
|
html += Attr(field, 'type');
|
||||||
html += "ng-model=\"" + fld + '" ';
|
html += "ng-model=\"" + fld + '" ';
|
||||||
html += "name=\"" + fld + '" ';
|
html += "name=\"" + fld + '" ';
|
||||||
|
if (form.name === "permission") {
|
||||||
|
html += "ng-disabled='permission_type === \"admin\"'";
|
||||||
|
html += "ng-checked='permission_type === \"admin\"'";
|
||||||
|
}
|
||||||
html += (field.ngChange) ? Attr(field, 'ngChange') : "";
|
html += (field.ngChange) ? Attr(field, 'ngChange') : "";
|
||||||
html += "id=\"" + form.name + "_" + fld + "_chbox\" ";
|
html += "id=\"" + form.name + "_" + fld + "_chbox\" ";
|
||||||
html += (idx !== undefined) ? "_" + idx : "";
|
html += (idx !== undefined) ? "_" + idx : "";
|
||||||
@@ -752,7 +757,9 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((!field.readonly) || (field.readonly && options.mode === 'edit')) {
|
if ((!field.readonly) || (field.readonly && options.mode === 'edit')) {
|
||||||
html += "<div class='form-group' ";
|
html += "<div class='form-group ";
|
||||||
|
html += (field['class']) ? (field['class']) : "";
|
||||||
|
html += "'";
|
||||||
html += (field.ngShow) ? this.attr(field, 'ngShow') : "";
|
html += (field.ngShow) ? this.attr(field, 'ngShow') : "";
|
||||||
html += (field.ngHide) ? this.attr(field, 'ngHide') : "";
|
html += (field.ngHide) ? this.attr(field, 'ngHide') : "";
|
||||||
html += ">\n";
|
html += ">\n";
|
||||||
@@ -1246,6 +1253,8 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
if (horizontal) {
|
if (horizontal) {
|
||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html += (field.helpCollapse) ? this.buildHelpCollapse(field.helpCollapse) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
//radio group
|
//radio group
|
||||||
@@ -1642,6 +1651,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
button.label = 'Reset';
|
button.label = 'Reset';
|
||||||
button['class'] = 'btn-default';
|
button['class'] = 'btn-default';
|
||||||
}
|
}
|
||||||
|
if (btn === 'launch') {
|
||||||
|
button.label = 'Launch';
|
||||||
|
button['class'] = 'btn-primary';
|
||||||
|
}
|
||||||
|
|
||||||
// Build button HTML
|
// Build button HTML
|
||||||
html += "<button type=\"button\" ";
|
html += "<button type=\"button\" ";
|
||||||
|
|||||||
@@ -130,6 +130,9 @@ angular.module('GeneratorHelpers', [systemStatus.name])
|
|||||||
case 'submit':
|
case 'submit':
|
||||||
icon = 'fa-rocket';
|
icon = 'fa-rocket';
|
||||||
break;
|
break;
|
||||||
|
case 'launch':
|
||||||
|
icon = 'fa-rocket';
|
||||||
|
break;
|
||||||
case 'stream':
|
case 'stream':
|
||||||
icon = 'fa-clock-o';
|
icon = 'fa-clock-o';
|
||||||
break;
|
break;
|
||||||
@@ -652,12 +655,14 @@ angular.module('GeneratorHelpers', [systemStatus.name])
|
|||||||
var hdr = params.hdr,
|
var hdr = params.hdr,
|
||||||
content = params.content,
|
content = params.content,
|
||||||
show = params.show,
|
show = params.show,
|
||||||
|
ngHide = params.ngHide,
|
||||||
idx = params.idx,
|
idx = params.idx,
|
||||||
bind = params.bind,
|
bind = params.bind,
|
||||||
html = '';
|
html = '';
|
||||||
|
|
||||||
html += "<div class=\"panel-group collapsible-help\" ";
|
html += "<div class=\"panel-group collapsible-help\" ";
|
||||||
html += (show) ? "ng-show=\"" + show + "\"" : "";
|
html += (show) ? "ng-show=\"" + show + "\" " : "";
|
||||||
|
html += (ngHide) ? "ng-hide=\"" + ngHide + "\" " : "";
|
||||||
html += ">\n";
|
html += ">\n";
|
||||||
html += "<div class=\"panel panel-default\">\n";
|
html += "<div class=\"panel panel-default\">\n";
|
||||||
html += "<div class=\"panel-heading\" ng-click=\"accordionToggle('#accordion" + idx + "')\">\n";
|
html += "<div class=\"panel-heading\" ng-click=\"accordionToggle('#accordion" + idx + "')\">\n";
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
<span ng-repeat="(name, options) in list.actions">
|
<span ng-repeat="(name, options) in list.actions">
|
||||||
|
<!-- TODO: Unfortunately, the data-tip-watch attribute is not loaded for
|
||||||
|
some reason -->
|
||||||
<button
|
<button
|
||||||
toolbar-button
|
toolbar-button
|
||||||
mode="options.mode"
|
mode="options.mode"
|
||||||
icon-name="{{name}}"
|
icon-name="{{name}}"
|
||||||
aw-tool-tip="{{options.awToolTip}}"
|
aw-tool-tip="{{options.awToolTip}}"
|
||||||
|
data-tip-watch="{{options.dataTipWatch}}"
|
||||||
data-placement="{{options.dataPlacement}}"
|
data-placement="{{options.dataPlacement}}"
|
||||||
data-container="{{options.dataContainer}}"
|
data-container="{{options.dataContainer}}"
|
||||||
class="options.class"
|
class="options.class"
|
||||||
|
|||||||
@@ -1535,9 +1535,9 @@ input[type="checkbox"].checkbox-no-label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inventory edit dialog, source form, ec2
|
// ad hoc permission checkbox
|
||||||
#source_form.squeeze .form-group {
|
.squeeze.form-group {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
|
|||||||
4
awx/ui/static/partials/adhoc.html
Normal file
4
awx/ui/static/partials/adhoc.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<div class="tab-pane" id="credentials">
|
||||||
|
<div ng-cloak id="htmlTemplate">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
50
awx/ui/static/partials/job_stdout_adhoc.html
Normal file
50
awx/ui/static/partials/job_stdout_adhoc.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<div class="tab-pane" id="jobs-stdout">
|
||||||
|
<div ng-cloak id="htmlTemplate">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div id="breadcrumb-container" class="col-md-6"
|
||||||
|
style="position: relative;">
|
||||||
|
<ul class="ansible-breadcrumb" id="breadcrumb-list">
|
||||||
|
<li><a href="/#/jobs">Jobs</a></li>
|
||||||
|
<li class="active">
|
||||||
|
<a href="/#/ad_hoc_commands/{{ job.id }}">
|
||||||
|
{{ job.id }} - {{ job.name }} standard out
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="home-list-actions"
|
||||||
|
class="list-actions pull-right col-md-6">
|
||||||
|
<button type="button" class="btn btn-xs btn-primary ng-hide"
|
||||||
|
ng-click="refresh()" id="refresh_btn"
|
||||||
|
aw-tool-tip="Refresh the page"
|
||||||
|
data-placement="top" ng-show="socketStatus == 'error'"
|
||||||
|
data-original-title="" title="">
|
||||||
|
<i class="fa fa-refresh fa-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div id="job-status">
|
||||||
|
<label>Job Status</label>
|
||||||
|
<i class="fa icon-job-{{ job.status }}"></i> {{ job.status }}
|
||||||
|
</div>
|
||||||
|
<div class="scroll-spinner" id="stdoutMoreRowsTop">
|
||||||
|
<i class="fa fa-cog fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
<div id="pre-container" class="body_background
|
||||||
|
body_foreground pre mono-space"
|
||||||
|
lr-infinite-scroll="stdOutScrollToTop"
|
||||||
|
scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||||
|
<div id="pre-container-content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||||
|
<i class="fa fa-cog fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user