mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
Merge pull request #4425 from mabashian/toggles
Swap text-based on and off toggles to non-text based Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
commit
d7c15a782f
@ -15,3 +15,4 @@
|
||||
@import 'utility/_index';
|
||||
@import 'code-mirror/_index';
|
||||
@import 'cards/_index';
|
||||
@import 'switch/_index';
|
||||
|
||||
@ -44,6 +44,7 @@ import truncate from '~components/truncate/truncate.directive';
|
||||
import atCodeMirror from '~components/code-mirror';
|
||||
import card from '~components/cards/card.directive';
|
||||
import cardGroup from '~components/cards/group.directive';
|
||||
import atSwitch from '~components/switch/switch.directive';
|
||||
|
||||
import BaseInputController from '~components/input/base.controller';
|
||||
import ComponentsStrings from '~components/components.strings';
|
||||
@ -98,6 +99,7 @@ angular
|
||||
.directive('atTruncate', truncate)
|
||||
.directive('atCard', card)
|
||||
.directive('atCardGroup', cardGroup)
|
||||
.directive('atSwitch', atSwitch)
|
||||
.service('BaseInputController', BaseInputController)
|
||||
.service('ComponentsStrings', ComponentsStrings);
|
||||
|
||||
|
||||
85
awx/ui/client/lib/components/switch/_index.less
Normal file
85
awx/ui/client/lib/components/switch/_index.less
Normal file
@ -0,0 +1,85 @@
|
||||
.atSwitch-listTableCell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
justify-content: flex-end;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.atSwitch-outer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 26px;
|
||||
cursor: pointer;
|
||||
|
||||
.fa {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.atSwitch-on {
|
||||
.atSwitch-slider {
|
||||
background-color: @default-link;
|
||||
}
|
||||
|
||||
.atSwitch-slider:before {
|
||||
-webkit-transform: translateX(16px);
|
||||
-ms-transform: translateX(16px);
|
||||
transform: translateX(16px);
|
||||
}
|
||||
|
||||
.fa {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 4px;
|
||||
color: @default-bg;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.atSwitch-disabled {
|
||||
cursor: not-allowed;
|
||||
|
||||
.atSwitch-inner {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.atSwitch-slider {
|
||||
background-color: @default-icon;
|
||||
}
|
||||
|
||||
.atSwitch-slider:before {
|
||||
background-color: @d2grey;
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: @d2grey;
|
||||
}
|
||||
}
|
||||
|
||||
.atSwitch-slider {
|
||||
position: absolute;
|
||||
border-radius: 34px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: @d2grey;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.atSwitch-slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 4px;
|
||||
bottom: 5px;
|
||||
background-color: @default-bg;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
22
awx/ui/client/lib/components/switch/switch.directive.js
Normal file
22
awx/ui/client/lib/components/switch/switch.directive.js
Normal file
@ -0,0 +1,22 @@
|
||||
const templateUrl = require('~components/switch/switch.partial.html');
|
||||
|
||||
function atSwitch () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl,
|
||||
scope: {
|
||||
hide: '=',
|
||||
onToggle: '&',
|
||||
switchOn: '=',
|
||||
switchDisabled: '=',
|
||||
tooltip: '=',
|
||||
tooltipString: '@',
|
||||
tooltipPlacement: '@',
|
||||
tooltipContainer: '@',
|
||||
tooltipWatch: '='
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default atSwitch;
|
||||
6
awx/ui/client/lib/components/switch/switch.partial.html
Normal file
6
awx/ui/client/lib/components/switch/switch.partial.html
Normal file
@ -0,0 +1,6 @@
|
||||
<span class="atSwitch-outer" ng-hide="hide" ng-class="{'atSwitch-on': switchOn, 'atSwitch-disabled': switchDisabled}" aw-tool-tip="{{tooltipString ? tooltipString : tooltip}}" data-placement="{{tooltipPlacement}}" data-tip-watch="tooltipWatch">
|
||||
<span class="atSwitch-inner" ng-click="onToggle()">
|
||||
<span class="atSwitch-slider"></span>
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</span>
|
||||
@ -79,7 +79,6 @@
|
||||
@import '../../src/inventories-hosts/inventories/inventories.block.less';
|
||||
@import '../../src/inventories-hosts/shared/associate-groups/associate-groups.block.less';
|
||||
@import '../../src/inventories-hosts/shared/associate-hosts/associate-hosts.block.less';
|
||||
@import '../../src/job-submission/job-submission.block.less';
|
||||
@import '../../src/license/license.block.less';
|
||||
@import '../../src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less';
|
||||
@import '../../src/login/loginModal/loginModal.block.less';
|
||||
@ -93,7 +92,6 @@
|
||||
@import '../../src/scheduler/schedulerDatePicker.block.less';
|
||||
@import '../../src/scheduler/schedulerFormDetail.block.less';
|
||||
@import '../../src/scheduler/schedulertime.block.less';
|
||||
@import '../../src/scheduler/scheduleToggle.block.less';
|
||||
@import '../../src/scheduler/spinnerInput.block.less';
|
||||
@import '../../src/shared/container/container.block.less';
|
||||
@import '../../src/shared/detail-nav/detail-nav.block.less';
|
||||
|
||||
@ -28,17 +28,14 @@
|
||||
<div ng-show="systemVm.activeSystemForm === 'logging'">
|
||||
<div class="form-group Form-formGroup">
|
||||
<label class="Form-inputLabelContainer" for="LOG_AGGREGATOR_ENABLED">
|
||||
<span class="Form-inputLabel">
|
||||
<span class="Form-inputLabel" translate>
|
||||
Enable External Logging
|
||||
</span>
|
||||
<a id="awp-LOG_AGGREGATOR_ENABLED" href="" aw-pop-over="Enable sending logs to external log aggregator." data-placement="top" over-title="Enable External Logging" class="help-link" tabindex="-1">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': LOG_AGGREGATOR_ENABLED, 'ScheduleToggle--disabled': (!LOG_AGGREGATOR_ENABLED && (!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '')) || $rootScope.user_is_system_auditor}">
|
||||
<button ng-show="LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch is-on" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="$rootScope.user_is_system_auditor">ON</button>
|
||||
<button ng-show="!LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '' || $rootScope.user_is_system_auditor">OFF</button>
|
||||
</div>
|
||||
<at-switch on-toggle="toggleForm('LOG_AGGREGATOR_ENABLED')" switch-on="LOG_AGGREGATOR_ENABLED" switch-disabled="(!LOG_AGGREGATOR_ENABLED && (!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '')) || $rootScope.user_is_system_auditor"></at-switch>
|
||||
</div>
|
||||
<div id="system-logging-form">
|
||||
|
||||
|
||||
@ -131,9 +131,8 @@ input#filePickerText {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
// Filepicker and toggle disabling
|
||||
.Form-browseButton, .Form-filePicker--textBox,
|
||||
.ScheduleToggle {
|
||||
// Filepicker disabling
|
||||
.Form-browseButton, .Form-filePicker--textBox {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@ -45,24 +45,7 @@
|
||||
<at-row ng-repeat="instance in vm.instances"
|
||||
ng-class="{'at-Row--active': (instance.id === vm.activeId)}">
|
||||
<div class="at-Row-toggle">
|
||||
<div class="ScheduleToggle"
|
||||
ng-class="{'is-on': instance.enabled,
|
||||
'ScheduleToggle--disabled': vm.rowAction.toggle._disabled}">
|
||||
<button ng-show="instance.enabled"
|
||||
type="button"
|
||||
class="ScheduleToggle-switch is-on ng-hide"
|
||||
ng-click="vm.toggle(instance)"
|
||||
ng-disabled="vm.rowAction.toggle._disabled">
|
||||
{{:: vm.strings.get('ON') }}
|
||||
</button>
|
||||
<button ng-show="!instance.enabled"
|
||||
type="button"
|
||||
class="ScheduleToggle-switch"
|
||||
ng-click="vm.toggle(instance)"
|
||||
ng-disabled="vm.rowAction.toggle._disabled">
|
||||
{{:: vm.strings.get('OFF') }}
|
||||
</button>
|
||||
</div>
|
||||
<at-switch on-toggle="vm.toggle(instance)" switch-on="instance.enabled" switch-disabled="vm.rowAction.toggle._disabled"></at-switch>
|
||||
</div>
|
||||
|
||||
<div class="at-Row-items at-Row-items--instances">
|
||||
|
||||
@ -52,10 +52,7 @@
|
||||
<div class="List-staticColumnLayout--hosts List-tableRow" ng-repeat="host in hosts track by host.id">
|
||||
<div></div>
|
||||
<div class="List-tableCell toggleHost-column List-staticColumn--toggle">
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': host.enabled}" aw-tool-tip="{{strings.get('hostList.DISABLED_TOGGLE_TOOLTIP')}}" data-placement="right" data-tip-watch="undefined">
|
||||
<button type="button" ng-show="host.enabled" class="ScheduleToggle-switch is-on" ng-click="toggleHost($event, host)" translate>ON</button>
|
||||
<button type="button" ng-show="!host.enabled" class="ScheduleToggle-switch" ng-click="toggleHost($event, host)" translate>OFF</button>
|
||||
</div>
|
||||
<at-switch on-toggle="toggleHost($event, host)" switch-on="host.enabled" switch-disabled="!host.summary_fields.user_capabilities.edit" tooltip="strings.get('hostList.DISABLED_TOGGLE_TOOLTIP')" tooltip-placement="right"></at-switch>
|
||||
</div>
|
||||
<div class="List-tableCell active_failures-column status-column List-staticColumn--smallStatus">
|
||||
<div class="host-name">
|
||||
|
||||
@ -80,9 +80,8 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
|
||||
}
|
||||
|
||||
host.enabled = !host.enabled;
|
||||
|
||||
HostsService.put(host).then(function(){
|
||||
$state.go($state.current, null, {reload: true});
|
||||
HostsService.patch(host.id, {
|
||||
enabled: host.enabled
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -34,6 +34,15 @@
|
||||
.catch(this.error.bind(this))
|
||||
.finally(Wait('stop'));
|
||||
},
|
||||
patch: function(id, data){
|
||||
Wait('start');
|
||||
this.url = GetBasePath('hosts') + id;
|
||||
Rest.setUrl(this.url);
|
||||
return Rest.patch(data)
|
||||
.then(this.success.bind(this))
|
||||
.catch(this.error.bind(this))
|
||||
.finally(Wait('stop'));
|
||||
},
|
||||
post: function(host){
|
||||
Wait('start');
|
||||
this.url = GetBasePath('hosts');
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
export default
|
||||
function GetSurveyQuestions($filter, GetBasePath, Rest, Empty, ProcessErrors, $stateParams) {
|
||||
|
||||
// This factory goes out and gets a job template's survey questions and attaches
|
||||
// them to scope so that they can be ng-repeated in the job submission template
|
||||
|
||||
return function(params) {
|
||||
var id= params.id,
|
||||
scope = params.scope,
|
||||
submitJobType = params.submitJobType,
|
||||
i,
|
||||
survey_url;
|
||||
|
||||
if(submitJobType === 'job_template') {
|
||||
survey_url = GetBasePath('job_templates') + id + '/survey_spec/';
|
||||
}
|
||||
else if(submitJobType === 'workflow_job_template') {
|
||||
survey_url = GetBasePath('workflow_job_templates') + id + '/survey_spec/';
|
||||
}
|
||||
|
||||
Rest.setUrl(survey_url);
|
||||
Rest.get()
|
||||
.then(({data}) => {
|
||||
if(!Empty(data)){
|
||||
scope.survey_name = data.name;
|
||||
scope.survey_description = data.description;
|
||||
scope.survey_questions = data.spec;
|
||||
|
||||
for(i=0; i<scope.survey_questions.length; i++){
|
||||
var question = scope.survey_questions[i];
|
||||
question.index = i;
|
||||
question.question_name = $filter('sanitize')(question.question_name);
|
||||
question.question_description = (question.question_description) ? $filter('sanitize')(question.question_description) : undefined;
|
||||
|
||||
if(question.type === "textarea" && !Empty(question.default_textarea)) {
|
||||
question.model = angular.copy(question.default_textarea);
|
||||
}
|
||||
else if(question.type === "multiselect") {
|
||||
question.model = question.default.split(/\n/);
|
||||
question.choices = question.choices.split(/\n/);
|
||||
}
|
||||
else if(question.type === "multiplechoice") {
|
||||
question.model = question.default ? angular.copy(question.default) : "";
|
||||
question.choices = question.choices.split(/\n/);
|
||||
|
||||
// Add a default empty string option to the choices array. If this choice is
|
||||
// selected then the extra var will not be sent when we POST to the launch
|
||||
// endpoint
|
||||
if(!question.required) {
|
||||
question.choices.unshift('');
|
||||
}
|
||||
}
|
||||
else if(question.type === "float"){
|
||||
question.model = (!Empty(question.default)) ? angular.copy(question.default) : (!Empty(question.default_float)) ? angular.copy(question.default_float) : "";
|
||||
}
|
||||
else {
|
||||
question.model = question.default ? angular.copy(question.default) : "";
|
||||
}
|
||||
|
||||
if(question.type === "text" || question.type === "textarea" || question.type === "password") {
|
||||
question.minlength = (!Empty(question.min)) ? Number(question.min) : "";
|
||||
question.maxlength = (!Empty(question.max)) ? Number(question.max) : "" ;
|
||||
}
|
||||
else if(question.type === "integer") {
|
||||
question.minValue = (!Empty(question.min)) ? Number(question.min) : "";
|
||||
question.maxValue = (!Empty(question.max)) ? Number(question.max) : "" ;
|
||||
}
|
||||
else if(question.type === "float") {
|
||||
question.minValue = (!Empty(question.min)) ? question.min : "";
|
||||
question.maxValue = (!Empty(question.max)) ? question.max : "" ;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors(scope, data, status, { hdr: 'Error!',
|
||||
msg: 'Failed to retrieve organization: ' + $stateParams.id + '. GET status: ' + status });
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
GetSurveyQuestions.$inject =
|
||||
[ '$filter',
|
||||
'GetBasePath',
|
||||
'Rest' ,
|
||||
'Empty',
|
||||
'ProcessErrors',
|
||||
'$stateParams'
|
||||
];
|
||||
@ -1,261 +0,0 @@
|
||||
.JobSubmission {
|
||||
padding: 20px!important;
|
||||
display: none;
|
||||
height: auto!important;
|
||||
min-height: 400px!important;
|
||||
}
|
||||
.JobSubmission-container {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
height: auto;
|
||||
min-height: 360px;
|
||||
}
|
||||
.JobSubmission-dialog {
|
||||
padding: 0px;
|
||||
margin-bottom: 20px;
|
||||
.ui-dialog-buttonpane, .ui-dialog-titlebar {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.JobSubmission-header {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.JobSubmission-title {
|
||||
align-items: center;
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
max-width: 98%;
|
||||
}
|
||||
.JobSubmission-titleText {
|
||||
color: @list-title-txt;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.JobSubmission-titleLockup {
|
||||
margin-left: 4px;
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
margin-top: 0px;
|
||||
padding-bottom: 2px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.JobSubmission-titleLockup:before {
|
||||
content: "\007C";
|
||||
color: @default-icon-hov;
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
}
|
||||
.JobSubmission-close {
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
}
|
||||
.JobSubmission-exit{
|
||||
cursor:pointer;
|
||||
padding:0px;
|
||||
border: none;
|
||||
height:20px;
|
||||
font-size: 20px;
|
||||
background-color:@default-bg;
|
||||
color:@d7grey;
|
||||
transition: color 0.2s;
|
||||
line-height:1;
|
||||
}
|
||||
.JobSubmission-exit:hover{
|
||||
color:@default-icon;
|
||||
}
|
||||
.JobSubmission-stepsContainer {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
margin-top: 25px;
|
||||
}
|
||||
.JobSubmission-steps {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
min-height: 30px;
|
||||
}
|
||||
.JobSubmission-step {
|
||||
color: @default-interface-txt;
|
||||
background-color: @default-bg;
|
||||
font-size: 12px;
|
||||
border: 1px solid @default-border;
|
||||
height: 30px;
|
||||
border-radius: 5px;
|
||||
margin-right: 20px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
transition: background-color 0.2s;
|
||||
text-transform: uppercase;
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.JobSubmission-step:hover {
|
||||
color: @btn-txt;
|
||||
background-color: @btn-bg-hov;
|
||||
cursor: pointer;
|
||||
}
|
||||
.JobSubmission-step--active {
|
||||
color: @default-bg!important;
|
||||
background-color: @default-icon!important;
|
||||
border-color: @default-icon!important;
|
||||
cursor: default!important;
|
||||
}
|
||||
.JobSubmission-step--disabled {
|
||||
opacity: 0.65;
|
||||
cursor: not-allowed!important;
|
||||
}
|
||||
.JobSubmission-formContainer {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
.JobSubmission-form {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
max-width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
.JobSubmission-footerContainer {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
margin-top: 15px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.JobSubmission-footerPreview {
|
||||
display: flex;
|
||||
}
|
||||
.JobSubmission-footerButtons {
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.JobSubmission-previewItem {
|
||||
min-width: 150px;
|
||||
font-weight: normal;
|
||||
font-size: small;
|
||||
}
|
||||
.JobSubmission-previewItemTitle, .JobSubmission-previewItemSubTitle, .JobSubmission-selectedItemInfoSubTitle {
|
||||
color: @default-interface-txt;
|
||||
}
|
||||
.JobSubmission-previewItemNone {
|
||||
color: @default-icon;
|
||||
}
|
||||
.JobSubmission-actionButton {
|
||||
background-color: @submit-button-bg;
|
||||
color: @submit-button-text;
|
||||
height: 30px;
|
||||
padding-left:15px;
|
||||
padding-right: 15px;
|
||||
width: 85px;
|
||||
}
|
||||
.JobSubmission-actionButton:hover,
|
||||
.JobSubmission-actionButton:focus {
|
||||
color: @submit-button-text;
|
||||
background-color: @submit-button-bg-hov;
|
||||
}
|
||||
.JobSubmission-defaultButton{
|
||||
background-color: @default-bg;
|
||||
color: @btn-txt;
|
||||
text-transform: uppercase;
|
||||
border-radius: 5px;
|
||||
border: 1px solid @btn-bord;
|
||||
padding-left:15px;
|
||||
padding-right: 15px;
|
||||
height: 30px;
|
||||
min-width: 85px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.JobSubmission-defaultButton:hover{
|
||||
background-color: @btn-bg-hov;
|
||||
color: @btn-txt;
|
||||
}
|
||||
|
||||
.JobSubmission-revertLink {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.JobSubmission-selectedItem {
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
margin-bottom: 15px;
|
||||
align-items: baseline;
|
||||
}
|
||||
.JobSubmission-selectedItemInfo {
|
||||
display: flex;
|
||||
flex: 0 0 100%;
|
||||
background-color: @default-no-items-bord;
|
||||
border: 1px solid @default-border;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
max-height: 120px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.JobSubmission-selectedItemRevert {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.JobSubmission-credentialSubSection {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.JobSubmission-selectedItemLabel, .JobSubmission-label {
|
||||
color: @default-interface-txt;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.JobSubmission-label {
|
||||
line-height: 24px;
|
||||
}
|
||||
.JobSubmission-selectedItemNone {
|
||||
color: @default-icon;
|
||||
}
|
||||
.JobSubmission-selectedItemContainer {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
.JobSubmission-instructions {
|
||||
color: @default-interface-txt;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.JobSubmission-passwordButton {
|
||||
padding: 5px 13px!important;
|
||||
}
|
||||
.JobSubmission .List-noItems {
|
||||
margin-top: auto;
|
||||
}
|
||||
.JobSubmission-selectedItemLabel {
|
||||
flex: 0 0 80px;
|
||||
line-height: 29px;
|
||||
}
|
||||
.JobSubmission-previewTags--outer {
|
||||
flex: 1 0 auto;
|
||||
max-width: ~"calc(100% - 140px)";
|
||||
}
|
||||
.JobSubmission-previewTags--inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.JobSubmission-previewTagLabel {
|
||||
color: @default-interface-txt;
|
||||
}
|
||||
.JobSubmission-previewTagLabel--deletable{
|
||||
color: @default-list-header-bg;
|
||||
}
|
||||
.JobSubmission-previewTagRevert {
|
||||
flex: 0 0 60px;
|
||||
line-height: 29px;
|
||||
}
|
||||
.JobSubmission-previewTagContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.JobSubmission-credentialSubSection .select2 {
|
||||
width: 50% !important;
|
||||
}
|
||||
@ -1,584 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name controllers.function:JobSubmission
|
||||
* @description This controller's for the Job Submission Modal
|
||||
* The job-submission directive is intended to handle job launch/relaunch from a playbook. There are 4 potential steps involved in launching a job:
|
||||
*
|
||||
* Select an Inventory
|
||||
* Select a Credential
|
||||
* Extra prompts (extra vars, limit, job type, job tags)
|
||||
* Fill in survey
|
||||
*
|
||||
* #Workflow when user hits launch button
|
||||
*
|
||||
* A 'get' call is made to the API's 'job_templates/:job_template_id/launch' endpoint for that job template. The response from the API will specify
|
||||
*
|
||||
*```
|
||||
* "credential_needed_to_start": true,
|
||||
* "can_start_without_user_input": false,
|
||||
* "ask_variables_on_launch": false,
|
||||
* "passwords_needed_to_start": [],
|
||||
* "variables_needed_to_start": [],
|
||||
* "survey_enabled": false
|
||||
*```
|
||||
* #Step 1 - Hit the launch/relaunch endpoint
|
||||
*
|
||||
* The launch/relaunch endpoint(s) let us know what the default values are for a particular job template. It also lets us know what the creator of
|
||||
* the job template selected as "promptable" fields.
|
||||
*
|
||||
* #Step 2 - Gather inv/credential lists and job template survey questions
|
||||
*
|
||||
* If the job template allows for inventory or credential prompting then we need to go out and get the available inventories and credentials for the
|
||||
* launching user. We also go out and get the survey from its endpoint if a survey has been created and is enabled for this job template (getsurveyquestions.factory).
|
||||
*
|
||||
* #Step 3 - Fill out the job launch form
|
||||
*
|
||||
* No server calls needed as a user fills out the form. Note that if no user input is required (no prompts, no passwords) then we skip ahead to the next
|
||||
* step.
|
||||
*
|
||||
* #Step 4 - Launch the job: LaunchJob
|
||||
*
|
||||
* This is maybe the most crucial step. We have setup everything we need in order to gather information from the user and now we want to be sure
|
||||
* we handle it correctly. And there are many scenarios to take into account. The first scenario we check for is is ``survey_enabled=true`` and
|
||||
* ``prompt_for_vars=false``, in which case we want to make sure to include the extra_vars from the job template in the data being
|
||||
* sent to the API (it is important to note that anything specified in the extra vars on job submission will override vars specified in the job template.
|
||||
* Likewise, any variables specified in the extra vars that are duplicated by the survey vars, will get overridden by the survey vars).
|
||||
* If the previous scenario is NOT the case, then we continue to gather the modal's answers regularly: gather the passwords, then the extra_vars, then
|
||||
* any survey results. Also note that we must gather any required survey answers, as well as any optional survey answers that happened to be provided
|
||||
* by the user. We also include the credential that was chosen if the user was prompted to select a credential.
|
||||
* At this point we have all the info we need and we are almost ready to perform a POST to the '/launch' endpoint. We must lastly check
|
||||
* if the user was not prompted for anything and therefore we don't want to pass any extra_vars to the POST. Once this is done we
|
||||
* make the REST POST call and provide all the data to hte API. The response from the API will be the job ID, which is used to redirect the user
|
||||
* to the job detail page for that job run.
|
||||
*
|
||||
* @Usage
|
||||
* This is usage information.
|
||||
*/
|
||||
|
||||
export default
|
||||
[ '$scope', 'GetBasePath', 'Wait', 'Rest', 'ProcessErrors',
|
||||
'LaunchJob', '$state', 'InventoryList', 'CredentialList', 'ParseTypeChange',
|
||||
function($scope, GetBasePath, Wait, Rest, ProcessErrors,
|
||||
LaunchJob, $state, InventoryList, CredentialList, ParseTypeChange) {
|
||||
|
||||
var launch_url;
|
||||
|
||||
var clearRequiredPasswords = function() {
|
||||
$scope.ssh_password_required = false;
|
||||
$scope.ssh_key_unlock_required = false;
|
||||
$scope.become_password_required = false;
|
||||
|
||||
$scope.ssh_password = "";
|
||||
$scope.ssh_key_unlock = "";
|
||||
$scope.become_password = "";
|
||||
};
|
||||
|
||||
var launchJob = function() {
|
||||
LaunchJob({
|
||||
scope: $scope,
|
||||
url: launch_url,
|
||||
submitJobType: $scope.submitJobType,
|
||||
relaunchHostType: $scope.relaunchHostType
|
||||
});
|
||||
};
|
||||
|
||||
// This gets things started - goes out and hits the launch endpoint (based on launch/relaunch) and
|
||||
// prepares the form fields, defauts, etc.
|
||||
$scope.init = function() {
|
||||
$scope.forms = {};
|
||||
$scope.passwords = {};
|
||||
$scope.selected_credentials = {
|
||||
machine: null,
|
||||
extra: []
|
||||
};
|
||||
|
||||
// As of 3.0, the only place the user can relaunch a
|
||||
// playbook is on jobTemplates.edit (completed_jobs tab),
|
||||
// jobs, and jobResults $states.
|
||||
|
||||
if (!$scope.submitJobRelaunch) {
|
||||
if($scope.submitJobType && $scope.submitJobType === 'job_template') {
|
||||
launch_url = GetBasePath('job_templates') + $scope.submitJobId + '/launch/';
|
||||
}
|
||||
else if($scope.submitJobType && $scope.submitJobType === 'workflow_job_template') {
|
||||
launch_url = GetBasePath('workflow_job_templates') + $scope.submitJobId + '/launch/';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($scope.submitJobType && $scope.submitJobType === 'workflow_job') {
|
||||
launch_url = GetBasePath('workflow_jobs') + $scope.submitJobId + '/relaunch/';
|
||||
}
|
||||
else {
|
||||
launch_url = GetBasePath('jobs') + $scope.submitJobId + '/relaunch/';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch('selected_credentials.machine', function(){
|
||||
if($scope.selected_credentials.machine) {
|
||||
if($scope.selected_credentials.machine.id === $scope.defaults.credential.id) {
|
||||
clearRequiredPasswords();
|
||||
for(var i=0; i<$scope.passwords_needed_to_start.length; i++) {
|
||||
var password = $scope.passwords_needed_to_start[i];
|
||||
switch(password) {
|
||||
case "ssh_password":
|
||||
$scope.ssh_password_required = true;
|
||||
break;
|
||||
case "ssh_key_unlock":
|
||||
$scope.ssh_key_unlock_required = true;
|
||||
break;
|
||||
case "become_password":
|
||||
$scope.become_password_required = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$scope.ssh_password_required = ($scope.selected_credentials.machine.inputs && $scope.selected_credentials.machine.inputs.password === "ASK") ? true : false;
|
||||
$scope.ssh_key_unlock_required = ($scope.selected_credentials.machine.inputs && $scope.selected_credentials.machine.inputs.ssh_key_unlock === "ASK") ? true : false;
|
||||
$scope.become_password_required = $scope.selected_credentials.machine.inputs && ($scope.selected_credentials.machine.inputs.become_password === "ASK") ? true : false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
clearRequiredPasswords();
|
||||
}
|
||||
});
|
||||
|
||||
// Get the job or job_template record
|
||||
Wait('start');
|
||||
Rest.setUrl(launch_url);
|
||||
Rest.get()
|
||||
.then(({data}) => {
|
||||
|
||||
// Put all the data that we get back about the launch onto scope
|
||||
angular.extend($scope, data);
|
||||
|
||||
// General catch-all for "other prompts" - used in this link function and to hide the Other Prompts tab when
|
||||
// it should be hidden
|
||||
$scope.has_other_prompts = (data.ask_verbosity_on_launch || data.ask_job_type_on_launch || data.ask_limit_on_launch || data.ask_tags_on_launch || data.ask_skip_tags_on_launch || data.ask_variables_on_launch || data.ask_diff_mode_on_launch) ? true : false;
|
||||
$scope.password_needed = data.passwords_needed_to_start && data.passwords_needed_to_start.length > 0;
|
||||
$scope.has_default_inventory = data.defaults && data.defaults.inventory && data.defaults.inventory.id;
|
||||
$scope.has_default_credential = data.defaults && data.defaults.credential && data.defaults.credential.id;
|
||||
$scope.has_default_vault_credential = data.defaults && data.defaults.vault_credential && data.defaults.vault_credential.id;
|
||||
$scope.vault_password_required = ($scope.password_needed && data.passwords_needed_to_start.includes('vault_password'));
|
||||
$scope.has_default_extra_credentials = data.defaults && data.defaults.extra_credentials && data.defaults.extra_credentials.length > 0;
|
||||
|
||||
$scope.other_prompt_data = {};
|
||||
|
||||
let getChoices = (options, lookup) => {
|
||||
return _.get(options, lookup, []).map(c => ({label: c[1], value: c[0]}));
|
||||
};
|
||||
|
||||
let getChoiceFromValue = (choices, value) => {
|
||||
return _.find(choices, item => item.value === value);
|
||||
};
|
||||
|
||||
if ($scope.has_other_prompts) {
|
||||
Rest.options()
|
||||
.then(options => {
|
||||
if ($scope.ask_job_type_on_launch) {
|
||||
let choices = getChoices(options.data, 'actions.POST.job_type.choices');
|
||||
let initialValue = _.get(data, 'defaults.job_type');
|
||||
let initialChoice = getChoiceFromValue(choices, initialValue);
|
||||
$scope.other_prompt_data.job_type_options = choices;
|
||||
$scope.other_prompt_data.job_type = initialChoice;
|
||||
}
|
||||
if ($scope.ask_verbosity_on_launch) {
|
||||
let choices = getChoices(options.data, 'actions.POST.verbosity.choices');
|
||||
let initialValue = _.get(data, 'defaults.verbosity');
|
||||
let initialChoice = getChoiceFromValue(choices, initialValue);
|
||||
$scope.other_prompt_data.verbosity_options = choices;
|
||||
$scope.other_prompt_data.verbosity = initialChoice;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
ProcessErrors($scope, error.data, error.status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: `Failed to get ${launch_url}. OPTIONS status: ${error.status}`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if($scope.ask_limit_on_launch) {
|
||||
$scope.other_prompt_data.limit = (data.defaults && data.defaults.limit) ? data.defaults.limit : "";
|
||||
}
|
||||
|
||||
if($scope.ask_tags_on_launch) {
|
||||
$scope.other_prompt_data.job_tags_options = (data.defaults && data.defaults.job_tags) ? data.defaults.job_tags.split(',')
|
||||
.map((i) => ({name: i, label: i, value: i})) : [];
|
||||
$scope.other_prompt_data.job_tags = $scope.other_prompt_data.job_tags_options;
|
||||
}
|
||||
|
||||
if($scope.ask_skip_tags_on_launch) {
|
||||
$scope.other_prompt_data.skip_tags_options = (data.defaults && data.defaults.skip_tags) ? data.defaults.skip_tags.split(',')
|
||||
.map((i) => ({name: i, label: i, value: i})) : [];
|
||||
$scope.other_prompt_data.skip_tags = $scope.other_prompt_data.skip_tags_options;
|
||||
}
|
||||
|
||||
if($scope.ask_diff_mode_on_launch) {
|
||||
$scope.other_prompt_data.diff_mode = (data.defaults && data.defaults.diff_mode) ? data.defaults.diff_mode : false;
|
||||
}
|
||||
|
||||
if($scope.ask_variables_on_launch) {
|
||||
$scope.jobLaunchVariables = (data.defaults && data.defaults.extra_vars) ? data.defaults.extra_vars : "---";
|
||||
$scope.other_prompt_data.parseType = 'yaml';
|
||||
$scope.parseType = 'yaml';
|
||||
}
|
||||
|
||||
if($scope.has_default_inventory) {
|
||||
$scope.selected_inventory = angular.copy($scope.defaults.inventory);
|
||||
}
|
||||
|
||||
if($scope.has_default_credential) {
|
||||
$scope.selected_credentials.machine = angular.copy($scope.defaults.credential);
|
||||
}
|
||||
|
||||
if($scope.has_default_vault_credential) {
|
||||
$scope.selected_credentials.vault = angular.copy($scope.defaults.vault_credential);
|
||||
}
|
||||
|
||||
if($scope.has_default_extra_credentials) {
|
||||
$scope.selected_credentials.extra = angular.copy($scope.defaults.extra_credentials);
|
||||
}
|
||||
|
||||
if( ($scope.submitJobType === 'workflow_job_template' && !$scope.survey_enabled) || ($scope.submitJobRelaunch && !$scope.password_needed) || (!$scope.submitJobRelaunch && $scope.can_start_without_user_input && !$scope.ask_inventory_on_launch && !$scope.ask_credential_on_launch && !$scope.has_other_prompts && !$scope.survey_enabled)) {
|
||||
// The job can be launched if
|
||||
// a) It's a relaunch and no passwords are needed
|
||||
// or
|
||||
// b) It's not a relaunch and there's not any prompting/surveys
|
||||
launchJob();
|
||||
Wait('stop');
|
||||
}
|
||||
else {
|
||||
|
||||
var initiateModal = function() {
|
||||
|
||||
// Go out and get the credential types
|
||||
Rest.setUrl(GetBasePath('credential_types'));
|
||||
Rest.get()
|
||||
.then( (response) => {
|
||||
let credentialTypeData = response.data;
|
||||
let credential_types = {};
|
||||
$scope.credentialTypeOptions = [];
|
||||
credentialTypeData.results.forEach((credentialType => {
|
||||
credential_types[credentialType.id] = credentialType;
|
||||
if(credentialType.kind.match(/^(machine|cloud|net|ssh)$/)) {
|
||||
$scope.credentialTypeOptions.push({
|
||||
name: credentialType.name,
|
||||
value: credentialType.id
|
||||
});
|
||||
}
|
||||
}));
|
||||
$scope.credential_types = credential_types;
|
||||
})
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get credential types. GET status: ' + status
|
||||
});
|
||||
});
|
||||
|
||||
// Figure out which step the user needs to start on
|
||||
if($scope.ask_inventory_on_launch) {
|
||||
$scope.setStep("inventory", true);
|
||||
}
|
||||
else if($scope.ask_credential_on_launch || $scope.password_needed) {
|
||||
$scope.setStep("credential", true);
|
||||
}
|
||||
else if($scope.has_other_prompts) {
|
||||
$scope.setStep("otherprompts", true);
|
||||
}
|
||||
else if($scope.survey_enabled) {
|
||||
$scope.setStep("survey", true);
|
||||
}
|
||||
|
||||
$scope.openLaunchModal();
|
||||
};
|
||||
|
||||
if($scope.submitJobRelaunch) {
|
||||
// Go out and get some of the job details like inv, cred, name
|
||||
Rest.setUrl(GetBasePath('jobs') + $scope.submitJobId);
|
||||
Rest.get()
|
||||
.then( (response) => {
|
||||
let jobResultData = response.data;
|
||||
$scope.job_template_data = {
|
||||
name: jobResultData.name
|
||||
};
|
||||
$scope.defaults = {};
|
||||
if(jobResultData.summary_fields.inventory) {
|
||||
$scope.defaults.inventory = angular.copy(jobResultData.summary_fields.inventory);
|
||||
$scope.selected_inventory = angular.copy(jobResultData.summary_fields.inventory);
|
||||
}
|
||||
if(jobResultData.summary_fields.credential) {
|
||||
$scope.defaults.credential = angular.copy(jobResultData.summary_fields.credential);
|
||||
$scope.selected_credentials.machine = angular.copy(jobResultData.summary_fields.credential);
|
||||
}
|
||||
initiateModal();
|
||||
})
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get job details. GET returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Move forward with the modal
|
||||
initiateModal();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get job template details. GET returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setStep = function(step, initialStep) {
|
||||
$scope.step = step;
|
||||
|
||||
if(step === "credential") {
|
||||
$scope.credentialTabEnabled = true;
|
||||
}
|
||||
else if(step === "otherprompts") {
|
||||
$scope.otherPromptsTabEnabled = true;
|
||||
|
||||
if(!initialStep && $scope.step === 'otherprompts' && $scope.ask_variables_on_launch && !$scope.extra_vars_code_mirror_loaded) {
|
||||
ParseTypeChange({
|
||||
scope: $scope,
|
||||
variable: 'jobLaunchVariables',
|
||||
field_id: 'job_launch_variables'
|
||||
});
|
||||
|
||||
$scope.extra_vars_code_mirror_loaded = true;
|
||||
}
|
||||
}
|
||||
else if(step === "survey") {
|
||||
$scope.surveyTabEnabled = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.revertToDefaultInventory = function() {
|
||||
if($scope.has_default_inventory) {
|
||||
$scope.selected_inventory = angular.copy($scope.defaults.inventory);
|
||||
}
|
||||
else {
|
||||
$scope.selected_inventory = null;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.revertToDefaultCredentials = function() {
|
||||
if($scope.has_default_credential) {
|
||||
$scope.selected_credentials.machine = angular.copy($scope.defaults.credential);
|
||||
}
|
||||
else {
|
||||
$scope.selected_credentials.machine = null;
|
||||
}
|
||||
if($scope.has_default_vault_credential) {
|
||||
$scope.selected_credentials.vault = angular.copy($scope.defaults.vault_credential);
|
||||
}
|
||||
else {
|
||||
$scope.selected_credentials.vault = null;
|
||||
}
|
||||
if($scope.has_default_extra_credentials) {
|
||||
$scope.selected_credentials.extra = angular.copy($scope.defaults.extra_credentials);
|
||||
}
|
||||
else {
|
||||
$scope.selected_credentials.extra = [];
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggle_credential = function(cred) {
|
||||
$scope.credentials.forEach(function(row, i) {
|
||||
if (row.id === cred.id) {
|
||||
$scope.selected_credentials.machine = angular.copy(row);
|
||||
$scope.credentials[i].checked = 1;
|
||||
} else {
|
||||
$scope.credentials[i].checked = 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.getActionButtonText = function() {
|
||||
if($scope.step === "inventory") {
|
||||
return ($scope.ask_credential_on_launch || $scope.password_needed || $scope.has_other_prompts || $scope.survey_enabled) ? "NEXT" : "LAUNCH";
|
||||
}
|
||||
else if($scope.step === "credential") {
|
||||
return ($scope.has_other_prompts || $scope.survey_enabled) ? "NEXT" : "LAUNCH";
|
||||
}
|
||||
else if($scope.step === "otherprompts") {
|
||||
return ($scope.survey_enabled) ? "NEXT" : "LAUNCH";
|
||||
}
|
||||
else if($scope.step === "survey") {
|
||||
return "LAUNCH";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.actionButtonDisabled = function() {
|
||||
if($scope.step === "inventory") {
|
||||
if($scope.selected_inventory) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$scope.credentialTabEnabled = false;
|
||||
$scope.otherPromptsTabEnabled = false;
|
||||
$scope.surveyTabEnabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if($scope.step === "credential") {
|
||||
if(($scope.selected_credentials.machine || $scope.selected_credentials.vault) && $scope.forms.credentialpasswords && $scope.forms.credentialpasswords.$valid) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$scope.otherPromptsTabEnabled = false;
|
||||
$scope.surveyTabEnabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if($scope.step === "otherprompts") {
|
||||
if($scope.forms.otherprompts.$valid) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$scope.surveyTabEnabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if($scope.step === "survey") {
|
||||
if($scope.forms.survey.$valid) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.takeAction = function() {
|
||||
if($scope.step === "inventory") {
|
||||
// Check to see if there's another step after this one
|
||||
if($scope.ask_credential_on_launch || $scope.password_needed) {
|
||||
$scope.setStep("credential");
|
||||
}
|
||||
else if($scope.has_other_prompts) {
|
||||
$scope.setStep("otherprompts");
|
||||
}
|
||||
else if($scope.survey_enabled) {
|
||||
$scope.setStep("survey");
|
||||
}
|
||||
else {
|
||||
launchJob();
|
||||
}
|
||||
}
|
||||
else if($scope.step === "credential") {
|
||||
if($scope.has_other_prompts) {
|
||||
$scope.setStep("otherprompts");
|
||||
}
|
||||
else if($scope.survey_enabled) {
|
||||
$scope.setStep("survey");
|
||||
}
|
||||
else {
|
||||
launchJob();
|
||||
}
|
||||
}
|
||||
else if($scope.step === "otherprompts") {
|
||||
if($scope.survey_enabled) {
|
||||
$scope.setStep("survey");
|
||||
}
|
||||
else {
|
||||
launchJob();
|
||||
}
|
||||
}
|
||||
else {
|
||||
launchJob();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleForm = function(key) {
|
||||
$scope.other_prompt_data[key] = !$scope.other_prompt_data[key];
|
||||
};
|
||||
|
||||
$scope.updateParseType = function() {
|
||||
// This is what the ParseTypeChange factory is expecting
|
||||
// It shares the same scope with this directive and will
|
||||
// pull the new value of parseType out to determine which
|
||||
// direction to convert the extra vars
|
||||
|
||||
$scope.parseType = $scope.other_prompt_data.parseType;
|
||||
$scope.parseTypeChange('parseType', 'jobLaunchVariables');
|
||||
};
|
||||
|
||||
$scope.showRevertCredentials = function(){
|
||||
let machineCredentialMatches = true;
|
||||
let extraCredentialsMatch = true;
|
||||
|
||||
if($scope.defaults.credential && $scope.defaults.credential.id) {
|
||||
if(!$scope.selected_credentials.machine || ($scope.selected_credentials.machine && $scope.selected_credentials.machine.id !== $scope.defaults.credential.id)) {
|
||||
machineCredentialMatches = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($scope.selected_credentials.machine && $scope.selected_credentials.machine.id) {
|
||||
machineCredentialMatches = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($scope.defaults.extra_credentials && $scope.defaults.extra_credentials.length > 0) {
|
||||
if($scope.selected_credentials.extra && $scope.selected_credentials.extra.length > 0) {
|
||||
if($scope.defaults.extra_credentials.length !== $scope.selected_credentials.extra.length) {
|
||||
extraCredentialsMatch = false;
|
||||
}
|
||||
else {
|
||||
$scope.defaults.extra_credentials.forEach((defaultExtraCredential) =>{
|
||||
let matchesSelected = false;
|
||||
$scope.selected_credentials.extra.forEach((selectedExtraCredential) =>{
|
||||
if(defaultExtraCredential.id === selectedExtraCredential.id) {
|
||||
matchesSelected = true;
|
||||
}
|
||||
});
|
||||
if(!matchesSelected) {
|
||||
extraCredentialsMatch = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
extraCredentialsMatch = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if($scope.selected_credentials.extra && $scope.selected_credentials.extra.length > 0) {
|
||||
extraCredentialsMatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
return machineCredentialMatches && extraCredentialsMatch ? false : true;
|
||||
};
|
||||
|
||||
$scope.$on('inventorySelected', function(evt, selectedRow){
|
||||
$scope.selected_inventory = _.cloneDeep(selectedRow);
|
||||
});
|
||||
|
||||
$scope.deleteMachineCred = function() {
|
||||
$scope.selected_credentials.machine = null;
|
||||
};
|
||||
|
||||
$scope.deleteExtraCred = function(index) {
|
||||
$scope.selected_credentials.extra.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.deleteSelectedInventory = function() {
|
||||
$scope.selected_inventory = null;
|
||||
};
|
||||
|
||||
}
|
||||
];
|
||||
@ -1,144 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import jobSubmissionController from './job-submission.controller';
|
||||
|
||||
export default [ 'templateUrl', 'CreateDialog', 'Wait', 'CreateSelect2', 'ParseTypeChange', 'GetSurveyQuestions', 'i18n', 'credentialTypesLookup', '$transitions',
|
||||
function(templateUrl, CreateDialog, Wait, CreateSelect2, ParseTypeChange, GetSurveyQuestions, i18n, credentialTypesLookup, $transitions) {
|
||||
return {
|
||||
scope: {
|
||||
submitJobId: '=',
|
||||
submitJobType: '@',
|
||||
submitJobRelaunch: '=',
|
||||
relaunchHostType: '@'
|
||||
},
|
||||
templateUrl: templateUrl('job-submission/job-submission'),
|
||||
controller: jobSubmissionController,
|
||||
restrict: 'E',
|
||||
link: function(scope) {
|
||||
|
||||
scope.openLaunchModal = function() {
|
||||
if (scope.removeLaunchJobModalReady) {
|
||||
scope.removeLaunchJobModalReady();
|
||||
}
|
||||
scope.removeLaunchJobModalReady = scope.$on('LaunchJobModalReady', function() {
|
||||
credentialTypesLookup()
|
||||
.then(kinds => {
|
||||
if(scope.ask_credential_on_launch) {
|
||||
scope.credentialKind = "" + kinds.ssh;
|
||||
scope.includeCredentialList = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Go get the list/survey data that we need from the server
|
||||
if(scope.ask_inventory_on_launch) {
|
||||
scope.includeInventoryList = true;
|
||||
}
|
||||
if(scope.survey_enabled) {
|
||||
GetSurveyQuestions({
|
||||
scope: scope,
|
||||
id: scope.submitJobId,
|
||||
submitJobType: scope.submitJobType
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$('#job-launch-modal').dialog('open');
|
||||
|
||||
// select2-ify the job type dropdown
|
||||
CreateSelect2({
|
||||
element: '#job_launch_job_type',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#job_launch_verbosity',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: `#job-launch-credential-kind-select`,
|
||||
multiple: false,
|
||||
placeholder: i18n._('Select a credential')
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#job_launch_job_tags',
|
||||
multiple: true,
|
||||
addNew: true
|
||||
});
|
||||
|
||||
CreateSelect2({
|
||||
element: '#job_launch_skip_tags',
|
||||
multiple: true,
|
||||
addNew: true
|
||||
});
|
||||
|
||||
if(scope.step === 'otherprompts' && scope.ask_variables_on_launch) {
|
||||
ParseTypeChange({
|
||||
scope: scope,
|
||||
variable: 'jobLaunchVariables',
|
||||
field_id: 'job_launch_variables'
|
||||
});
|
||||
|
||||
scope.extra_vars_code_mirror_loaded = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
CreateDialog({
|
||||
id: 'job-launch-modal',
|
||||
scope: scope,
|
||||
width: 800,
|
||||
minWidth: 400,
|
||||
draggable: false,
|
||||
dialogClass: 'JobSubmission-dialog',
|
||||
onOpen: function() {
|
||||
Wait('stop');
|
||||
},
|
||||
callback: 'LaunchJobModalReady'
|
||||
});
|
||||
};
|
||||
|
||||
scope.clearDialog = function() {
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page
|
||||
$('#content-container').find('submit-job').remove();
|
||||
|
||||
// Clear out the scope (we'll create a new scope the next time
|
||||
// job launch is called)
|
||||
scope.$destroy();
|
||||
};
|
||||
|
||||
// This function is used to hide/show the contents of a password
|
||||
// within a form
|
||||
scope.togglePassword = function(id) {
|
||||
var buttonId = id + "_show_input_button",
|
||||
inputId = id,
|
||||
buttonInnerHTML = $(buttonId).html();
|
||||
if (buttonInnerHTML.indexOf("Show") > -1) {
|
||||
$(buttonId).html("Hide");
|
||||
$(inputId).attr("type", "text");
|
||||
} else {
|
||||
$(buttonId).html("Show");
|
||||
$(inputId).attr("type", "password");
|
||||
}
|
||||
};
|
||||
|
||||
$transitions.onStart({}, function() {
|
||||
scope.$evalAsync(function( scope ) {
|
||||
scope.clearDialog();
|
||||
});
|
||||
});
|
||||
|
||||
scope.init();
|
||||
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,375 +0,0 @@
|
||||
<div id="job-launch-modal" class="JobSubmission modal">
|
||||
<div class="JobSubmission-container">
|
||||
<div class="JobSubmission-header">
|
||||
<div class="JobSubmission-title">
|
||||
<div class="JobSubmission-titleText">
|
||||
<span translate>LAUNCH JOB</span>
|
||||
<div class="JobSubmission-titleLockup"></div>
|
||||
<span>{{job_template_data.name || workflow_job_template_data.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-close">
|
||||
<button class="JobSubmission-exit" ng-click="clearDialog()"><i class="fa fa-times-circle"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-stepsContainer">
|
||||
<div class="JobSubmission-steps">
|
||||
<div class="JobSubmission-step" ng-class="{'JobSubmission-step--active': step==='inventory'}" ng-if="ask_inventory_on_launch" ng-click="setStep('inventory')" translate>Inventory</div>
|
||||
<div class="JobSubmission-step" ng-class="{'JobSubmission-step--active': step==='credential', 'JobSubmission-step--disabled': !credentialTabEnabled}" ng-if="ask_credential_on_launch || password_needed" ng-click="!credentialTabEnabled || setStep('credential')" translate>Credential</div>
|
||||
<div class="JobSubmission-step" ng-class="{'JobSubmission-step--active': step==='otherprompts', 'JobSubmission-step--disabled': !otherPromptsTabEnabled}" ng-if="has_other_prompts" ng-click="!otherPromptsTabEnabled || setStep('otherprompts')" translate>Other Prompts</div>
|
||||
<div class="JobSubmission-step" ng-class="{'JobSubmission-step--active': step==='survey', 'JobSubmission-step--disabled': !surveyTabEnabled}" ng-if="survey_enabled" ng-click="!surveyTabEnabled || setStep('survey')" translate>Survey</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-formContainer">
|
||||
<div ng-if="ask_inventory_on_launch" ng-show="step === 'inventory'" class="JobSubmission-form">
|
||||
<div class="JobSubmission-selectedItemContainer">
|
||||
<div class="JobSubmission-selectedItem">
|
||||
<div class="JobSubmission-selectedItemInfo" ng-hide="!selected_inventory">
|
||||
<div class="JobSubmission-selectedItemLabel">
|
||||
<span translate>SELECTED:</span>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTags--outer">
|
||||
<div class="JobSubmission-previewTags--inner">
|
||||
<div class="JobSubmission-previewTagContainer">
|
||||
<div class="JobSubmission-previewTag JobSubmission-previewTag--deletable">
|
||||
<span>{{selected_inventory.name}}</span>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagContainerDelete" ng-click="deleteSelectedInventory()">
|
||||
<i class="fa fa-times JobSubmission-previewTagContainerTagDelete"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagRevert">
|
||||
<a class="JobSubmission-revertLink" href="" ng-hide="selected_inventory.id === defaults.inventory.id" ng-click="revertToDefaultInventory()" translate>REVERT</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<job-sub-inv-list ng-if="includeInventoryList" selected-inventory="$parent.selected_inventory"></job-sub-inv-list>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="ask_credential_on_launch || password_needed" ng-show="step === 'credential'" class="JobSubmission-form">
|
||||
<div class="JobSubmission-selectedItemContainer">
|
||||
<div class="JobSubmission-selectedItem">
|
||||
<div class="JobSubmission-selectedItemInfo" ng-hide="!selected_credentials.machine && !selected_credentials.vault && selected_credentials.extra.length === 0">
|
||||
<div class="JobSubmission-selectedItemLabel">
|
||||
<span translate>SELECTED:</span>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTags--outer">
|
||||
<div class="JobSubmission-previewTags--inner">
|
||||
<div class="JobSubmission-previewTagContainer u-wordwrap" ng-show="selected_credentials.machine">
|
||||
<div class="JobSubmission-previewTag" ng-class="{'JobSubmission-previewTag--deletable': ask_credential_on_launch}">
|
||||
<span><span class="JobSubmission-previewTagLabel" ng-class="{'JobSubmission-previewTagLabel--deletable': ask_credential_on_launch}">
|
||||
MACHINE</span>: {{selected_credentials.machine.name}}</span>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagContainerDelete" ng-click="deleteMachineCred()" ng-show="ask_credential_on_launch">
|
||||
<i class="fa fa-times JobSubmission-previewTagContainerTagDelete"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagContainer" ng-repeat="extraCredential in selected_credentials.extra">
|
||||
<div class="JobSubmission-previewTag" ng-class="{'JobSubmission-previewTag--deletable': ask_credential_on_launch}">
|
||||
<span><span class="JobSubmission-previewTagLabel" ng-class="{'JobSubmission-previewTagLabel--deletable': ask_credential_on_launch}">
|
||||
{{credential_types[extraCredential.credential_type].name | uppercase}}</span>: {{extraCredential.name}}</span>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagContainerDelete" ng-click="deleteExtraCred($index)" ng-show="ask_credential_on_launch">
|
||||
<i class="fa fa-times JobSubmission-previewTagContainerTagDelete"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagContainer JobSubmission-previewTagContainer--vault" ng-show="selected_credentials.vault">
|
||||
<div class="JobSubmission-previewTag JobSubmission-previewTag--vault" ng-class="{'JobSubmission-previewTag--deletable': ask_credential_on_launch}">
|
||||
<span><span class="JobSubmission-previewTagLabel" ng-class="{'JobSubmission-previewTagLabel--deletable': ask_credential_on_launch}">
|
||||
VAULT</span>: {{selected_credentials.vault.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-previewTagRevert" ng-if="ask_credential_on_launch">
|
||||
<a class="JobSubmission-revertLink" href="" ng-show="showRevertCredentials()" ng-click="revertToDefaultCredentials()" translate>REVERT</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-credentialSubSection" ng-show="ask_credential_on_launch">
|
||||
<span class="JobSubmission-label" translate>CREDENTIAL TYPE:</span>
|
||||
<select id="job-launch-credential-kind-select" ng-model="credentialKind">
|
||||
<option ng-repeat="option in credentialTypeOptions" value="{{option.value}}">{{option.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<job-sub-cred-list ng-if="includeCredentialList" selected-credentials="selected_credentials" credential-types="::credential_types" credential-kind="credentialKind"></job-sub-cred-list>
|
||||
<div ng-show="ssh_password_required || ssh_key_unlock_required || become_password_required || vault_password_required">
|
||||
<div class="JobSubmission-instructions" translate>Launching this job requires the passwords listed below. Enter and confirm each password before continuing.</div>
|
||||
<form name="forms.credentialpasswords" autocomplete="off" novalidate>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ssh_password_required">
|
||||
<label for="ssh_password" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Password</span>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn input-group-prepend">
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-password')" data-container="job-launch-modal" data-original-title="" title="" translate>Show</button>
|
||||
</span>
|
||||
<input id="job-submission-ssh-password" type="password" ng-model="passwords.ssh_password" name="ssh_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.ssh_password.$dirty && forms.credentialpasswords.ssh_password.$error.required" translate>Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="ssh_password_api_error"></div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ssh_key_unlock_required">
|
||||
<label for="ssh_key_unlock" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Private Key Passphrase</span>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn input-group-prepend">
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-key-unlock_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-key-unlock')" data-container="job-launch-modal" data-original-title="" title="" translate>Show</button>
|
||||
</span>
|
||||
<input id="job-submission-ssh-key-unlock" type="password" ng-model="passwords.ssh_key_unlock" name="ssh_key_unlock" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.ssh_key_unlock.$dirty && forms.credentialpasswords.ssh_key_unlock.$error.required" translate>Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="ssh_key_unlock_api_error"></div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="become_password_required">
|
||||
<label for="become_password" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Privilege Escalation Password</span>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn input-group-prepend">
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-become-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-become-password')" data-container="job-launch-modal" data-original-title="" title="" translate>Show</button>
|
||||
</span>
|
||||
<input id="job-submission-become-password" type="password" ng-model="passwords.become_password" name="become_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.become_password.$dirty && forms.credentialpasswords.become_password.$error.required" translate>Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="become_password_api_error"></div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="vault_password_required">
|
||||
<label for="vault_password" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Vault Password</span>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn input-group-prepend">
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-vault-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-vault-password')" data-container="job-launch-modal" data-original-title="" title="" translate>Show</button>
|
||||
</span>
|
||||
<input id="job-submission-vault-password" type="password" ng-model="passwords.vault_password" name="vault_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.vault_password.$dirty && forms.credentialpasswords.vault_password.$error.required" translate>Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="vault_password_api_error"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="has_other_prompts" ng-show="step === 'otherprompts'" class="JobSubmission-form">
|
||||
<form name="forms.otherprompts" autocomplete="off" novalidate>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_variables_on_launch">
|
||||
<label for="variables">
|
||||
<span class="Form-inputLabel" translate>Extra Variables</span>
|
||||
<a id="awp-variables" href="" aw-pop-over="<p>Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON.</p>JSON:<br /><blockquote>{<br />"somevar": "somevalue",<br />"password": "magic"<br /> }</blockquote>YAML:<br /><blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>" data-placement="right" data-container="body" over-title="Extra Variables" class="help-link" data-original-title="" title="" tabindex="-1">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
</a>
|
||||
<div class="parse-selection" id="job_launch_variables_parse_type">
|
||||
<input type="radio" ng-model="other_prompt_data.parseType" value="yaml" ng-change="updateParseType()">
|
||||
<span class="parse-label" translate>YAML</span>
|
||||
<input type="radio" ng-model="other_prompt_data.parseType" value="json" ng-change="updateParseType()">
|
||||
<span class="parse-label" translate>JSON</span>
|
||||
</div>
|
||||
</label>
|
||||
<div>
|
||||
<textarea rows="6" ng-model="other_prompt_data.extra_vars" name="variables" class="form-control Form-textArea Form-textAreaLabel" id="job_launch_variables" aw-watch=""></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_verbosity_on_launch">
|
||||
<label for="verbosity" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Verbosity</span>
|
||||
</label>
|
||||
<div>
|
||||
<select
|
||||
id="job_launch_verbosity"
|
||||
ng-options="v.label for v in other_prompt_data.verbosity_options track by v.value"
|
||||
ng-model="other_prompt_data.verbosity"
|
||||
class="form-control Form-dropDown"
|
||||
name="verbosity"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
required>
|
||||
<option value="" class="" selected="selected">Choose a verbosity</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_job_type_on_launch">
|
||||
<label for="job_type" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<span class="Form-inputLabel" translate> Job Type</span>
|
||||
</label>
|
||||
<div>
|
||||
<select
|
||||
id="job_launch_job_type"
|
||||
ng-options="v.label for v in other_prompt_data.job_type_options track by v.value"
|
||||
ng-model="other_prompt_data.job_type"
|
||||
class="form-control Form-dropDown"
|
||||
name="job_type"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
required>
|
||||
<option value="" class="" selected="selected">Choose a job type</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_limit_on_launch">
|
||||
<label for="limit">
|
||||
<span class="Form-inputLabel" translate>Limit</span>
|
||||
</label>
|
||||
<div>
|
||||
<input type="text" ng-model="other_prompt_data.limit" name="limit" class="form-control Form-textInput">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_tags_on_launch">
|
||||
<label for="tags">
|
||||
<span class="Form-inputLabel" translate>Job Tags</span>
|
||||
</label>
|
||||
<div>
|
||||
<select
|
||||
id="job_launch_job_tags"
|
||||
ng-options="v.label for v in other_prompt_data.job_tags_options track by v.value"
|
||||
ng-model="other_prompt_data.job_tags"
|
||||
class="form-control Form-dropDown"
|
||||
name="verbosity"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
multiple>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_skip_tags_on_launch">
|
||||
<label for="skip_tags">
|
||||
<span class="Form-inputLabel" translate>Skip Tags</span>
|
||||
</label>
|
||||
<div>
|
||||
<!-- <textarea rows="5" ng-model="other_prompt_data.skip_tags" name="skip_tags" class="form-control Form-textArea Form-textInput"></textarea> -->
|
||||
<select
|
||||
id="job_launch_skip_tags"
|
||||
ng-options="v.label for v in other_prompt_data.skip_tags_options track by v.value"
|
||||
ng-model="other_prompt_data.skip_tags"
|
||||
class="form-control Form-dropDown"
|
||||
name="verbosity"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
multiple>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="ask_diff_mode_on_launch">
|
||||
<label for="diff_mode">
|
||||
<span class="Form-inputLabel" translate>Diff Mode</span>
|
||||
</label>
|
||||
<div>
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': other_prompt_data.diff_mode}" aw-tool-tip="" data-placement="top" data-original-title="" title="">
|
||||
<button type="button" ng-show="other_prompt_data.diff_mode" class="ScheduleToggle-switch is-on" ng-click="toggleForm('diff_mode')"
|
||||
translate>ON</button>
|
||||
<button type="button" ng-show="!other_prompt_data.diff_mode" class="ScheduleToggle-switch ng-hide" ng-click="toggleForm('diff_mode')" translate>OFF</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div ng-if="survey_enabled" ng-show="step === 'survey'" class="JobSubmission-form">
|
||||
<form name="forms.survey" autocomplete="off" novalidate>
|
||||
<div ng-repeat="question in survey_questions" id="taker_'+question.index+'" class="form-group Form-formGroup Form-formGroup--singleColumn">
|
||||
<label ng-attr-for="{{question.variable}}" class="Form-inputLabelContainer">
|
||||
<span ng-show="question.required===true" class="Form-requiredAsterisk">*</span>
|
||||
<span class="label-text Form-inputLabel"> {{question.question_name}}</span>
|
||||
</label>
|
||||
|
||||
<div class="survey_taker_description" ng-if="question.question_description">
|
||||
<i ng-bind-html="question.question_description"></i>
|
||||
</div>
|
||||
<div ng-if="question.type === 'text'">
|
||||
<input type="text" id="survey_question_{{$index}}" ng-model="question.model" name="survey_question_{{$index}}" ng-minlength="question.minlength" ng-maxlength="question.maxlength" class="form-control Form-textInput" ng-required="question.required">
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$dirty && forms.survey.survey_question_{{$index}}.$error.required" translate>Please enter an answer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.minlength || forms.survey.survey_question_{{$index}}.$error.maxlength"><span translate>Please enter an answer between</span> {{question.minlength}} <span translate>to</span> {{question.maxlength}} <span translate>characters long.</span></div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'textarea'">
|
||||
<textarea id="survey_question_{{$index}}" name="survey_question_{{$index}}" ng-model="question.model" ng-minlength="question.minlength" ng-maxlength="question.maxlength" class="form-control final Form-textArea" ng-required="question.required" rows="3"></textarea>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$dirty && forms.survey.survey_question_{{$index}}.$error.required" translate>Please enter an answer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.minlength || forms.survey.survey_question_{{$index}}.$error.maxlength"><span translate>Please enter an answer between</span> {{question.minlength}} <span translate>to</span> {{question.maxlength}} <span translate>characters long.</span></div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'password'">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn input-group-prepend">
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="survey_question_{{$index}}_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#survey_question_' + $index)" data-original-title="" data-container="job-launch-modal" title="" translate>Show</button>
|
||||
</span>
|
||||
<input id="survey_question_{{$index}}" ng-if="!question.default" type="password" ng-model="question.model" name="survey_question_{{$index}}" ng-required="question.required" ng-minlength="question.minlength" ng-maxlength="question.maxlength" class="form-control Form-textInput" autocomplete="false">
|
||||
<input id="survey_question_{{$index}}" ng-if="question.default" type="password" ng-model="question.model" name="survey_question_{{$index}}" ng-required="question.required" aw-password-min="question.minlength" aw-password-max="question.maxlength" class="form-control Form-textInput" autocomplete="false">
|
||||
</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$dirty && forms.survey.survey_question_{{$index}}.$error.required" translate>Please enter an answer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.awPasswordMin || forms.survey.survey_question_{{$index}}.$error.awPasswordMax || forms.survey.survey_question_{{$index}}.$error.minlength || forms.survey.survey_question_{{$index}}.$error.maxlength"><span translate>Please enter an answer between</span> {{question.minlength}} <span translate>to</span> {{question.maxlength}} <span translate>characters long.</span></div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'integer'">
|
||||
<input type="number" id="survey_question_{{$index}}" ng-model="question.model" class="form-control Form-textInput" name="survey_question_{{$index}}" ng-required="question.required" integer aw-min="question.minValue" aw-max="question.maxValue"/>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$dirty && forms.survey.survey_question_{{$index}}.$error.required" translate>Please enter an answer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.number || forms.survey.survey_question_{{$index}}.$error.integer" translate>Please enter an answer that is a valid integer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.awMin || forms.survey.survey_question_{{$index}}.$error.awMax"><span translate>Please enter an answer between</span> {{question.minValue}} <span>and</span> {{question.maxValue}}.</div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'float'">
|
||||
<input type="number" id="survey_question_{{$index}}" ng-model="question.model" class="form-control Form-textInput" name="survey_question_{{$index}}" ng-required="question.required" smart-float aw-min="question.minValue" aw-max="question.maxValue"/>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$dirty && forms.survey.survey_question_{{$index}}.$error.required" translate>Please enter an answer.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.number || forms.survey.survey_question_{{$index}}.$error.float" translate>Please enter an answer that is a decimal number.</div>
|
||||
<div class="error survey_error" ng-show="forms.survey.survey_question_{{$index}}.$error.awMin || forms.survey.survey_question_{{$index}}.$error.awMax"><span translate>Please enter an answer between</span> {{question.minValue}} <span translate>and</span> {{question.maxValue}}.</div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'multiplechoice'">
|
||||
<div class="survey_taker_input">
|
||||
<multiple-choice
|
||||
multi-select="false"
|
||||
question="question"
|
||||
choices="question.choices"
|
||||
ng-required="question.required"
|
||||
ng-model="question.model">
|
||||
</multiple-choice>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="question.type === 'multiselect'">
|
||||
<multiple-choice
|
||||
multi-select="true"
|
||||
question="question"
|
||||
choices="question.choices"
|
||||
ng-required="question.required"
|
||||
ng-model="question.model">
|
||||
</multiple-choice>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-footerContainer">
|
||||
<div class="JobSubmission-footerPreview">
|
||||
<div class="JobSubmission-previewItem" ng-show="submitJobType === 'job_template'">
|
||||
<div class="JobSubmission-previewItemTitle" translate>INVENTORY</div>
|
||||
<div ng-show="selected_inventory" ng-bind="selected_inventory.name"></div>
|
||||
<div class="JobSubmission-previewItemNone" ng-show="!selected_inventory" translate>None selected</div>
|
||||
</div>
|
||||
<div class="JobSubmission-previewItem" ng-show="submitJobType === 'job_template'">
|
||||
<div class="JobSubmission-previewItemTitle" translate>CREDENTIAL</div>
|
||||
<div>
|
||||
<span ng-show="!selected_credentials.machine && !selected_credentials.vault && selected_credentials.extra.length === 0" class="JobSubmission-selectedItemNone" translate>None selected</span>
|
||||
</div>
|
||||
<div>
|
||||
<span ng-show="selected_credentials.machine" class="JobSubmission-previewItemSubTitle"><span translate>Machine</span>: </span>
|
||||
<span class="u-wordwrap" ng-show="selected_credentials.machine">{{selected_credentials.machine.name}}</span>
|
||||
</div>
|
||||
<div ng-repeat="extraCredential in selected_credentials.extra">
|
||||
<span class="JobSubmission-previewItemSubTitle">{{credential_types[extraCredential.credential_type].name}}: </span>
|
||||
<span class="u-wordwrap">{{extraCredential.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span ng-show="selected_credentials.vault" class="JobSubmission-previewItemSubTitle"><span translate>Vault</span>: </span>
|
||||
<span ng-show="selected_credentials.vault" class="u-wordwrap">{{selected_credentials.vault.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="JobSubmission-footerButtons">
|
||||
<button id="job-submission-close-button" class="btn btn-sm JobSubmission-defaultButton" ng-click="clearDialog()" translate>CANCEL</button>
|
||||
<button id="job-submission-action-button" class="btn btn-sm JobSubmission-actionButton" ng-click="takeAction()" ng-disabled="actionButtonDisabled()">{{getActionButtonText()}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,128 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
[ '$scope', 'CredentialList', 'i18n', 'QuerySet', 'GetBasePath', 'credentialTypesLookup',
|
||||
function($scope, CredentialList, i18n, qs, GetBasePath, credentialTypesLookup) {
|
||||
let credentialKinds = {};
|
||||
|
||||
let updateExtraCredentialsList = function() {
|
||||
$scope.credentials.forEach((row, i) => {
|
||||
$scope.credentials[i].checked = 0;
|
||||
$scope.selectedCredentials.extra.forEach((extraCredential, j) => {
|
||||
if (row.id === $scope.selectedCredentials.extra[j].id) {
|
||||
$scope.credentials[i].checked = 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
let updateMachineCredentialList = function() {
|
||||
$scope.credentials.forEach((row, i) => {
|
||||
$scope.credentials[i].checked = 0;
|
||||
if (row.id === $scope.selectedCredentials.machine.id) {
|
||||
$scope.credentials[i].checked = 1;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let uncheckAllCredentials = function() {
|
||||
$scope.credentials.forEach((row, i) => {
|
||||
$scope.credentials[i].checked = 0;
|
||||
});
|
||||
};
|
||||
|
||||
let init = function() {
|
||||
$scope.credential_dataset = [];
|
||||
$scope.credentials = [];
|
||||
$scope.listRendered = false;
|
||||
|
||||
let credList = _.cloneDeep(CredentialList);
|
||||
credList.emptyListText = i18n._('No Credentials Matching This Type Have Been Created');
|
||||
$scope.list = credList;
|
||||
|
||||
$scope.credential_default_params = {
|
||||
order_by: 'name',
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
$scope.credential_queryset = {
|
||||
order_by: 'name',
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
$scope.$watch('credentialKind', function(){
|
||||
$scope.credential_queryset.page = 1;
|
||||
$scope.credential_default_params.credential_type = $scope.credential_queryset.credential_type = parseInt($scope.credentialKind);
|
||||
|
||||
qs.search(GetBasePath('credentials'), $scope.credential_default_params)
|
||||
.then(res => {
|
||||
$scope.credential_dataset = res.data;
|
||||
$scope.credentials = $scope.credential_dataset.results;
|
||||
if(!$scope.listRendered) {
|
||||
$scope.generateCredentialList();
|
||||
$scope.listRendered = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$watchCollection('selectedCredentials.extra', () => {
|
||||
if($scope.credentials && $scope.credentials.length > 0) {
|
||||
if($scope.selectedCredentials.extra && $scope.selectedCredentials.extra.length > 0 && parseInt($scope.credentialKind) !== credentialKinds.ssh) {
|
||||
updateExtraCredentialsList();
|
||||
} else if (parseInt($scope.credentialKind) !== credentialKinds.ssh) {
|
||||
uncheckAllCredentials();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('selectedCredentials.machine', () => {
|
||||
if($scope.credentials && $scope.credentials.length > 0) {
|
||||
if($scope.selectedCredentials.machine && parseInt($scope.credentialKind) === credentialKinds.ssh) {
|
||||
updateMachineCredentialList();
|
||||
}
|
||||
else {
|
||||
uncheckAllCredentials();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watchGroup(['credentials', 'selectedCredentials.machine'], () => {
|
||||
if($scope.credentials && $scope.credentials.length > 0) {
|
||||
if($scope.selectedCredentials.machine && parseInt($scope.credentialKind) === credentialKinds.ssh) {
|
||||
updateMachineCredentialList();
|
||||
}
|
||||
else if($scope.selectedCredentials.extra && $scope.selectedCredentials.extra.length > 0 && parseInt($scope.credentialKind) !== credentialKinds.ssh) {
|
||||
updateExtraCredentialsList();
|
||||
}
|
||||
else {
|
||||
uncheckAllCredentials();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggle_row = function(selectedRow) {
|
||||
if(parseInt($scope.credentialKind) === credentialKinds.ssh) {
|
||||
$scope.selectedCredentials.machine = _.cloneDeep(selectedRow);
|
||||
}
|
||||
else {
|
||||
for (let i = $scope.selectedCredentials.extra.length - 1; i >= 0; i--) {
|
||||
if(selectedRow.credential_type === $scope.selectedCredentials.extra[i].credential_type) {
|
||||
$scope.selectedCredentials.extra.splice(i, 1);
|
||||
}
|
||||
}
|
||||
$scope.selectedCredentials.extra.push(_.cloneDeep(selectedRow));
|
||||
}
|
||||
};
|
||||
|
||||
credentialTypesLookup()
|
||||
.then(kinds => {
|
||||
credentialKinds = kinds;
|
||||
init();
|
||||
});
|
||||
}
|
||||
];
|
||||
@ -1,31 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import jobSubCredListController from './job-sub-cred-list.controller';
|
||||
|
||||
export default [ 'templateUrl', '$compile', 'generateList',
|
||||
(templateUrl, $compile, GenerateList) => {
|
||||
return {
|
||||
scope: {
|
||||
selectedCredentials: '=',
|
||||
credentialKind: '=',
|
||||
credentialTypes: '='
|
||||
},
|
||||
templateUrl: templateUrl('job-submission/lists/credential/job-sub-cred-list'),
|
||||
controller: jobSubCredListController,
|
||||
restrict: 'E',
|
||||
link: scope => {
|
||||
scope.generateCredentialList = function() {
|
||||
let html = GenerateList.build({
|
||||
list: scope.list,
|
||||
input_type: 'radio',
|
||||
mode: 'lookup'
|
||||
});
|
||||
$('#job-submission-credential-lookup').append($compile(html)(scope));
|
||||
};
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,3 +0,0 @@
|
||||
<div>
|
||||
<div id="job-submission-credential-lookup"></div>
|
||||
</div>
|
||||
@ -1,63 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2017 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default
|
||||
[ '$scope',
|
||||
function($scope) {
|
||||
|
||||
let updateInventoryList = function() {
|
||||
$scope.inventories.forEach((row, i) => {
|
||||
$scope.inventories[i].checked = 0;
|
||||
if (row.id === $scope.selectedInventory.id) {
|
||||
$scope.inventories[i].checked = 1;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let uncheckAllInventories = function() {
|
||||
$scope.inventories.forEach((row, i) => {
|
||||
$scope.inventories[i].checked = 0;
|
||||
});
|
||||
};
|
||||
|
||||
let init = function() {
|
||||
$scope.$watch('selectedInventory', () => {
|
||||
if($scope.inventories && $scope.inventories.length > 0) {
|
||||
if($scope.selectedInventory) {
|
||||
updateInventoryList();
|
||||
}
|
||||
else {
|
||||
uncheckAllInventories();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
$scope.toggle_row = function(selectedRow) {
|
||||
let list = $scope.list;
|
||||
let count = 0;
|
||||
$scope[list.name].forEach(function(row) {
|
||||
if (row.id === selectedRow.id) {
|
||||
if (row.checked) {
|
||||
row.success_class = 'success';
|
||||
} else {
|
||||
row.checked = 1;
|
||||
row.success_class = '';
|
||||
}
|
||||
$scope.$emit('inventorySelected', row);
|
||||
} else {
|
||||
row.checked = 0;
|
||||
row.success_class = '';
|
||||
}
|
||||
if (row.checked) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
];
|
||||
@ -1,66 +0,0 @@
|
||||
/*************************************************
|
||||
* Copyright (c) 2016 Ansible, Inc.
|
||||
*
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
import jobSubInvListController from './job-sub-inv-list.controller';
|
||||
|
||||
export default [ 'templateUrl', 'QuerySet', 'GetBasePath', 'generateList', '$compile', 'InventoryList',
|
||||
(templateUrl, qs, GetBasePath, GenerateList, $compile, InventoryList) => {
|
||||
return {
|
||||
scope: {
|
||||
selectedInventory: '='
|
||||
},
|
||||
templateUrl: templateUrl('job-submission/lists/inventory/job-sub-inv-list'),
|
||||
controller: jobSubInvListController,
|
||||
restrict: 'E',
|
||||
link: scope => {
|
||||
let toDestroy = [];
|
||||
|
||||
scope.inventory_default_params = {
|
||||
order_by: 'name',
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
scope.inventory_queryset = {
|
||||
order_by: 'name',
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
// Fire off the initial search
|
||||
qs.search(GetBasePath('inventory'), scope.inventory_default_params)
|
||||
.then(res => {
|
||||
scope.inventory_dataset = res.data;
|
||||
scope.inventories = scope.inventory_dataset.results;
|
||||
|
||||
let invList = _.cloneDeep(InventoryList);
|
||||
let html = GenerateList.build({
|
||||
list: invList,
|
||||
input_type: 'radio',
|
||||
mode: 'lookup'
|
||||
});
|
||||
|
||||
scope.list = invList;
|
||||
|
||||
$('#job-submission-inventory-lookup').append($compile(html)(scope));
|
||||
|
||||
toDestroy.push(scope.$watchCollection('selectedInventory', () => {
|
||||
if(scope.selectedInventory) {
|
||||
// Loop across the inventories and see if one of them should be "checked"
|
||||
scope.inventories.forEach((row, i) => {
|
||||
if (row.id === scope.selectedInventory.id) {
|
||||
scope.inventories[i].checked = 1;
|
||||
}
|
||||
else {
|
||||
scope.inventories[i].checked = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
scope.$on('$destroy', () => toDestroy.forEach(watcher => watcher()));
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -1,3 +0,0 @@
|
||||
<div>
|
||||
<div id="job-submission-inventory-lookup"></div>
|
||||
</div>
|
||||
@ -5,31 +5,23 @@
|
||||
*************************************************/
|
||||
|
||||
import LaunchJob from './job-submission-factories/launchjob.factory';
|
||||
import GetSurveyQuestions from './job-submission-factories/getsurveyquestions.factory';
|
||||
import AdhocRun from './job-submission-factories/adhoc-run.factory.js';
|
||||
import CheckPasswords from './job-submission-factories/check-passwords.factory';
|
||||
import CreateLaunchDialog from './job-submission-factories/create-launch-dialog.factory';
|
||||
import InventoryUpdate from './job-submission-factories/inventory-update.factory';
|
||||
import ProjectUpdate from './job-submission-factories/project-update.factory';
|
||||
import PromptForPasswords from './job-submission-factories/prompt-for-passwords.factory';
|
||||
import submitJob from './job-submission.directive';
|
||||
import credentialList from './lists/credential/job-sub-cred-list.directive';
|
||||
import inventoryList from './lists/inventory/job-sub-inv-list.directive';
|
||||
import awPasswordMin from './job-submission-directives/aw-password-min.directive';
|
||||
import awPasswordMax from './job-submission-directives/aw-password-max.directive';
|
||||
|
||||
export default
|
||||
angular.module('jobSubmission', [])
|
||||
.factory('LaunchJob', LaunchJob)
|
||||
.factory('GetSurveyQuestions', GetSurveyQuestions)
|
||||
.factory('AdhocRun', AdhocRun)
|
||||
.factory('CheckPasswords', CheckPasswords)
|
||||
.factory('CreateLaunchDialog', CreateLaunchDialog)
|
||||
.factory('InventoryUpdate', InventoryUpdate)
|
||||
.factory('ProjectUpdate', ProjectUpdate)
|
||||
.factory('PromptForPasswords', PromptForPasswords)
|
||||
.directive('submitJob', submitJob)
|
||||
.directive('jobSubCredList', credentialList)
|
||||
.directive('jobSubInvList', inventoryList)
|
||||
.directive('awPasswordMin', awPasswordMin)
|
||||
.directive('awPasswordMax', awPasswordMax);
|
||||
|
||||
@ -39,7 +39,7 @@ export default ['i18n', 'templateUrl', function(i18n, templateUrl){
|
||||
label: i18n._("Start"),
|
||||
flag: 'notification_templates_started',
|
||||
type: "toggle",
|
||||
ngClick: "toggleNotification($event, notification.id, \"notification_templates_started\")",
|
||||
ngClick: "toggleNotification($event, notification.id, 'notification_templates_started')",
|
||||
ngDisabled: "!sufficientRoleForNotifToggle",
|
||||
awToolTip: "{{ schedule.play_tip }}",
|
||||
dataTipWatch: "schedule.play_tip",
|
||||
@ -51,7 +51,7 @@ export default ['i18n', 'templateUrl', function(i18n, templateUrl){
|
||||
label: i18n._('Success'),
|
||||
flag: 'notification_templates_success',
|
||||
type: "toggle",
|
||||
ngClick: "toggleNotification($event, notification.id, \"notification_templates_success\")",
|
||||
ngClick: "toggleNotification($event, notification.id, 'notification_templates_success')",
|
||||
ngDisabled: "!sufficientRoleForNotifToggle",
|
||||
awToolTip: "{{ schedule.play_tip }}",
|
||||
dataTipWatch: "schedule.play_tip",
|
||||
@ -64,7 +64,7 @@ export default ['i18n', 'templateUrl', function(i18n, templateUrl){
|
||||
columnClass: 'd-none d-md-flex justify-content-start col-md-1 NotifierList-lastColumn',
|
||||
flag: 'notification_templates_error',
|
||||
type: "toggle",
|
||||
ngClick: "toggleNotification($event, notification.id, \"notification_templates_error\")",
|
||||
ngClick: "toggleNotification($event, notification.id, 'notification_templates_error')",
|
||||
ngDisabled: "!sufficientRoleForNotifToggle",
|
||||
awToolTip: "{{ schedule.play_tip }}",
|
||||
dataTipWatch: "schedule.play_tip",
|
||||
|
||||
@ -22,10 +22,7 @@
|
||||
<div class="SurveyMaker-header">
|
||||
<div class="SurveyMaker-title">
|
||||
<div class="SurveyMaker-titleText">{{name || "New Job Template"}}<div class="SurveyMaker-titleLockup"></div><span translate>SURVEY</span></div>
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': survey_enabled}" aw-tool-tip="surveyEnabledTooltip" data-container="#survey-modal-dialog" data-placement="right" data-tip-watch="surveyEnabledTooltip">
|
||||
<button type="button" ng-show="survey_enabled" class="ScheduleToggle-switch is-on" ng-click="toggleSurveyEnabled()" translate>ON</button>
|
||||
<button type="button" ng-show="!survey_enabled" class="ScheduleToggle-switch" ng-click="toggleSurveyEnabled()" translate>OFF</button>
|
||||
</div>
|
||||
<at-switch on-toggle="toggleSurveyEnabled()" switch-on="survey_enabled" switch-disabled="(!job_template_obj.summary_fields.user_capabilities.edit && !workflow_job_template_obj.summary_fields.user_capabilities.edit && !canAdd)" tooltip="surveyEnabledTooltip" tooltip-placement="right" tooltip-watch="surveyEnabledTooltip"></at-switch>
|
||||
</div>
|
||||
<div class="SurveyMaker-close">
|
||||
<button class="SurveyMaker-exit" ng-click="closeSurvey('survey-modal-dialog')"><i class="fa fa-times-circle"></i></button>
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
/** @define ScheduleToggle */
|
||||
|
||||
.Form-formGroup--disabled .ScheduleToggle {
|
||||
cursor: not-allowed;
|
||||
border-color: @default-link !important;
|
||||
.ScheduleToggle-switch {
|
||||
background-color: @d7grey !important;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.ScheduleToggle {
|
||||
border-radius: 5px;
|
||||
border: 1px solid @default-link;
|
||||
background-color: @default-link;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 42px;
|
||||
|
||||
&.ScheduleToggle--disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: none;
|
||||
border-color: @d7grey !important;
|
||||
.ScheduleToggle-switch {
|
||||
background-color: @d7grey !important;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ScheduleToggle-switch {
|
||||
color: @default-link;
|
||||
background-color: @default-bg;
|
||||
border-left: 1px solid @default-link;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
padding: 0px 5px;
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
border-right: 0px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.ScheduleToggle.is-on {
|
||||
border-color: @default-link;
|
||||
background-color: @default-bg;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.ScheduleToggle-switch.is-on {
|
||||
background-color: @default-link;
|
||||
color: @default-bg;
|
||||
border-left: 0;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.ScheduleToggle-switch:hover {
|
||||
background-color: @default-tertiary-bg;
|
||||
}
|
||||
|
||||
.ScheduleToggle.is-on:hover {
|
||||
border-color: @default-link-hov;
|
||||
}
|
||||
|
||||
.ScheduleToggle-switch.is-on:hover {
|
||||
background-color: @default-link-hov;
|
||||
}
|
||||
|
||||
.ScheduleToggle-listTableCell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
justify-content: flex-end;
|
||||
padding-right: 0px;
|
||||
}
|
||||
@ -25,6 +25,7 @@
|
||||
@f7grey: #F7F7F7;
|
||||
@insights-yellow: #dedc4f;
|
||||
@f2grey: #f2f2f2;
|
||||
@d2grey: #d2d2d2;
|
||||
@fcgrey: #fcfcfc;
|
||||
@f6grey: #f6f6f6;
|
||||
@ebgrey: #ebebeb;
|
||||
|
||||
@ -512,21 +512,11 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
var html = '';
|
||||
// extend these blocks to include elements similarly buildField()
|
||||
if (field.type === 'toggle'){
|
||||
html += "<div class=\"Field-header--" + key;
|
||||
html += (field['class']) ? " " + field['class'] : "";
|
||||
html += " " + field.columnClass;
|
||||
html += "\"><div class='ScheduleToggle' ng-class='{\"is-on\": " + form.iterator + ".";
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += (field.ngDisabled) ? ', "ScheduleToggle--disabled": ' + field.ngDisabled : '';
|
||||
html += "\}' aw-tool-tip='" + field.awToolTip + "' data-placement='" + field.dataPlacement + "' data-tip-watch='" + field.dataTipWatch + "'><button type='button' ng-show='" + form.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : 'enabled';
|
||||
html += "' ";
|
||||
html += (field.ngDisabled) ? `ng-disabled="${field.ngDisabled}" ` : "";
|
||||
html += " class='ScheduleToggle-switch is-on' ng-click='" + field.ngClick + "' translate>" + i18n._("ON") + "</button><button type='button' ng-show='!" + form.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += "' ";
|
||||
html += (field.ngDisabled) ? `ng-disabled="${field.ngDisabled}" ` : "";
|
||||
html += " class='ScheduleToggle-switch' ng-click='" + field.ngClick + "' translate>" + i18n._("OFF") + "</button></div></div>";
|
||||
html += `
|
||||
<div class="Field-header--${key} ${field['class']} ${field.columnClass}">
|
||||
<at-switch on-toggle="${field.ngClick}" switch-on="${"flag" in field} ? ${form.iterator}.${field.flag} : ${form.iterator}.enabled" switch-disabled="${"ngDisabled" in field} ? ${field.ngDisabled} : false" tooltip-string="${field.awToolTip}" tooltip-placement="${field.dataPlacement ? field.dataPlacement : 'right'}"></at-switch>
|
||||
</div>
|
||||
`;
|
||||
} else if (field.type === 'html') {
|
||||
html += field.html;
|
||||
}
|
||||
@ -676,17 +666,11 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
}
|
||||
|
||||
if (field.type === 'toggle'){
|
||||
html += "<td class=\"List-tableCell " + fld + "-column";
|
||||
html += (field['class']) ? " " + field['class'] : "";
|
||||
html += " " + field.columnClass;
|
||||
html += "\"><div class='ScheduleToggle' ng-class='{\"is-on\": " + form.iterator + ".";
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += (field.ngDisabled) ? ', "ScheduleToggle--disabled": ' + field.ngDisabled : '';
|
||||
html += "\}' aw-tool-tip='" + field.awToolTip + "' data-placement='" + field.dataPlacement + "' data-tip-watch='" + field.dataTipWatch + "'><div ng-show='" + form.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : 'enabled';
|
||||
html += "' class='ScheduleToggle-switch is-on' ng-click='" + field.ngClick + "' translate>ON</div><div ng-show='!" + form.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += "' class='ScheduleToggle-switch' ng-click='" + field.ngClick + "' translate>OFF</div></div></td>";
|
||||
html += `
|
||||
<td class="List-tableCell-${fld}-column ${field['class']} ${field.columnClass}">
|
||||
<at-switch on-toggle="${field.ngClick}" switch-on="${"flag" in field} ? ${form.iterator}.${field.flag} : ${form.iterator}.enabled" switch-disabled="${"ngDisabled" in field} ? ${field.ngDisabled} : false" tooltip-string="${field.awToolTip}" tooltip-placement="${field.dataPlacement ? field.dataPlacement : 'right'}"></at-switch>
|
||||
</td>
|
||||
`;
|
||||
}
|
||||
|
||||
if (field.type === 'alertblock') {
|
||||
@ -741,14 +725,11 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
|
||||
html += label(labelOptions);
|
||||
|
||||
html += `<div class="ScheduleToggle" ng-class="{'is-on': ${field.toggleSource}, 'ScheduleToggle--disabled': ${field.ngDisabled}}" aw-tool-tip="" `;
|
||||
html += (field.ngShow) ? "ng-show=\"" + field.ngShow + "\" " : "";
|
||||
html += `data-placement="top">`;
|
||||
html += `<button type="button" ng-show="${field.toggleSource}" class="ScheduleToggle-switch is-on" ng-click="toggleForm('${field.toggleSource}')"
|
||||
ng-disabled="${field.ngDisabled}" translate>${i18n._("ON")}</button>
|
||||
<button type="button" ng-show="!${field.toggleSource}" class="ScheduleToggle-switch" ng-click="toggleForm('${field.toggleSource}')"
|
||||
ng-disabled="${field.ngDisabled}" translate>${i18n._("OFF")}</button>
|
||||
</div>`;
|
||||
html += `
|
||||
<div>
|
||||
<at-switch on-toggle="toggleForm('${field.toggleSource}')" switch-on="${field.toggleSource}" switch-disabled="${"ngDisabled" in field} ? ${field.ngDisabled} : false" hide="!(${"ngShow" in field ? field.ngShow : true})"></at-switch>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
//text fields
|
||||
|
||||
@ -527,21 +527,11 @@ angular.module('GeneratorHelpers', [systemStatus.name])
|
||||
} else if (field.type === 'template') {
|
||||
html = Template(field);
|
||||
} else if (field.type === 'toggle') {
|
||||
html += "<div class=\"ScheduleToggle-listTableCell " + fld + "-column";
|
||||
html += (field['class']) ? " " + field['class'] : "";
|
||||
html += field.columnClass ? " " + field.columnClass : "";
|
||||
html += "\"><div class='ScheduleToggle' ng-class='{\"is-on\": " + list.iterator + ".";
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += (field.ngDisabled) ? ', "ScheduleToggle--disabled": ' + field.ngDisabled : '';
|
||||
html += "\}' aw-tool-tip='" + field.awToolTip + "' data-placement='" + field.dataPlacement + "' data-tip-watch='" + field.dataTipWatch + "'><button type='button'";
|
||||
html += (field.ngDisabled) ? `ng-disabled="${field.ngDisabled}" ` : "";
|
||||
html += "ng-show='" + list.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : 'enabled';
|
||||
html += "' class='ScheduleToggle-switch is-on' ng-click='" + field.ngClick + "'>" + i18n._("ON") + "</button><button type='button'";
|
||||
html += (field.ngDisabled) ? `ng-disabled="${field.ngDisabled}" ` : "";
|
||||
html += "ng-show='!" + list.iterator + "." ;
|
||||
html += (field.flag) ? field.flag : "enabled";
|
||||
html += "' class='ScheduleToggle-switch' ng-click='" + field.ngClick + "'>" + i18n._("OFF") + "</button></div></div>";
|
||||
html += `
|
||||
<div class="atSwitch-listTableCell ${field}-column ${field['class']} ${field.columnClass}">
|
||||
<at-switch on-toggle="${field.ngClick}" switch-on="${"flag" in field} ? ${list.iterator}.${field.flag} : ${list.iterator}.enabled" switch-disabled="${"ngDisabled" in field} ? ${field.ngDisabled} : false" tooltip-string="${field.awToolTip}" tooltip-placement="${field.dataPlacement ? field.dataPlacement : 'right'}" tooltip-watch="${field.dataTipWatch}"></at-switch>
|
||||
</div>
|
||||
`;
|
||||
} else if (field.type === 'invalid') {
|
||||
html += `<div class='List-tableRow--invalid'><div class='List-tableRow--invalidBar' ng-show="${field.ngShow}"`;
|
||||
html += `aw-tool-tip="${field.awToolTip}" data-placement=${field.dataPlacement}>`;
|
||||
|
||||
@ -111,10 +111,7 @@
|
||||
</a>
|
||||
</label>
|
||||
<div>
|
||||
<div class="ScheduleToggle" ng-class="{'is-on': promptData.prompts.diffMode.value}" aw-tool-tip="" data-placement="top" data-original-title="" title="" ng-click="vm.toggleDiff()">
|
||||
<button type="button" ng-show="promptData.prompts.diffMode.value" class="ScheduleToggle-switch is-on" ng-disabled="readOnlyPrompts">{{:: vm.strings.get('ON') }}</button>
|
||||
<button type="button" ng-show="!promptData.prompts.diffMode.value" class="ScheduleToggle-switch ng-hide" ng-disabled="readOnlyPrompts">{{:: vm.strings.get('OFF') }}</button>
|
||||
</div>
|
||||
<at-switch on-toggle="vm.toggleDiff()" switch-on="promptData.prompts.diffMode.value" switch-disabled="readOnlyPrompts"></at-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="promptData.launchConf.ask_variables_on_launch && !promptData.prompts.variables.ignore">
|
||||
|
||||
@ -18,7 +18,7 @@ const standardInvDetails = createFormSection({
|
||||
'#inventory_form .Form-textArea',
|
||||
'#inventory_form input[type="checkbox"]',
|
||||
'#inventory_form .ui-spinner-input',
|
||||
'#inventory_form .ScheduleToggle-switch'
|
||||
'#inventory_form .atSwitch-inner'
|
||||
]
|
||||
},
|
||||
labels: {
|
||||
|
||||
@ -19,7 +19,7 @@ const details = createFormSection({
|
||||
'#notification_template_form input[type="radio"]',
|
||||
'#notification_template_form .ui-spinner-input',
|
||||
'#notification_template_form .Form-textArea',
|
||||
'#notification_template_form .ScheduleToggle-switch',
|
||||
'#notification_template_form .atSwitch-inner',
|
||||
'#notification_template_form .Form-lookupButton'
|
||||
]
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ const jtDetails = createFormSection({
|
||||
'#job_template_form .Form-textArea',
|
||||
'#job_template_form input[type="checkbox"]',
|
||||
'#job_template_form .ui-spinner-input',
|
||||
'#job_template_form .ScheduleToggle-switch'
|
||||
'#job_template_form .atSwitch-inner'
|
||||
]
|
||||
},
|
||||
labels: {
|
||||
@ -38,7 +38,7 @@ const wfjtDetails = createFormSection({
|
||||
'#workflow_job_template_form .Form-textArea',
|
||||
'#workflow_job_template_form input[type="checkbox"]',
|
||||
'#workflow_job_template_form .ui-spinner-input',
|
||||
'#workflow_job_template_form .ScheduleToggle-switch'
|
||||
'#workflow_job_template_form .atSwitch-inner'
|
||||
]
|
||||
},
|
||||
labels: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user