Implemented the ability to specify credentials when creating a scheduled job run. Added validation for removing but not replacing default credentials.

This commit is contained in:
mabashian 2018-03-01 15:24:50 -05:00
parent 61a48996ee
commit a5043029c1
16 changed files with 264 additions and 67 deletions

View File

@ -118,5 +118,5 @@
query-set="querySet">
</paginate>
</at-panel-body>
<prompt prompt-data="promptData" open-modal="openModal" on-finish="launchJob()"></launch>
<prompt prompt-data="promptData" on-finish="launchJob()"></launch>
</at-panel>

View File

@ -55,7 +55,8 @@ function TemplatesStrings (BaseString) {
VALID_DECIMAL: t.s('Please enter an answer that is a decimal number.'),
PLAYBOOK_RUN: t.s('Playbook Run'),
CHECK: t.s('Check'),
NO_CREDS_MATCHING_TYPE: t.s('No Credentials Matching This Type Have Been Created'),
NO_CREDS_MATCHING_TYPE: t.s('No Credentials Matching This Type Have Been Created'),
CREDENTIAL_TYPE_MISSING: typeLabel => t.s('This job template has a default {{typeLabel}} credential which must be included or replaced before proceeding.', { typeLabel })
};
ns.alert = {
@ -85,7 +86,7 @@ function TemplatesStrings (BaseString) {
ns.warnings = {
WORKFLOW_RESTRICTED_COPY: t.s('You do not have access to all resources used by this workflow. Resources that you don\'t have access to will not be copied and will result in an incomplete workflow.')
}
};
}
TemplatesStrings.$inject = ['BaseStringService'];

View File

@ -0,0 +1,38 @@
let Base;
let $http;
function postCredential (params) {
const req = {
method: 'POST',
url: `${this.path}${params.id}/credentials/`
};
if (params.data) {
req.data = params.data;
}
return $http(req);
}
function ScheduleModel (method, resource, config) {
Base.call(this, 'schedules');
this.Constructor = ScheduleModel;
this.postCredential = postCredential.bind(this);
return this.create(method, resource, config);
}
function ScheduleModelLoader (BaseModel, _$http_) {
Base = BaseModel;
$http = _$http_;
return ScheduleModel;
}
ScheduleModelLoader.$inject = [
'BaseModel',
'$http'
];
export default ScheduleModelLoader;

View File

@ -16,6 +16,7 @@ import ModelsStrings from '~models/models.strings';
import NotificationTemplate from '~models/NotificationTemplate';
import Organization from '~models/Organization';
import Project from '~models/Project';
import Schedule from '~models/Schedule';
import UnifiedJobTemplate from '~models/UnifiedJobTemplate';
import WorkflowJob from '~models/WorkflowJob';
import WorkflowJobTemplate from '~models/WorkflowJobTemplate';
@ -43,6 +44,7 @@ angular
.service('NotificationTemplate', NotificationTemplate)
.service('OrganizationModel', Organization)
.service('ProjectModel', Project)
.service('ScheduleModel', Schedule)
.service('UnifiedJobTemplateModel', UnifiedJobTemplate)
.service('WorkflowJobModel', WorkflowJob)
.service('WorkflowJobTemplateModel', WorkflowJobTemplate)

View File

