Prevent scheduling JT runs where credentials with passwords are required. Added read-only view of schedules when user does not have edit permissions.

This commit is contained in:
mabashian 2018-05-30 12:42:10 -04:00
parent b1f36572c6
commit 09ee140fb4
27 changed files with 326 additions and 247 deletions

View File

@ -18,7 +18,6 @@
margin: 2px @at-space-2x;
align-self: center;
word-break: break-word;
text-transform: lowercase;
&:hover,
&:focus {

View File

@ -58,6 +58,7 @@ function BaseStringService (namespace) {
* the project.
*/
this.CANCEL = t.s('CANCEL');
this.CLOSE = t.s('CLOSE');
this.SAVE = t.s('SAVE');
this.OK = t.s('OK');
this.NEXT = t.s('NEXT');

View File

@ -19,7 +19,7 @@ export default ['i18n', function(i18n) {
basePath: 'inventory',
title: false,
disableRow: "{{ inventory.pending_deletion }}",
disableRowValue: 'pending_deletion',
disableRowValue: 'inventory.pending_deletion',
fields: {
status: {

View File

@ -8,12 +8,12 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait',
'$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', 'GetBasePath',
'Rest', 'ParentObject', 'JobTemplateModel', '$q', 'Empty', 'SchedulePost',
'ProcessErrors', 'SchedulerInit', '$location', 'PromptService', 'RRuleToAPI', 'moment',
'WorkflowJobTemplateModel', 'TemplatesStrings', 'rbacUiControlService',
'WorkflowJobTemplateModel', 'TemplatesStrings', 'rbacUiControlService', 'Alert', 'i18n',
function($filter, $state, $stateParams, $http, Wait,
$scope, $rootScope, CreateSelect2, ParseTypeChange, GetBasePath,
Rest, ParentObject, JobTemplate, $q, Empty, SchedulePost,
ProcessErrors, SchedulerInit, $location, PromptService, RRuleToAPI, moment,
WorkflowJobTemplate, TemplatesStrings, rbacUiControlService
WorkflowJobTemplate, TemplatesStrings, rbacUiControlService, Alert, i18n
) {
var base = $scope.base || $location.path().replace(/^\//, '').split('/')[0],
@ -112,6 +112,14 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait',
.then((responses) => {
let launchConf = responses[1].data;
if (launchConf.passwords_needed_to_start &&
launchConf.passwords_needed_to_start.length > 0 &&
!launchConf.ask_credential_on_launch
) {
Alert(i18n._('Warning'), i18n._('This Job Template has a default credential that requires a password before launch. Adding or editing schedules is prohibited while this credential is selected. To add or edit a schedule, credentials that require a password must be removed from the Job Template.'), 'alert-info');
$state.go('^', { reload: true });
}
let watchForPromptChanges = () => {
let promptValuesToWatch = [
'promptData.prompts.inventory.value',
@ -156,7 +164,6 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait',
!launchConf.survey_enabled &&
!launchConf.credential_needed_to_start &&
!launchConf.inventory_needed_to_start &&
launchConf.passwords_needed_to_start.length === 0 &&
launchConf.variables_needed_to_start.length === 0) {
$scope.showPromptButton = false;
} else {

View File

@ -1,11 +1,11 @@
export default ['$filter', '$state', '$stateParams', 'Wait', '$scope', 'moment',
'$rootScope', '$http', 'CreateSelect2', 'ParseTypeChange', 'ParentObject', 'ProcessErrors', 'Rest',
'GetBasePath', 'SchedulerInit', 'SchedulePost', 'JobTemplateModel', '$q', 'Empty', 'PromptService', 'RRuleToAPI',
'WorkflowJobTemplateModel', 'TemplatesStrings', 'scheduleResolve', 'timezonesResolve',
'WorkflowJobTemplateModel', 'TemplatesStrings', 'scheduleResolve', 'timezonesResolve', 'Alert', 'i18n',
function($filter, $state, $stateParams, Wait, $scope, moment,
$rootScope, $http, CreateSelect2, ParseTypeChange, ParentObject, ProcessErrors, Rest,
GetBasePath, SchedulerInit, SchedulePost, JobTemplate, $q, Empty, PromptService, RRuleToAPI,
WorkflowJobTemplate, TemplatesStrings, scheduleResolve, timezonesResolve
WorkflowJobTemplate, TemplatesStrings, scheduleResolve, timezonesResolve, Alert, i18n
) {
let schedule, scheduler, scheduleCredentials = [];
@ -249,8 +249,15 @@ function($filter, $state, $stateParams, Wait, $scope, moment,
.then((responses) => {
let launchOptions = responses[0].data,
launchConf = responses[1].data;
scheduleCredentials = responses[2].data.results;
scheduleCredentials = responses[2].data.results;
if (launchConf.passwords_needed_to_start &&
launchConf.passwords_needed_to_start.length > 0 &&
!launchConf.ask_credential_on_launch
) {
Alert(i18n._('Warning'), i18n._('This Job Template has a default credential that requires a password before launch. Adding or editing schedules is prohibited while this credential is selected. To add or edit a schedule, credentials that require a password must be removed from the Job Template.'), 'alert-info');
$scope.credentialRequiresPassword = true;
}
let watchForPromptChanges = () => {
let promptValuesToWatch = [

View File

@ -28,7 +28,7 @@
name="schedulerName"
id="schedulerName"
ng-model="schedulerName" required
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
placeholder="Schedule name">
<div class="error"
ng-show="scheduler_form.$dirty && scheduler_form.schedulerName.$error.required">
@ -42,7 +42,7 @@
</label>
<div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<scheduler-date-picker date="schedulerStartDt"
disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)">
disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword">
</scheduler-date-picker>
</div>
<div class="error"
@ -67,7 +67,7 @@
<input name="schedulerStartHour"
id="schedulerStartHour"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
ScheduleTime-input SpinnerInput"
aw-spinner="schedulerStartHour"
@ -83,7 +83,7 @@
<input name="schedulerStartMinute"
id="schedulerStartMinute"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
aw-spinner="schedulerStartMinute"
@ -99,7 +99,7 @@
<input name="schedulerStartSecond"
id="schedulerStartSecond"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
aw-spinner="schedulerStartSecond"
@ -121,7 +121,7 @@
Local Time Zone
</label>
<select
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
name="schedulerTimeZone"
id="schedulerTimeZone"
ng-model="schedulerTimeZone"
@ -137,7 +137,7 @@
Repeat frequency
</label>
<select name="schedulerFrequency"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
id="schedulerFrequency"
class="MakeSelect2"
ng-model="schedulerFrequency"
@ -166,7 +166,7 @@
<input name="schedulerInterval"
id="schedulerInterval"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-spinner
SpinnerInput"
aw-spinner="schedulerInterval"
@ -193,7 +193,7 @@
<label class="Form-inputLabel">
<span class="red-text">*</span>
<input type="radio" value="day"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-model="$parent.monthlyRepeatOption"
ng-change="monthlyRepeatChange()"
name="monthlyRepeatOption"
@ -205,7 +205,7 @@
name="monthDay"
id="monthDay"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-spinner SpinnerInput"
aw-spinner="$parent.monthDay"
ng-model="$parent.monthDay"
@ -224,7 +224,7 @@
<label class="Form-inputLabel">
<span class="red-text">*</span>
<input type="radio"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
value="other"
ng-model="$parent.monthlyRepeatOption"
ng-change="monthlyRepeatChange()"
@ -239,7 +239,7 @@
id="monthlyOccurrence"
ng-model="$parent.monthlyOccurrence"
ng-options="o.name for o in occurrences"
ng-disabled="monthlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="monthlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class=" MakeSelect2 form-control
input-sm
RepeatFrequencyOptions-spacedSelect
@ -250,7 +250,7 @@
id="monthlyWeekDay"
ng-model="$parent.monthlyWeekDay"
ng-options="w.name for w in weekdays"
ng-disabled="monthlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="monthlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="MakeSelect2 form-control input-sm" >
</select>
</div>
@ -263,7 +263,7 @@
<span class="red-text">*</span>
<label class="Form-inputLabel">
<input type="radio"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
value="month"
ng-model="$parent.yearlyRepeatOption"
ng-change="yearlyRepeatChange()"
@ -278,7 +278,7 @@
id="yearlyMonth"
ng-model="$parent.yearlyMonth"
ng-options="m.name for m in months"
ng-disabled="yearlyRepeatOption != 'month' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="yearlyRepeatOption != 'month' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="MakeSelect2 form-control input-sm
RepeatFrequencyOptions-spacedSelect"
>
@ -286,7 +286,7 @@
<input name="yearlyMonthDay"
id="yearlyMonthDay"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-spinner
SpinnerInput"
aw-spinner="$parent.yearlyMonthDay"
@ -308,7 +308,7 @@
<label class="Form-inputLabel">
<span class="red-text">*</span>
<input type="radio"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
value="other"
ng-model="$parent.yearlyRepeatOption"
ng-change="yearlyRepeatChange()"
@ -325,7 +325,7 @@
id="yearlyOccurrence"
ng-model="$parent.yearlyOccurrence"
ng-options="o.name for o in occurrences"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="MakeSelect2
form-control input-sm
RepeatFrequencyOptions-spacedSelect
@ -337,7 +337,7 @@
id="yearlyWeekDay"
ng-model="$parent.yearlyWeekDay"
ng-options="w.name for w in weekdays"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="MakeSelect2
form-control input-sm
RepeatFrequencyOptions-spacedSelect
@ -348,7 +348,7 @@
id="yearlyOtherMonth"
ng-model="$parent.yearlyOtherMonth"
ng-options="m.name for m in months"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="yearlyRepeatOption != 'other' || !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="MakeSelect2
form-control input-sm
RepeatFrequencyOptions-thirdSelect">
@ -370,7 +370,7 @@
data-toggle="buttons-checkbox"
id="weekdaySelect">
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDaySUClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -379,7 +379,7 @@
Sun
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDayMOClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -388,7 +388,7 @@
Mon
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDayTUClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -397,7 +397,7 @@
Tue
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDayWEClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -406,7 +406,7 @@
Wed
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDayTHClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -415,7 +415,7 @@
Thu
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDayFRClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -424,7 +424,7 @@
Fri
</button>
<button type="button"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-class="weekDaySAClass"
class="btn btn-default
RepeatFrequencyOptions-weekButton"
@ -448,7 +448,7 @@
</label>
<div>
<select id="schedulerEnd"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
name="schedulerEnd"
ng-model="$parent.schedulerEnd"
ng-options="e.name for e in endOptions"
@ -470,7 +470,7 @@
ng-name="schedulerOccurrenceCount"
ng-id="schedulerOccurrenceCount"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-spinner
SpinnerInput"
aw-spinner="$parent.schedulerOccurrenceCount"
@ -492,7 +492,7 @@
</label>
<div class="input-group Form-inputGroup SchedulerForm-inputGroup--date">
<scheduler-date-picker date="$parent.schedulerEndDt"
disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)">
disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword">
</scheduler-date-picker>
</div>
<div class="error"
@ -518,7 +518,7 @@
<input name="schedulerEndHour"
id="schedulerEndHour"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
ScheduleTime-input SpinnerInput"
aw-spinner="$parent.schedulerEndHour"
@ -534,7 +534,7 @@
<input name="schedulerEndMinute"
id="$parent.schedulerEndMinute"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
aw-spinner="$parent.schedulerEndMinute"
@ -550,7 +550,7 @@
<input name="schedulerEndSecond"
id="schedulerEndSecond"
sch-spinner="scheduler_form"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-disabled="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
aw-spinner="$parent.schedulerEndSecond"
@ -656,7 +656,7 @@
</div>
</label>
<div ng-class="{'CodeMirror--disabled': !(schedule_obj.summary_fields.user_capabilities.edit || canAdd)}">
<div ng-class="{'CodeMirror--disabled': !(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword}">
<textarea rows="6" ng-model="extraVars" name="Scheduler-extraVars" class="form-control" id="SchedulerForm-extraVars"></textarea>
</div>
</div>
@ -665,26 +665,26 @@
<button type="button"
class="btn btn-sm Form-primaryButton Form-primaryButton--noMargin"
id="schedule_prompt_btn"
ng-show="(schedule_obj.summary_fields.user_capabilities.edit || canAdd) && showPromptButton"
ng-show="showPromptButton"
ng-click="prompt()">Prompt</button>
<button type="button"
class="btn btn-sm Form-cancelButton"
id="schedule_cancel_btn"
ng-show="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-show="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd) || credentialRequiresPassword"
ng-click="formCancel()">Close</button>
<button type="button"
class="btn btn-sm Form-cancelButton"
id="schedule_cancel_btn"
ng-show="(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"
ng-show="(schedule_obj.summary_fields.user_capabilities.edit || canAdd) && !credentialRequiresPassword"
ng-click="formCancel()">Cancel</button>
<div class="SchedulerForm-promptSave" ng-show="(schedule_obj.summary_fields.user_capabilities.edit || canAdd)">
<div class="SchedulerForm-promptSave" ng-show="(schedule_obj.summary_fields.user_capabilities.edit || canAdd) && !credentialRequiresPassword">
<div ng-if="promptModalMissingReqFields" class="SchedulerForm-promptSaveTooltip" aw-tool-tip="Additional information required in the Prompt area before saving" data-placement="top"></div>
<button type="button"
class="btn btn-sm Form-saveButton"
id="schedule_save_btn"
ng-click="saveSchedule()"
ng-disabled="!schedulerIsValid || promptModalMissingReqFields || (preview_list.isEmpty && scheduler_form.$dirty)"> Save</button>
ng-disabled="!schedulerIsValid || promptModalMissingReqFields || (preview_list.isEmpty && scheduler_form.$dirty) || credentialRequiresPassword"> Save</button>
</div>
</div>
<prompt prompt-data="promptData" action-text="{{:: strings.get('prompt.CONFIRM')}}" prevent-creds-with-passwords="preventCredsWithPasswords"></prompt>
<prompt prompt-data="promptData" prevent-creds-with-passwords="preventCredsWithPasswords" action-text="{{:: strings.get('prompt.CONFIRM')}}" read-only-prompts="!(schedule_obj.summary_fields.user_capabilities.edit || canAdd)"></prompt>
</div>

View File

@ -13,13 +13,14 @@
export default [
'$filter', '$scope', '$location', '$stateParams', 'ScheduleList', 'Rest',
'rbacUiControlService',
'ToggleSchedule', 'DeleteSchedule', '$q', '$state', 'Dataset', 'ParentObject', 'UnifiedJobsOptions',
function($filter, $scope, $location, $stateParams,
ScheduleList, Rest,
rbacUiControlService,
ToggleSchedule, DeleteSchedule,
$q, $state, Dataset, ParentObject, UnifiedJobsOptions) {
'rbacUiControlService', 'JobTemplateModel', 'ToggleSchedule', 'DeleteSchedule',
'$q', '$state', 'Dataset', 'ParentObject', 'UnifiedJobsOptions', 'i18n',
'Alert',
function($filter, $scope, $location, $stateParams, ScheduleList, Rest,
rbacUiControlService, JobTemplate, ToggleSchedule, DeleteSchedule,
$q, $state, Dataset, ParentObject, UnifiedJobsOptions, i18n,
Alert
) {
var base, scheduleEndpoint,
list = ScheduleList;
@ -35,6 +36,19 @@ export default [
.then(function(params) {
$scope.canAdd = params.canAdd;
});
if (_.has(ParentObject, 'type') && ParentObject.type === 'job_template') {
const jobTemplate = new JobTemplate();
jobTemplate.getLaunch(ParentObject.id)
.then(({data}) => {
if (data.passwords_needed_to_start &&
data.passwords_needed_to_start.length > 0 &&
!ParentObject.ask_credential_on_launch
) {
$scope.credentialRequiresPassword = true;
$scope.addTooltip = i18n._("Using a credential that requires a password on launch is prohibited when creating a Job Template schedule");
}
});
}
}
// search init
@ -107,13 +121,15 @@ export default [
function buildTooltips(schedule) {
var job = schedule.summary_fields.unified_job_template;
if (schedule.enabled) {
schedule.play_tip = 'Schedule is active. Click to stop.';
const tip = (schedule.summary_fields.user_capabilities.edit || $scope.credentialRequiresPassword) ? i18n._('Schedule is active.') : i18n._('Schedule is active. Click to stop.');
schedule.play_tip = tip;
schedule.status = 'active';
schedule.status_tip = 'Schedule is active. Click to stop.';
schedule.status_tip = tip;
} else {
schedule.play_tip = 'Schedule is stopped. Click to activate.';
const tip = (schedule.summary_fields.user_capabilities.edit || $scope.credentialRequiresPassword) ? i18n._('Schedule is stopped.') : i18n._('Schedule is stopped. Click to activate.');
schedule.play_tip = tip;
schedule.status = 'stopped';
schedule.status_tip = 'Schedule is stopped. Click to activate.';
schedule.status_tip = tip;
}
schedule.nameTip = $filter('sanitize')(schedule.name);

View File

@ -26,7 +26,7 @@ export default ['i18n', function(i18n) {
ngShow: '!isValid(schedule)'
},
toggleSchedule: {
ngDisabled: "!schedule.summary_fields.user_capabilities.edit",
ngDisabled: "!schedule.summary_fields.user_capabilities.edit || credentialRequiresPassword",
label: '',
columnClass: 'List-staticColumn--toggle',
type: "toggle",
@ -70,11 +70,13 @@ export default ['i18n', function(i18n) {
},
add: {
mode: 'all',
ngClick: 'addSchedule()',
ngClick: 'credentialRequiresPassword || addSchedule()',
awToolTip: i18n._('Add a new schedule'),
dataTipWatch: 'addTooltip',
actionClass: 'at-Button--add',
actionId: 'button-add',
ngShow: 'canAdd'
ngShow: 'canAdd',
ngClass: "{ 'Form-tab--disabled': credentialRequiresPassword }"
}
},
@ -85,14 +87,14 @@ export default ['i18n', function(i18n) {
icon: 'icon-edit',
awToolTip: i18n._('Edit schedule'),
dataPlacement: 'top',
ngShow: 'schedule.summary_fields.user_capabilities.edit'
ngShow: 'schedule.summary_fields.user_capabilities.edit && !credentialRequiresPassword'
},
view: {
label: i18n._('View'),
ngClick: "editSchedule(schedule)",
awToolTip: i18n._('View schedule'),
dataPlacement: 'top',
ngShow: '!schedule.summary_fields.user_capabilities.edit'
ngShow: '!schedule.summary_fields.user_capabilities.edit || credentialRequiresPassword'
},
"delete": {
label: i18n._('Delete'),

View File

@ -50,6 +50,7 @@
data-placement="{{options.dataPlacement}}"
data-container="{{options.dataContainer}}"
class="{{options.actionClass}}"
ng-class="{{options.ngClass}}"
id="{{options.actionId}}"
data-title="{{options.dataTitle}}"
ng-disabled="{{options.ngDisabled}}"

View File

@ -314,7 +314,7 @@ export default ['$compile', 'Attr', 'Icon',
innerTable += `, {'List-tableRow--selected' : $stateParams['${list.iterator}_id'] == ${list.iterator}.id}`;
}
innerTable += (list.disableRow) ? `, {true: 'List-tableRow--disabled'}[${list.iterator}.${list.disableRowValue}]` : "";
innerTable += (list.disableRow) ? `, {'List-tableRow--disabled': ${list.disableRowValue}}` : "";
if (list.multiSelect) {
innerTable += ", " + list.iterator + ".isSelected ? 'is-selected-row' : ''";
@ -338,13 +338,13 @@ export default ['$compile', 'Attr', 'Icon',
}
if (list.multiSelect) {
innerTable += '<td class="col-xs-1 select-column List-staticColumn--smallStatus"><select-list-item item=\"' + list.iterator + '\" disabled="'+list.iterator + '.' + list.disableRowValue+'"></select-list-item></td>';
innerTable += '<td class="col-xs-1 select-column List-staticColumn--smallStatus"><select-list-item item=\"' + list.iterator + '\" disabled="'+list.disableRowValue+'"></select-list-item></td>';
}
// Change layout if a lookup list, place radio buttons before labels
if (options.mode === 'lookup') {
if (options.input_type === "radio") { //added by JT so that lookup forms can be either radio inputs or check box inputs
innerTable += `<td class="List-tableCell"> <input type="radio" ng-model="${list.iterator}.checked" ng-value="1" ng-false-value="0" name="check_${list.iterator}_{{${list.iterator}.id}}" ng-click="toggle_row(${list.iterator})"></td>`;
innerTable += `<td class="List-tableCell"> <input type="radio" ng-model="${list.iterator}.checked" ng-value="1" ng-false-value="0" name="check_${list.iterator}_{{${list.iterator}.id}}" ng-click="toggle_row(${list.iterator})" ng-disabled="${list.disableRowValue}"></td>`;
}
else { // its assumed that options.input_type = checkbox
innerTable += "<td class=\"List-tableCell select-column List-staticColumn--smallStatus\"><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_{{" +

View File

@ -482,19 +482,19 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.job_templates.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.job_templates[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.job_templates.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.job_templates[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
@ -559,19 +559,19 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.workflow_inventory_sources.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.workflow_inventory_sources[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.workflow_inventory_sources.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.workflow_inventory_sources[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
@ -636,19 +636,19 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
}
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.projects.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.projects[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.projects.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.projects[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
};
$scope.templateManuallySelected(row);
}
});
$scope.templateManuallySelected(row);
}
});
}
};
$scope.$watch('selectedTemplate', () => {
@ -708,6 +708,8 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
delete list.fields.labels;
delete list.fieldActions;
list.fields.name.columnClass = "col-md-8";
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
list.iterator = 'job_template';
list.name = 'job_templates';
list.basePath = "job_templates";
@ -733,6 +735,8 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
list.fields.name.columnClass = "col-md-11";
list.maxVisiblePages = 5;
list.searchBarFullWidth = true;
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
return list;
}
@ -742,6 +746,8 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
let list = _.cloneDeep(InventorySourcesList);
list.maxVisiblePages = 5;
list.searchBarFullWidth = true;
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
return list;
}

View File

@ -21,6 +21,7 @@
padding-left:15px;
padding-right: 15px;
min-width: 85px;
margin-left: 20px;
}
.Prompt-actionButton:disabled {
background-color: @d7grey;
@ -42,7 +43,6 @@
padding-right: 15px;
height: 30px;
min-width: 85px;
margin-right: 20px;
}
.Prompt-defaultButton:hover{
background-color: @btn-bg-hov;
@ -65,8 +65,6 @@
border: 1px solid @default-border;
padding: 10px;
border-radius: 5px;
max-height: 120px;
overflow-y: auto;
}
.Prompt-selectedItemRevert {
display: flex;
@ -108,8 +106,9 @@
line-height: 29px;
}
.Prompt-previewTags--outer {
display: flex;
flex: 1 0 auto;
max-width: ~"calc(100% - 140px)";
width: ~"calc(100% - 140px)";
}
.Prompt-previewTags--inner {
display: flex;
@ -123,8 +122,9 @@
color: @default-list-header-bg;
}
.Prompt-previewTagRevert {
flex: 0 0 60px;
line-height: 29px;
display: flex;
align-items: center;
justify-content: center;
}
.Prompt-previewTagContainer {
display: flex;
@ -142,8 +142,10 @@
text-transform: uppercase;
}
.Prompt-previewRowValue {
flex: 1 0 auto;
max-width: 508px;
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
.Prompt-noSelectedItem {
height: 30px;

View File

@ -145,7 +145,7 @@ export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel',
vm.steps.credential.includeStep = true;
vm.steps.credential.tab = {
_active: order === 1 ? true : false,
_disabled: order === 1 ? false : true,
_disabled: (order === 1 || vm.readOnlyPrompts) ? false : true,
order: order
};
order++;
@ -154,7 +154,7 @@ export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel',
vm.steps.other_prompts.includeStep = true;
vm.steps.other_prompts.tab = {
_active: order === 1 ? true : false,
_disabled: order === 1 ? false : true,
_disabled: (order === 1 || vm.readOnlyPrompts) ? false : true,
order: order
};
order++;
@ -170,12 +170,13 @@ export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel',
vm.steps.survey.includeStep = true;
vm.steps.survey.tab = {
_active: order === 1 ? true : false,
_disabled: order === 1 ? false : true,
_disabled: (order === 1 || vm.readOnlyPrompts) ? false : true,
order: order
};
order++;
}
vm.steps.preview.tab.order = order;
vm.steps.preview.tab._disabled = vm.readOnlyPrompts ? false : true;
modal.show('PROMPT');
vm.promptData.triggerModalOpen = false;

View File

@ -6,7 +6,8 @@ export default [ 'templateUrl',
promptData: '=',
onFinish: '&',
actionText: '@',
preventCredsWithPasswords: '<'
preventCredsWithPasswords: '<',
readOnlyPrompts: '='
},
templateUrl: templateUrl('templates/prompt/prompt'),
replace: true,

View File

@ -9,37 +9,53 @@
</at-tab-group>
<div class="Prompt-step">
<div ng-if="vm.steps.inventory.includeStep" ng-show="vm.steps.inventory.tab._active">
<prompt-inventory prompt-data="vm.promptDataClone"></prompt-inventory>
<prompt-inventory
prompt-data="vm.promptDataClone"
read-only-prompts="vm.readOnlyPrompts">
</prompt-inventory>
</div>
<div ng-if="vm.steps.credential.includeStep" ng-show="vm.steps.credential.tab._active">
<prompt-credential
prompt-data="vm.promptDataClone"
credential-passwords-form="vm.forms.credentialPasswords"
prevent-creds-with-passwords="vm.preventCredsWithPasswords">
prevent-creds-with-passwords="vm.preventCredsWithPasswords"
read-only-prompts="vm.readOnlyPrompts">
</prompt-credential>
</div>
<div ng-if="vm.steps.other_prompts.includeStep" ng-show="vm.steps.other_prompts.tab._active">
<prompt-other-prompts prompt-data="vm.promptDataClone" other-prompts-form="vm.forms.otherPrompts" is-active-step="vm.steps.other_prompts.tab._active" validate="vm.codeMirror.validate"></prompt-other-prompts>
<prompt-other-prompts
prompt-data="vm.promptDataClone"
other-prompts-form="vm.forms.otherPrompts"
is-active-step="vm.steps.other_prompts.tab._active"
validate="vm.codeMirror.validate"
read-only-prompts="vm.readOnlyPrompts">
</prompt-other-prompts>
</div>
<div ng-if="vm.steps.survey.includeStep" ng-show="vm.steps.survey.tab._active">
<prompt-survey prompt-data="vm.promptDataClone" survey-form="vm.forms.survey"></prompt-survey>
<prompt-survey
prompt-data="vm.promptDataClone"
survey-form="vm.forms.survey"
read-only-prompts="vm.readOnlyPrompts">
</prompt-survey>
</div>
<div ng-if="vm.steps.preview.tab._active">
<prompt-preview prompt-data="vm.promptDataClone"></prompt-preview>
</div>
</div>
<div class="Prompt-footer">
<button class="Prompt-defaultButton" ng-click="vm.cancel()">{{:: vm.strings.get('CANCEL') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.inventory.tab._active" ng-click="vm.next(vm.steps.inventory.tab)" ng-disabled="!vm.promptDataClone.prompts.inventory.value.id">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-defaultButton" ng-click="vm.cancel()" ng-show="!vm.readOnlyPrompts">{{:: vm.strings.get('CANCEL') }}</button>
<button class="Prompt-defaultButton" ng-click="vm.cancel()" ng-show="vm.readOnlyPrompts">{{:: vm.strings.get('CLOSE') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.inventory.tab._active" ng-click="vm.next(vm.steps.inventory.tab)" ng-disabled="!vm.promptDataClone.prompts.inventory.value.id && !vm.readOnlyPrompts">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton"
ng-show="vm.steps.credential.tab._active"
ng-click="vm.next(vm.steps.credential.tab)"
ng-disabled="(preventCredsWithPasswords && (vm.promptDataClone.prompts.credentials.passwords.ssh_password || vm.promptDataClone.prompts.credentials.passwords.become_password || vm.promptDataClone.prompts.credentials.passwords.ssh_key_unlock || (vm.promptDataClone.prompts.credentials.passwords.vault && vm.promptDataClone.prompts.credentials.passwords.vault.length > 0))) ||
!vm.forms.credentialPasswords.$valid ||
(vm.promptData.credentialTypeMissing && vm.promptData.credentialTypeMissing.length > 0)">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.other_prompts.tab._active" ng-click="vm.next(vm.steps.other_prompts.tab)" ng-disabled="!vm.forms.otherPrompts.$valid">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.survey.tab._active" ng-click="vm.next(vm.steps.survey.tab)" ng-disabled="!vm.forms.survey.$valid">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.preview.tab._active" ng-click="vm.finish()" ng-bind="vm.actionText" ng-disabled="vm.actionButtonClicked"></button>
ng-disabled="!vm.readOnlyPrompts &&
((preventCredsWithPasswords && (vm.promptDataClone.prompts.credentials.passwords.ssh_password || vm.promptDataClone.prompts.credentials.passwords.become_password || vm.promptDataClone.prompts.credentials.passwords.ssh_key_unlock || (vm.promptDataClone.prompts.credentials.passwords.vault && vm.promptDataClone.prompts.credentials.passwords.vault.length > 0))) ||
!vm.forms.credentialPasswords.$valid ||
(vm.promptDataClone.credentialTypeMissing && vm.promptDataClone.credentialTypeMissing.length > 0))">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.other_prompts.tab._active" ng-click="vm.next(vm.steps.other_prompts.tab)" ng-disabled="!vm.readOnlyPrompts && !vm.forms.otherPrompts.$valid">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.survey.tab._active" ng-click="vm.next(vm.steps.survey.tab)" ng-disabled="!vm.readOnlyPrompts && !vm.forms.survey.$valid">{{:: vm.strings.get('NEXT') }}</button>
<button class="Prompt-actionButton" ng-show="vm.steps.preview.tab._active && !vm.readOnlyPrompts" ng-click="vm.finish()" ng-bind="vm.actionText" ng-disabled="vm.actionButtonClicked"></button>
</div>
</at-modal>
</div>

View File

@ -18,9 +18,16 @@ export default
if(scope.credentials && scope.credentials.length > 0) {
scope.credentials.forEach((credential, i) => {
scope.credentials[i].checked = 0;
});
scope.promptData.prompts.credentials.value.forEach((selectedCredential) => {
if(selectedCredential.credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) {
if (_.has(selectedCredential, 'inputs.vault_id') || _.has(selectedCredential, 'vault_id')) {
const vaultId = selectedCredential.vault_id ? selectedCredential.vault_id : _.get(selectedCredential, 'inputs.vault_id');
selectedCredential.tag = `${selectedCredential.name } | ${vaultId}`;
} else {
selectedCredential.tag = selectedCredential.name;
}
if (selectedCredential.credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) {
scope.credentials.forEach((credential, i) => {
if(scope.credentials[i].id === selectedCredential.id) {
scope.credentials[i].checked = 1;
@ -135,78 +142,82 @@ export default
launch = _launch_;
scope.toggle_row = (selectedRow) => {
let selectedCred = _.cloneDeep(selectedRow);
if (!scope.readOnlyPrompts) {
let selectedCred = _.cloneDeep(selectedRow);
for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) {
if(scope.promptData.prompts.credentials.value[i].credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) {
wipePasswords(scope.promptData.prompts.credentials.value[i]);
scope.promptData.prompts.credentials.value.splice(i, 1);
for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) {
if(scope.promptData.prompts.credentials.value[i].credential_type === parseInt(scope.promptData.prompts.credentials.credentialKind)) {
wipePasswords(scope.promptData.prompts.credentials.value[i]);
scope.promptData.prompts.credentials.value.splice(i, 1);
}
}
}
scope.promptData.prompts.credentials.value.push(selectedCred);
updateNeededPasswords(selectedRow);
scope.promptData.prompts.credentials.value.push(selectedCred);
updateNeededPasswords(selectedRow);
for (let i = scope.promptData.credentialTypeMissing.length - 1; i >= 0; i--) {
if(scope.promptData.credentialTypeMissing[i].credential_type === selectedRow.credential_type) {
scope.promptData.credentialTypeMissing.splice(i,1);
i = -1;
for (let i = scope.promptData.credentialTypeMissing.length - 1; i >= 0; i--) {
if(scope.promptData.credentialTypeMissing[i].credential_type === selectedRow.credential_type) {
scope.promptData.credentialTypeMissing.splice(i,1);
i = -1;
}
}
}
};
scope.toggle_credential = (cred) => {
// This is a checkbox click. At the time of writing this the only
// multi-select credentials on launch are vault credentials so this
// logic should only get executed when a vault credential checkbox
// is clicked.
if (!scope.readOnlyPrompts) {
// This is a checkbox click. At the time of writing this the only
// multi-select credentials on launch are vault credentials so this
// logic should only get executed when a vault credential checkbox
// is clicked.
let uncheck = false;
let uncheck = false;
let removeCredential = (credentialToRemove, index) => {
wipePasswords(credentialToRemove);
scope.promptData.prompts.credentials.value.splice(index, 1);
};
let removeCredential = (credentialToRemove, index) => {
wipePasswords(credentialToRemove);
scope.promptData.prompts.credentials.value.splice(index, 1);
};
// Only one vault credential per vault_id is allowed so we need to check
// to see if one has already been selected and if so replace it.
for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) {
if(cred.credential_type === scope.promptData.prompts.credentials.value[i].credential_type) {
if(scope.promptData.prompts.credentials.value[i].id === cred.id) {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
i = -1;
uncheck = true;
}
else if(scope.promptData.prompts.credentials.value[i].inputs) {
if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].inputs.vault_id) {
// Only one vault credential per vault_id is allowed so we need to check
// to see if one has already been selected and if so replace it.
for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) {
if(cred.credential_type === scope.promptData.prompts.credentials.value[i].credential_type) {
if(scope.promptData.prompts.credentials.value[i].id === cred.id) {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
i = -1;
uncheck = true;
}
} else if(scope.promptData.prompts.credentials.value[i].vault_id) {
if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].vault_id) {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
}
} else {
// The currently selected vault credential does not have a vault_id
if(!cred.inputs.vault_id || cred.inputs.vault_id === "") {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
else if(scope.promptData.prompts.credentials.value[i].inputs) {
if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].inputs.vault_id) {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
}
} else if(scope.promptData.prompts.credentials.value[i].vault_id) {
if(cred.inputs.vault_id === scope.promptData.prompts.credentials.value[i].vault_id) {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
}
} else {
// The currently selected vault credential does not have a vault_id
if(!cred.inputs.vault_id || cred.inputs.vault_id === "") {
removeCredential(scope.promptData.prompts.credentials.value[i], i);
}
}
}
}
}
if(!uncheck) {
scope.promptData.prompts.credentials.value.push(cred);
updateNeededPasswords(cred);
if(!uncheck) {
scope.promptData.prompts.credentials.value.push(cred);
updateNeededPasswords(cred);
_.remove(scope.promptData.credentialTypeMissing, (missingCredType) => {
return (
missingCredType.credential_type === cred.credential_type &&
_.get(cred, 'inputs.vault_id') === _.get(missingCredType, 'vault_id')
);
});
} else {
if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) {
checkMissingCredType(cred);
_.remove(scope.promptData.credentialTypeMissing, (missingCredType) => {
return (
missingCredType.credential_type === cred.credential_type &&
_.get(cred, 'inputs.vault_id') === _.get(missingCredType, 'vault_id')
);
});
} else {
if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) {
checkMissingCredType(cred);
}
}
}
};
@ -259,7 +270,8 @@ export default
});
};
vm.deleteSelectedCredential = (credentialToDelete) => {
vm.deleteSelectedCredential = (index) => {
const credentialToDelete = scope.promptData.prompts.credentials.value[index];
for (let i = scope.promptData.prompts.credentials.value.length - 1; i >= 0; i--) {
if(scope.promptData.prompts.credentials.value[i].id === credentialToDelete.id) {
if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) {
@ -312,7 +324,7 @@ export default
};
vm.showRevertCredentials = () => {
if(scope.promptData.launchConf.ask_credential_on_launch) {
if(!scope.readOnlyPrompts && scope.promptData.launchConf.ask_credential_on_launch) {
if(scope.promptData.prompts.credentials.value && _.has(scope, 'promptData.launchConf.defaults.credentials') && (scope.promptData.prompts.credentials.value.length === scope.promptData.launchConf.defaults.credentials.length)) {
let selectedIds = scope.promptData.prompts.credentials.value.map((x) => { return x.id; }).sort();
let defaultIds = _.has(scope, 'promptData.launchConf.defaults.credentials') ? scope.promptData.launchConf.defaults.credentials.map((x) => { return x.id; }).sort() : [];

View File

@ -12,7 +12,8 @@ export default [ 'templateUrl', '$compile', 'generateList',
scope: {
promptData: '=',
credentialPasswordsForm: '=',
preventCredsWithPasswords: '<'
preventCredsWithPasswords: '<',
readOnlyPrompts: '<'
},
templateUrl: templateUrl('templates/prompt/steps/credential/prompt-credential'),
controller: promptCredentialController,
@ -43,6 +44,9 @@ export default [ 'templateUrl', '$compile', 'generateList',
};
}
list.disableRow = "{{ readOnlyPrompts }}";
list.disableRowValue = "readOnlyPrompts";
let html = GenerateList.build({
list: list,
input_type: inputType,

View File

@ -7,31 +7,19 @@
<div class="Prompt-previewTags--outer">
<div ng-show="promptData.launchConf.defaults.credentials && promptData.launchConf.defaults.credentials.length > 0 && promptData.prompts.credentials.value.length === 0" class="Prompt-noSelectedItem">{{:: vm.strings.get('prompt.NO_CREDENTIALS_SELECTED') }}</div>
<div class="Prompt-previewTags--inner">
<div class="MultiCredential-tagContainer"
ng-class="{'MultiCredential-tagContainer--disabled': !promptData.launchConf.ask_credential_on_launch}"
ng-repeat="credential in promptData.prompts.credentials.value">
<div class="MultiCredential-iconContainer" ng-switch="promptData.prompts.credentials.credentialTypes[credential.credential_type]">
<i class="fa fa-cloud MultiCredential-tagIcon" ng-switch-when="cloud"></i>
<i class="fa fa-info MultiCredential-tagIcon" ng-switch-when="insights"></i>
<i class="fa fa-sitemap MultiCredential-tagIcon" ng-switch-when="net"></i>
<i class="fa fa-code-fork MultiCredential-tagIcon" ng-switch-when="scm"></i>
<i class="fa fa-key MultiCredential-tagIcon" ng-switch-when="ssh"></i>
<i class="fa fa-archive MultiCredential-tagIcon" ng-switch-when="vault"></i>
</div>
<div class="MultiCredential-tag" ng-class="promptData.launchConf.ask_credential_on_launch ? 'MultiCredential-tag--deletable' : 'MultiCredential-tag--disabled'">
<span ng-if="!credential.inputs.vault_id && !credential.vault_id" class="MultiCredential-name--label">
{{ credential.name }}
</span>
<span ng-if="credential.inputs.vault_id || credential.vault_id" class="MultiCredential-name--label">
{{ credential.name }} | {{ credential.vault_id ? credential.vault_id : credential.inputs.vault_id }}
</span>
</div>
<div class="MultiCredential-deleteContainer"
ng-click="vm.deleteSelectedCredential(credential)"
ng-hide="!promptData.launchConf.ask_credential_on_launch">
<i class="fa fa-times MultiCredential-tagDelete"></i>
</div>
</div>
<span ng-repeat="credential in promptData.prompts.credentials.value">
<at-tag
ng-show="!readOnlyPrompts && promptData.launchConf.ask_credential_on_launch"
tag="credential.tag"
icon="{{ promptData.prompts.credentials.credentialTypes[credential.credential_type] }}"
remove-tag="vm.deleteSelectedCredential($index)">
</at-tag>
<at-tag
ng-show="readOnlyPrompts || !promptData.launchConf.ask_credential_on_launch"
tag="credential.tag"
icon="{{ promptData.prompts.credentials.credentialTypes[credential.credential_type] }}">
</at-tag>
</span>
</div>
</div>
<div class="Prompt-previewTagRevert">

View File

@ -18,8 +18,23 @@ export default
launch = _launch_;
scope.toggle_row = (row) => {
scope.promptData.prompts.inventory.value = row;
if (!scope.readOnlyPrompts) {
scope.promptData.prompts.inventory.value = row;
}
};
scope.$watchCollection('inventories', () => {
if(scope.inventories && scope.inventories.length > 0) {
scope.inventories.forEach((credential, i) => {
if (_.has(scope, 'promptData.prompts.inventory.value.id') && scope.promptData.prompts.inventory.value.id === scope.inventories[i].id) {
scope.inventories[i].checked = 1;
} else {
scope.inventories[i].checked = 0;
}
});
}
});
};
vm.deleteSelectedInventory = () => {

View File

@ -10,7 +10,8 @@ export default [ 'templateUrl', 'QuerySet', 'GetBasePath', 'generateList', '$com
(templateUrl, qs, GetBasePath, GenerateList, $compile, InventoryList) => {
return {
scope: {
promptData: '='
promptData: '=',
readOnlyPrompts: '<'
},
templateUrl: templateUrl('templates/prompt/steps/inventory/prompt-inventory'),
controller: promptInventoryController,
@ -43,6 +44,8 @@ export default [ 'templateUrl', 'QuerySet', 'GetBasePath', 'generateList', '$com
scope.inventories = scope.inventory_dataset.results;
let invList = _.cloneDeep(InventoryList);
invList.disableRow = "{{ readOnlyPrompts }}";
invList.disableRowValue = "readOnlyPrompts";
let html = GenerateList.build({
list: invList,
input_type: 'radio',

View File

@ -6,19 +6,11 @@
</div>
<div class="Prompt-previewTags--outer">
<div ng-show="promptData.launchConf.defaults.inventory.id && !promptData.prompts.inventory.value.id" class="Prompt-noSelectedItem">{{:: vm.strings.get('prompt.NO_INVENTORY_SELECTED') }}</div>
<div class="Prompt-previewTags--inner" ng-hide="!promptData.prompts.inventory.value.id">
<div class="Prompt-previewTagContainer">
<div class="Prompt-previewTag Prompt-previewTag--deletable">
<span>{{promptData.prompts.inventory.value.name}}</span>
</div>
<div class="Prompt-previewTagContainerDelete" ng-click="vm.deleteSelectedInventory()">
<i class="fa fa-times Prompt-previewTagContainerTagDelete"></i>
</div>
</div>
</div>
<at-tag tag="promptData.prompts.inventory.value.name" remove-tag="vm.deleteSelectedInventory()" ng-show="!readOnlyPrompts"></at-tag>
<at-tag tag="promptData.prompts.inventory.value.name" ng-show="readOnlyPrompts"></at-tag>
</div>
<div class="Prompt-previewTagRevert">
<a class="Prompt-revertLink" href="" ng-hide="promptData.prompts.inventory.value.id === promptData.launchConf.defaults.inventory.id" ng-click="vm.revert()">{{:: vm.strings.get('prompt.REVERT') }}</a>
<a class="Prompt-revertLink" href="" ng-hide="readOnlyPrompts || promptData.prompts.inventory.value.id === promptData.launchConf.defaults.inventory.id" ng-click="vm.revert()">{{:: vm.strings.get('prompt.REVERT') }}</a>
</div>
</div>
</div>

View File

@ -13,7 +13,8 @@ export default [ 'templateUrl',
promptData: '=',
otherPromptsForm: '=',
isActiveStep: '=',
validate: '='
validate: '=',
readOnlyPrompts: '<'
},
templateUrl: templateUrl('templates/prompt/steps/other-prompts/prompt-other-prompts'),
controller: promptOtherPrompts,

View File

@ -13,6 +13,7 @@
name="job_type"
tabindex="-1"
aria-hidden="true"
ng-disabled="readOnlyPrompts"
required>
<option value="" class="" selected="selected">{{:: vm.strings.get('prompt.CHOOSE_JOB_TYPE') }}</option>
</select>
@ -23,7 +24,12 @@
<span class="Form-inputLabel">{{:: vm.strings.get('prompt.LIMIT') }}</span>
</label>
<div>
<input type="text" ng-model="promptData.prompts.limit.value" name="limit" class="form-control Form-textInput">
<input
type="text"
ng-model="promptData.prompts.limit.value"
name="limit"
class="form-control Form-textInput"
ng-disabled="readOnlyPrompts">
</div>
</div>
<div class="form-group Form-formGroup Form-formGroup--singleColumn" ng-if="promptData.launchConf.ask_verbosity_on_launch">
@ -40,6 +46,7 @@
name="verbosity"
tabindex="-1"
aria-hidden="true"
ng-disabled="readOnlyPrompts"
required>
<option value="" class="" selected="selected">{{:: vm.strings.get('prompt.CHOOSE_VERBOSITY') }}</option>
</select>
@ -58,6 +65,7 @@
name="job_tags"
tabindex="-1"
aria-hidden="true"
ng-disabled="readOnlyPrompts"
multiple>
</select>
</div>
@ -75,6 +83,7 @@
name="skip_tags"
tabindex="-1"
aria-hidden="true"
ng-disabled="readOnlyPrompts"
multiple>
</select>
</div>
@ -85,8 +94,8 @@
</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 ng-show="promptData.prompts.diffMode.value" class="ScheduleToggle-switch is-on">{{:: vm.strings.get('ON') }}</button>
<button ng-show="!promptData.prompts.diffMode.value" class="ScheduleToggle-switch ng-hide">{{:: vm.strings.get('OFF') }}</button>
<button ng-show="promptData.prompts.diffMode.value" class="ScheduleToggle-switch is-on" ng-disabled="readOnlyPrompts">{{:: vm.strings.get('ON') }}</button>
<button ng-show="!promptData.prompts.diffMode.value" class="ScheduleToggle-switch ng-hide" ng-disabled="readOnlyPrompts">{{:: vm.strings.get('OFF') }}</button>
</div>
</div>
</div>
@ -104,7 +113,7 @@
</div>
</label>
<div>
<textarea rows="6" ng-model="promptData.prompts.variables.value" name="variables" class="form-control Form-textArea Form-textAreaLabel" id="job_launch_variables"></textarea>
<textarea rows="6" ng-model="promptData.prompts.variables.value" name="variables" class="form-control Form-textArea Form-textAreaLabel" id="job_launch_variables" ng-disabled="readOnlyPrompts"></textarea>
</div>
</div>
</form>

View File

@ -9,19 +9,11 @@
<div class="Prompt-previewRow--flex" ng-if="promptData.prompts.credentials.value && promptData.prompts.credentials.value.length > 0">
<div class="Prompt-previewRowTitle">{{:: vm.strings.get('prompt.CREDENTIAL') }}</div>
<div class="Prompt-previewRowValue">
<div class="Prompt-previewTagContainer u-wordwrap" ng-repeat="credential in promptData.prompts.credentials.value">
<div class="Prompt-previewTag">
<span ng-switch="promptData.prompts.credentials.credentialTypes[credential.credential_type]">
<span class="fa fa-cloud" ng-switch-when="cloud"></span>
<span class="fa fa-info" ng-switch-when="insights"></span>
<span class="fa fa-sitemap" ng-switch-when="net"></span>
<span class="fa fa-code-fork" ng-switch-when="scm"></span>
<span class="fa fa-key" ng-switch-when="ssh"></span>
<span class="fa fa-archive" ng-switch-when="vault"></span>
</span>
<span ng-bind="credential.name"></span>
</div>
</div>
<at-tag
ng-repeat="credential in promptData.prompts.credentials.value"
tag="credential.name"
icon="{{ promptData.prompts.credentials.credentialTypes[credential.credential_type] }}">
</at-tag>
</div>
</div>
<div class="Prompt-previewRow--flex" ng-if="promptData.prompts.inventory.value.id">

View File

@ -11,7 +11,8 @@ export default [ 'templateUrl',
return {
scope: {
promptData: '=',
surveyForm: '='
surveyForm: '=',
readOnlyPrompts: '<'
},
templateUrl: templateUrl('templates/prompt/steps/survey/prompt-survey'),
controller: promptSurvey,

View File

@ -9,12 +9,12 @@
<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">
<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" ng-disabled="readOnlyPrompts">
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.required">{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.minlength || surveyForm.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>
<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" ng-disabled="readOnlyPrompts"></textarea>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.required">{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.minlength || surveyForm.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>
@ -23,20 +23,20 @@
<span class="input-group-btn">
<button type="button" class="btn btn-default show_input_button Prompt-passwordButton" id="survey_question_{{$index}}_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="vm.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">
<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" ng-disabled="readOnlyPrompts">
<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" ng-disabled="readOnlyPrompts">
</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.required">{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.awPasswordMin || surveyForm.survey_question_{{$index}}.$error.awPasswordMax || surveyForm.survey_question_{{$index}}.$error.minlength || surveyForm.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"/>
<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" ng-disabled="readOnlyPrompts"/>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.required">{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.number || surveyForm.survey_question_{{$index}}.$error.integer">{{:: vm.strings.get('prompt.VALID_INTEGER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.awMin || surveyForm.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"/>
<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" ng-disabled="readOnlyPrompts"/>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.required">{{:: vm.strings.get('prompt.PLEASE_ENTER_ANSWER') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.number || surveyForm.survey_question_{{$index}}.$error.float">{{:: vm.strings.get('prompt.VALID_DECIMAL') }}</div>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$error.awMin || surveyForm.survey_question_{{$index}}.$error.awMax"><span translate>Please enter an answer between</span> {{question.minValue}} <span translate>and</span> {{question.maxValue}}.</div>
@ -49,6 +49,7 @@
choices="question.choices"
ng-required="question.required"
ng-model="question.model"
ng-disabled="readOnlyPrompts"
form-element-name="survey_question_{{$index}}">
</multiple-choice>
</div>
@ -61,6 +62,7 @@
choices="question.choices"
ng-required="question.required"
ng-model="question.model"
ng-disabled="readOnlyPrompts"
form-element-name="survey_question_{{$index}}">
</multiple-choice>
<div class="error survey_error" ng-show="surveyForm.survey_question_{{$index}}.$dirty && surveyForm.survey_question_{{$index}}.$error.multipleSelect">{{:: vm.strings.get('prompt.PLEASE_SELECT_VALUE') }}</div>

View File

@ -112,6 +112,7 @@
class="form-control Form-dropDown"
name="edgeType"
tabindex="-1"
ng-disabled="!workflowJobTemplateObj.summary_fields.user_capabilities.edit"
aria-hidden="true">
</select>
</div>
@ -129,5 +130,5 @@
<button type="button" class="btn btn-sm WorkflowMaker-cancelButton" ng-click="closeWorkflowMaker()"> Close</button>
<button type="button" class="btn btn-sm WorkflowMaker-saveButton" ng-click="saveWorkflowMaker()" ng-show="workflowJobTemplateObj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate" ng-disabled="edgeFlags.conflict || workflowMakerFormConfig.nodeMode === 'add'"> Save</button>
</div>
<prompt prompt-data="promptData" action-text="{{:: strings.get('prompt.CONFIRM')}}" prevent-creds-with-passwords="preventCredsWithPasswords"></prompt>
<prompt prompt-data="promptData" action-text="{{:: strings.get('prompt.CONFIRM')}}" prevent-creds-with-passwords="preventCredsWithPasswords" read-only-prompts="!(workflowJobTemplateObj.summary_fields.user_capabilities.edit || canAddWorkflowJobTemplate)"></prompt>
</div>