@ -1,36 +1,37 @@
export default
function SchedulePost(Rest, ProcessErrors, RRuleToAPI, Wait, $q) {
function SchedulePost(Rest, ProcessErrors, RRuleToAPI, Wait, $q, Schedule) {
return function(params) {
var scope = params.scope,
url = params.url,
scheduler = params.scheduler,
mode = params.mode,
schedule = (params.schedule) ? params.schedule : {},
scheduleData = (params.schedule) ? params.schedule : {},
promptData = params.promptData,
priorCredentials = params.priorCredentials ? params.priorCredentials : [],
newSchedule, rrule, extra_vars;
let deferred = $q.defer();
if (scheduler.isValid()) {
Wait('start');
newSchedule = scheduler.getValue();
rrule = scheduler.getRRule();
schedule.name = newSchedule.name;
schedule.rrule = RRuleToAPI(rrule.toString(), scope);
schedule.description = (/error/.test(rrule.toText())) ? '' : rrule.toText();
scheduleData.name = newSchedule.name;
scheduleData.rrule = RRuleToAPI(rrule.toString(), scope);
scheduleData.description = (/error/.test(rrule.toText())) ? '' : rrule.toText();
if (scope.isFactCleanup) {
extra_vars = {
"older_than": scope.scheduler_form.keep_amount.$viewValue + scope.scheduler_form.keep_unit.$viewValue.value,
"granularity": scope.scheduler_form.granularity_keep_amount.$viewValue + scope.scheduler_form.granularity_keep_unit.$viewValue.value
};
schedule.extra_data = JSON.stringify(extra_vars);
scheduleData.extra_data = JSON.stringify(extra_vars);
} else if (scope.cleanupJob) {
extra_vars = {
"days" : scope.scheduler_form.schedulerPurgeDays.$viewValue
};
schedule.extra_data = JSON.stringify(extra_vars);
scheduleData.extra_data = JSON.stringify(extra_vars);
}
else if(scope.extraVars){
schedule.extra_data = scope.parseType === 'yaml' ?
scheduleData.extra_data = scope.parseType === 'yaml' ?
(scope.extraVars === '---' ? "" : jsyaml.safeLoad(scope.extraVars)) : scope.extraVars;
}
@ -40,10 +41,10 @@ export default
var fld = promptData.surveyQuestions[i].variable;
// grab all survey questions that have answers
if(promptData.surveyQuestions[i].required || (promptData.surveyQuestions[i].required === false && promptData.surveyQuestions[i].model.toString()!=="")) {
if(!schedule.extra_data) {
schedule.extra_data = {};
if(!scheduleData.extra_data) {
scheduleData.extra_data = {};
}
schedule.extra_data[fld] = promptData.surveyQuestions[i].model;
scheduleData.extra_data[fld] = promptData.surveyQuestions[i].model;
}
if(promptData.surveyQuestions[i].required === false && _.isEmpty(promptData.surveyQuestions[i].model)) {
@ -55,7 +56,7 @@ export default
case "text":
case "textarea":
if (promptData.surveyQuestions[i].min === 0) {
schedule.extra_data[fld] = "";
scheduleData.extra_data[fld] = "";
}
break;
}
@ -64,43 +65,65 @@ export default
}
if(_.has(promptData, 'prompts.jobType.value.value') && _.get(promptData, 'launchConf.ask_job_type_on_launch')) {
schedule.job_type = promptData.prompts.jobType.templateDefault === promptData.prompts.jobType.value.value ? null : promptData.prompts.jobType.value.value;
scheduleData.job_type = promptData.launchConf.defaults.job_type && promptData.launchConf.defaults.job_type === promptData.prompts.jobType.value.value ? null : promptData.prompts.jobType.value.value;
}
if(_.has(promptData, 'prompts.tags.value') && _.get(promptData, 'launchConf.ask_tags_on_launch')){
let templateDefaultJobTags = promptData.prompts.tags.templateDefault.split(',');
schedule.job_tags = (_.isEqual(templateDefaultJobTags.sort(), promptData.prompts.tags.value.map(a => a.value).sort())) ? null : promptData.prompts.tags.value.map(a => a.value).join();
let templateDefaultJobTags = promptData.launchConf.defaults.job_tags.split(',');
scheduleData.job_tags = (_.isEqual(templateDefaultJobTags.sort(), promptData.prompts.tags.value.map(a => a.value).sort())) ? null : promptData.prompts.tags.value.map(a => a.value).join();
}
if(_.has(promptData, 'prompts.skipTags.value') && _.get(promptData, 'launchConf.ask_skip_tags_on_launch')){
let templateDefaultSkipTags = promptData.prompts.skipTags.templateDefault.split(',');
schedule.skip_tags = (_.isEqual(templateDefaultSkipTags.sort(), promptData.prompts.skipTags.value.map(a => a.value).sort())) ? null : promptData.prompts.skipTags.value.map(a => a.value).join();
let templateDefaultSkipTags = promptData.launchConf.defaults.skip_tags.split(',');
scheduleData.skip_tags = (_.isEqual(templateDefaultSkipTags.sort(), promptData.prompts.skipTags.value.map(a => a.value).sort())) ? null : promptData.prompts.skipTags.value.map(a => a.value).join();
}
if(_.has(promptData, 'prompts.limit.value') && _.get(promptData, 'launchConf.ask_limit_on_launch')){
schedule.limit = promptData.prompts.limit.templateDefault === promptData.prompts.limit.value ? null : promptData.prompts.limit.value;
scheduleData.limit = promptData.launchConf.defaults.limit && promptData.launchConf.defaults.limit === promptData.prompts.limit.value ? null : promptData.prompts.limit.value;
}
if(_.has(promptData, 'prompts.verbosity.value.value') && _.get(promptData, 'launchConf.ask_verbosity_on_launch')){
schedule.verbosity = promptData.prompts.verbosity.templateDefault === promptData.prompts.verbosity.value.value ? null : promptData.prompts.verbosity.value.value;
scheduleData.verbosity = promptData.launchConf.defaults.verbosity && promptData.launchConf.defaults.verbosity === promptData.prompts.verbosity.value.value ? null : promptData.prompts.verbosity.value.value;
}
if(_.has(promptData, 'prompts.inventory.value') && _.get(promptData, 'launchConf.ask_inventory_on_launch')){
schedule.inventory = promptData.prompts.inventory.templateDefault.id === promptData.prompts.inventory.value.id ? null : promptData.prompts.inventory.value.id;
scheduleData.inventory = promptData.launchConf.defaults.inventory && promptData.launchConf.defaults.inventory.id === promptData.prompts.inventory.value.id ? null : promptData.prompts.inventory.value.id;
}
if(_.has(promptData, 'prompts.diffMode.value') && _.get(promptData, 'launchConf.ask_diff_mode_on_launch')){
schedule.diff_mode = promptData.prompts.diffMode.templateDefault === promptData.prompts.diffMode.value ? null : promptData.prompts.diffMode.value;
scheduleData.diff_mode = promptData.launchConf.defaults.diff_mode && promptData.launchConf.defaults.diff_mode === promptData.prompts.diffMode.value ? null : promptData.prompts.diffMode.value;
}
// Credentials gets POST'd to a separate endpoint
// if($scope.promptData.launchConf.ask_credential_on_launch){
// jobLaunchData.credentials = [];
// promptData.credentials.value.forEach((credential) => {
// jobLaunchData.credentials.push(credential.id);
// });
// }
}
Rest.setUrl(url);
if (mode === 'add') {
Rest.post(schedule)
.then(() => {
Wait('stop');
deferred.resolve();
Rest.post(scheduleData)
.then(({data}) => {
if(_.get(promptData, 'launchConf.ask_credential_on_launch')){
// This finds the credentials that were selected in the prompt but don't occur
// in the template defaults
let credentialsToPost = promptData.prompts.credentials.value.filter(function(credFromPrompt) {
let defaultCreds = promptData.launchConf.defaults.credentials ? promptData.launchConf.defaults.credentials : [];
return !defaultCreds.some(function(defaultCred) {
return credFromPrompt.id === defaultCred.id;
});
});
let promises = [];
let schedule = new Schedule();
credentialsToPost.forEach((credentialToPost) => {
promises.push(schedule.postCredential({
id: data.id,
data: {
id: credentialToPost.id
}
}));
});
$q.all(promises)
.then(() => {
Wait('stop');
deferred.resolve();
});
} else {
Wait('stop');
deferred.resolve();
}
})
.catch(({data, status}) => {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
@ -110,10 +133,62 @@ export default
});
}
else {
Rest.put(schedule)
.then(() => {
Rest.put(scheduleData)
.then(({data}) => {
if(_.get(promptData, 'launchConf.ask_credential_on_launch')){
let credentialsNotInPriorCredentials = promptData.prompts.credentials.value.filter(function(credFromPrompt) {
let defaultCreds = promptData.launchConf.defaults.credentials ? promptData.launchConf.defaults.credentials : [];
return !defaultCreds.some(function(defaultCred) {
return credFromPrompt.id === defaultCred.id;
});
});
let credentialsToAdd = credentialsNotInPriorCredentials.filter(function(credNotInPrior) {
return !priorCredentials.some(function(priorCred) {
return credNotInPrior.id === priorCred.id;
});
});
let credentialsToRemove = priorCredentials.filter(function(priorCred) {
return !credentialsNotInPriorCredentials.some(function(credNotInPrior) {
return priorCred.id === credNotInPrior.id;
});
});
let promises = [];
let schedule = new Schedule();
credentialsToAdd.forEach((credentialToAdd) => {
promises.push(schedule.postCredential({
id: data.id,
data: {
id: credentialToAdd.id
}
}));
});
credentialsToRemove.forEach((credentialToRemove) => {
promises.push(schedule.postCredential({
id: data.id,
data: {
id: credentialToRemove.id,
disassociate: true
}
}));
});
$q.all(promises)
.then(() => {
Wait('stop');
deferred.resolve();
});
} else {
Wait('stop');
deferred.resolve();
}
Wait('stop');
deferred.resolve(schedule);
deferred.resolve(scheduleData);
})
.catch(({data, status}) => {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
@ -136,5 +211,6 @@ SchedulePost.$inject =
'ProcessErrors',
'RRuleToAPI',
'Wait',
'$q'
'$q',
'ScheduleModel'
];

View File

@ -104,6 +104,7 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait',
let watchForPromptChanges = () => {
let promptValuesToWatch = [
'promptData.prompts.inventory.value',
'promptData.prompts.jobType.value',
'promptData.prompts.verbosity.value',
'missingSurveyValue'
];

View File

@ -5,7 +5,7 @@ function($filter, $state, $stateParams, Wait, $scope, moment,
$rootScope, $http, CreateSelect2, ParseTypeChange, ParentObject, ProcessErrors, Rest,
GetBasePath, SchedulerInit, SchedulePost, JobTemplate, $q, Empty, PromptService, RRuleToAPI) {
let schedule, scheduler;
let schedule, scheduler, scheduleCredentials = [];
// initial end @ midnight values
$scope.schedulerEndHour = "00";
@ -63,7 +63,8 @@ function($filter, $state, $stateParams, Wait, $scope, moment,
scheduler: scheduler,
mode: 'edit',
schedule: schedule,
promptData: $scope.promptData
promptData: $scope.promptData,
priorCredentials: scheduleCredentials
}).then(() => {
Wait('stop');
$state.go("^", null, {reload: true});
@ -254,14 +255,14 @@ function($filter, $state, $stateParams, Wait, $scope, moment,
$q.all([jobTemplate.optionsLaunch(ParentObject.id), jobTemplate.getLaunch(ParentObject.id), Rest.get()])
.then((responses) => {
let launchOptions = responses[0].data,
launchConf = responses[1].data,
scheduleCredentials = responses[2].data;
launchConf = responses[1].data;
scheduleCredentials = responses[2].data.results;
let watchForPromptChanges = () => {
let promptValuesToWatch = [
// credential passwords...?
'promptData.prompts.inventory.value',
'promptData.prompts.jobType.value',
'promptData.prompts.verbosity.value',
'missingSurveyValue'
];
@ -283,7 +284,23 @@ function($filter, $state, $stateParams, Wait, $scope, moment,
currentValues: data
});
prompts.credentials.value = scheduleCredentials.results.length > 0 ? scheduleCredentials.results : prompts.credentials.value;
let defaultCredsWithoutOverrides = [];
prompts.credentials.value.forEach((defaultCred) => {
let typeMatches = false;
scheduleCredentials.forEach((scheduleCred) => {
if(defaultCred.credential_type === scheduleCred.credential_type) {
if((!defaultCred.vault_id && !scheduleCred.inputs.vault_id) || (defaultCred.vault_id && scheduleCred.inputs.vault_id && defaultCred.vault_id === scheduleCred.inputs.vault_id)) {
typeMatches = true;
}
}
});
if(!typeMatches) {
defaultCredsWithoutOverrides.push(defaultCred);
}
});
prompts.credentials.value = scheduleCredentials.concat(defaultCredsWithoutOverrides);
if(!launchConf.ask_variables_on_launch) {
$scope.noVars = true;

View File

@ -560,7 +560,13 @@ angular.module('GeneratorHelpers', [systemStatus.name])
}
html += "\" ";
html += field.columnNgClass ? " ng-class=\"" + field.columnNgClass + "\"": "";
html += (options.mode === 'lookup' || options.mode === 'select') ? " ng-click=\"toggle_row(" + list.iterator + ")\"" : "";
if(options.mode === 'lookup' || options.mode === 'select') {
if (options.input_type === "radio") {
html += " ng-click=\"toggle_row(" + list.iterator + ")\"";
} else {
html += " ng-click=\"toggle_" + list.iterator + "(" + list.iterator + ", true)\"";
}
}
html += (field.columnShow) ? Attr(field, 'columnShow') : "";
html += (field.ngBindHtml) ? "ng-bind-html=\"" + field.ngBindHtml + "\" " : "";
html += (field.columnClick) ? "ng-click=\"" + field.columnClick + "\" " : "";

View File

@ -165,3 +165,7 @@
.Prompt-credentialSubSection .select2 {
width: 50% !important;
}
.Prompt-credentialTypeMissing {
margin-bottom: 20px;
color: @default-err;
}

View File

@ -65,8 +65,6 @@ export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel',
}
}));
vm.promptData.prompts.inventory.templateDefault = _.has(vm, 'promptData.launchConf.defaults.inventory') ? vm.promptData.launchConf.defaults.inventory : null;
vm.promptData.prompts.credentials.templateDefault = _.has(vm, 'promptData.launchConf.defaults.credentials') ? angular.copy(vm.promptData.launchConf.defaults.credentials) : [];
vm.promptData.prompts.credentials.passwordsNeededToStart = vm.promptData.launchConf.passwords_needed_to_start;
vm.promptData.prompts.credentials.passwords = {};
@ -99,17 +97,12 @@ export default [ 'Rest', 'GetBasePath', 'ProcessErrors', 'CredentialTypeModel',
vm.promptData.prompts.credentials.passwords.vault.push(credPassObj);
}
});
}
});
vm.promptData.credentialTypeMissing = [];
vm.promptData.prompts.variables.ignore = vm.promptData.launchConf.ignore_ask_variables;
vm.promptData.prompts.verbosity.templateDefault = vm.promptData.launchConf.defaults.verbosity;
vm.promptData.prompts.jobType.templateDefault = vm.promptData.launchConf.defaults.job_type;
vm.promptData.prompts.limit.templateDefault = vm.promptData.launchConf.defaults.limit;
vm.promptData.prompts.tags.templateDefault = vm.promptData.launchConf.defaults.job_tags;
vm.promptData.prompts.skipTags.templateDefault = vm.promptData.launchConf.defaults.skip_tags;
vm.promptData.prompts.diffMode.templateDefault = vm.promptData.launchConf.defaults.diff_mode;
if(vm.promptData.launchConf.ask_inventory_on_launch) {
vm.steps.inventory.includeStep = true;

View File

@ -27,7 +27,7 @@
<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.promptData.prompts.inventory.value.id">{{:: 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="!vm.forms.credentialPasswords.$valid">{{:: 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="!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"></button>

View File

@ -13,7 +13,7 @@ function PromptService (Empty, $filter) {
diffMode: {}
};
prompts.credentials.value = _.has(params, 'launchConf.defaults.credentials') ? params.launchConf.defaults.credentials : [];
prompts.credentials.value = _.has(params, 'launchConf.defaults.credentials') ? _.cloneDeep(params.launchConf.defaults.credentials) : [];
prompts.inventory.value = _.has(params, 'currentValues.summary_fields.inventory') ? params.currentValues.summary_fields.inventory : (_.has(params, 'launchConf.defaults.inventory') ? params.launchConf.defaults.inventory : null);
let skipTags = _.has(params, 'currentValues.skip_tags') && params.currentValues.skip_tags ? params.currentValues.skip_tags : (_.has(params, 'launchConf.defaults.skip_tags') ? params.launchConf.defaults.skip_tags : "");

View File

@ -88,11 +88,41 @@ export default
}
};
let checkMissingCredType = (cred) => {
scope.promptData.launchConf.defaults.credentials.forEach((defaultCred) => {
if(cred.credential_type === defaultCred.credential_type) {
let credTypeLabel = "";
scope.promptData.prompts.credentials.credentialTypeOptions.forEach((credTypeOption) => {
if(credTypeOption.value === defaultCred.credential_type) {
credTypeLabel = credTypeOption.name;
}
});
if(scope.promptData.prompts.credentials.credentialTypes[cred.credential_type] === "vault") {
if((_.get(cred, 'inputs.vault_id') ? _.get(cred, 'inputs.vault_id') : _.get(cred, 'vault_id')) === _.get(defaultCred, 'vault_id')) {
scope.promptData.credentialTypeMissing.push({
credential_type: defaultCred.credential_type,
vault_id: defaultCred.vault_id,
label: defaultCred.vault_id ? `${credTypeLabel} (id: ${defaultCred.vault_id})` : credTypeLabel
});
}
} else {
scope.promptData.credentialTypeMissing.push({
credential_type: defaultCred.credential_type,
label: credTypeLabel
});
}
}
});
};
vm.init = (_scope_, _launch_) => {
scope = _scope_;
launch = _launch_;
scope.toggle_row = (selectedRow) => {
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]);
@ -100,8 +130,15 @@ export default
}
}
scope.promptData.prompts.credentials.value.push(_.cloneDeep(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;
}
}
};
scope.toggle_credential = (cred) => {
@ -146,6 +183,18 @@ export default
if(!uncheck) {
scope.promptData.prompts.credentials.value.push(cred);
updateNeededPasswords(cred);
for (let i = scope.promptData.credentialTypeMissing.length - 1; i >= 0; i--) {
if(scope.promptData.credentialTypeMissing[i].credential_type === cred.credential_type) {
if(_.get(cred, 'inputs.vault_id') === _.get(scope.promptData.credentialTypeMissing[i], 'vault_id')) {
scope.promptData.credentialTypeMissing.splice(i,1);
i = -1;
}
}
}
} else {
if(scope.promptData.launchConf.defaults.credentials && scope.promptData.launchConf.defaults.credentials.length > 0) {
checkMissingCredType(cred);
}
}
};
@ -200,6 +249,9 @@ export default
vm.deleteSelectedCredential = (credentialToDelete) => {
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) {
checkMissingCredType(credentialToDelete);
}
wipePasswords(credentialToDelete);
scope.promptData.prompts.credentials.value.splice(i, 1);
}
@ -213,7 +265,7 @@ export default
};
vm.revert = () => {
scope.promptData.prompts.credentials.value = scope.promptData.prompts.credentials.templateDefault;
scope.promptData.prompts.credentials.value = _.has(scope, 'promptData.launchConf.defaults.credentials') ? _.cloneDeep(scope.promptData.launchConf.defaults.credentials) : [];
scope.promptData.prompts.credentials.passwords = {
vault: []
};
@ -242,13 +294,15 @@ export default
}
});
scope.promptData.credentialTypeMissing = [];
};
vm.showRevertCredentials = () => {
if(scope.promptData.launchConf.ask_credential_on_launch) {
if(scope.promptData.prompts.credentials.value && scope.promptData.prompts.credentials.templateDefault && (scope.promptData.prompts.credentials.value.length === scope.promptData.prompts.credentials.templateDefault.length)) {
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 = scope.promptData.prompts.credentials.templateDefault.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() : [];
return !selectedIds.every((e, i) => { return defaultIds.indexOf(e) === i; });
} else {
return true;

View File

@ -1,11 +1,11 @@
<div>
<div class="Prompt-selectedItem">
<div class="Prompt-selectedItemInfo" ng-hide="promptData.prompts.credentials.templateDefault.length === 0 && promptData.prompts.credentials.value.length === 0">
<div class="Prompt-selectedItemInfo" ng-hide="(!promptData.launchConf.defaults.credentials || promptData.launchConf.defaults.credentials.length === 0) && promptData.prompts.credentials.value.length === 0">
<div class="Prompt-selectedItemLabel">
<span>{{:: vm.strings.get('prompt.SELECTED') }}</span>
</div>
<div class="Prompt-previewTags--outer">
<div ng-show="promptData.prompts.credentials.templateDefault.length > 0 && promptData.prompts.credentials.value.length === 0" class="Prompt-noSelectedItem">{{:: vm.strings.get('prompt.NO_CREDENTIALS_SELECTED') }}</div>
<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}"
@ -39,6 +39,11 @@
</div>
</div>
</div>
<div ng-if="promptData.credentialTypeMissing && promptData.credentialTypeMissing.length > 0" class="Prompt-credentialTypeMissing">
<div ng-repeat="missingCred in promptData.credentialTypeMissing">
<span class="fa fa-warning"></span>&nbsp;{{:: vm.strings.get('prompt.CREDENTIAL_TYPE_MISSING', missingCred.label) }}
</div>
</div>
<span ng-show="promptData.launchConf.ask_credential_on_launch">
<div class="Prompt-credentialSubSection">
<span class="Prompt-label">{{:: vm.strings.get('prompt.CREDENTIAL_TYPE') }}:</span>

View File

@ -31,7 +31,7 @@ export default
};
vm.revert = () => {
scope.promptData.prompts.inventory.value = scope.promptData.prompts.inventory.templateDefault;
scope.promptData.prompts.inventory.value = scope.promptData.launchConf.defaults.inventory;
};
}
];

View File

@ -1,11 +1,11 @@
<div>
<div class="Prompt-selectedItem">
<div class="Prompt-selectedItemInfo" ng-hide="!promptData.prompts.inventory.value.id && !promptData.prompts.inventory.templateDefault.id">
<div class="Prompt-selectedItemInfo" ng-hide="!promptData.prompts.inventory.value.id && !promptData.launchConf.defaults.inventory.id">
<div class="Prompt-selectedItemLabel">
<span>{{:: vm.strings.get('prompt.SELECTED') }}</span>
</div>
<div class="Prompt-previewTags--outer">
<div ng-show="promptData.prompts.inventory.templateDefault.id && !promptData.prompts.inventory.value.id" class="Prompt-noSelectedItem">{{:: vm.strings.get('prompt.NO_INVENTORY_SELECTED') }}</div>
<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">
@ -18,7 +18,7 @@
</div>
</div>
<div class="Prompt-previewTagRevert">
<a class="Prompt-revertLink" href="" ng-hide="promptData.prompts.inventory.value.id === promptData.prompts.inventory.templateDefault.id" ng-click="vm.revert()">{{:: vm.strings.get('prompt.REVERT') }}</a>
<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>
</div>
</div>
</div>