1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-30 13:55:31 +03:00

add webhook credential field

This commit is contained in:
Jake McDermott 2019-09-05 15:59:03 -04:00 committed by Jeff Bradberry
parent f5c151d5c4
commit 151de89c26
10 changed files with 449 additions and 29 deletions

View File

@ -112,6 +112,7 @@
@import '../../src/workflow-results/standard-out.block.less';
@import '../../src/templates/prompt/prompt.block.less';
@import '../../src/templates/job_templates/multi-credential/multi-credential.block.less';
@import '../../src/templates/job_templates/webhook-credential/webhook-credential.block.less';
@import '../../src/templates/labels/labelsList.block.less';
@import '../../src/templates/survey-maker/survey-maker.block.less';
@import '../../src/templates/survey-maker/survey-maker.block.less';

View File

@ -10,14 +10,14 @@
'ProcessErrors', 'GetBasePath', 'hashSetup', 'ParseTypeChange', 'Wait',
'Empty', 'ToJSON', 'CallbackHelpInit', 'GetChoices', '$state', 'availableLabels',
'CreateSelect2', '$q', 'i18n', 'Inventory', 'Project', 'InstanceGroupsService',
'MultiCredentialService', 'ConfigData', 'resolvedModels',
'MultiCredentialService', 'ConfigData', 'resolvedModels', '$compile',
function(
$filter, $scope,
$stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
ProcessErrors, GetBasePath, hashSetup, ParseTypeChange, Wait,
Empty, ToJSON, CallbackHelpInit, GetChoices,
$state, availableLabels, CreateSelect2, $q, i18n, Inventory, Project, InstanceGroupsService,
MultiCredentialService, ConfigData, resolvedModels
MultiCredentialService, ConfigData, resolvedModels, $compile
) {
// Inject dynamic view
@ -45,6 +45,113 @@
$scope.credentialNotPresent = false;
$scope.canGetAllRelatedResources = true;
//
// webhook credential - all handlers, dynamic state, etc. live here
//
$scope.webhookCredential = {
id: null,
name: null,
isModalOpen: false,
isModalReady: false,
modalTitle: i18n._('Select Webhook Credential'),
modalBaseParams: {
order_by: 'name',
page_size: 5,
credential_type__namespace: null,
},
modalSelectedId: null,
modalSelectedName: null,
};
$scope.handleWebhookCredentialLookupClick = () => {
$scope.webhookCredential.modalSelectedId = $scope.webhookCredential.id;
$scope.webhookCredential.isModalOpen = true;
};
$scope.handleWebhookCredentialTagDelete = () => {
$scope.webhookCredential.id = null;
$scope.webhookCredential.name = null;
};
$scope.handleWebhookCredentialModalClose = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
};
$scope.handleWebhookCredentialModalReady = () => {
$scope.webhookCredential.isModalReady = true;
};
$scope.handleWebhookCredentialModalItemSelect = (item) => {
$scope.webhookCredential.modalSelectedId = item.id;
$scope.webhookCredential.modalSelectedName = item.name;
};
$scope.handleWebhookCredentialModalCancel = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
$scope.webhookCredential.modalSelectedId = null;
$scope.webhookCredential.modalSelectedName = null;
};
$scope.handleWebhookCredentialSelect = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
$scope.webhookCredential.id = $scope.webhookCredential.modalSelectedId;
$scope.webhookCredential.name = $scope.webhookCredential.modalSelectedName;
$scope.webhookCredential.modalSelectedId = null;
$scope.webhookCredential.modalSelectedName = null;
};
$('#content-container').append($compile(`
<at-dialog
title="webhookCredential.modalTitle"
on-close="handleWebhookCredentialModalClose"
ng-if="webhookCredential.isModalOpen"
ng-show="webhookCredential.isModalOpen && webhookCredential.isModalReady"
>
<at-lookup-list
ng-show="webhookCredential.isModalOpen && webhookCredential.isModalReady"
resource-name="credential"
base-params="webhookCredential.modalBaseParams"
selected-id="webhookCredential.modalSelectedId"
on-ready="handleWebhookCredentialModalReady"
on-item-select="handleWebhookCredentialModalItemSelect"
/>
<at-action-group col="12" pos="right">
<at-action-button
variant="tertiary"
ng-click="handleWebhookCredentialModalCancel()"
>
${i18n._('CANCEL')}
</at-action-button>
<at-action-button
variant="primary"
ng-click="handleWebhookCredentialSelect()"
>
${i18n._('SELECT')}
</at-action-button>
</at-action-group>
</at-dialog>`)($scope));
$scope.$watch('webhook_service', (newValue, oldValue) => {
const newServiceValue = newValue && typeof newValue === 'object' ? newValue.value : newValue;
const oldServiceValue = oldValue && typeof oldValue === 'object' ? oldValue.value : oldValue;
if (newServiceValue !== oldServiceValue || newServiceValue === newValue) {
$scope.webhook_service = { value: newServiceValue };
sync_webhook_service_select2();
$scope.webhookCredential.modalBaseParams.credential_type__namespace = newServiceValue ?
`${newServiceValue}_token`
: null;
if (newServiceValue !== newValue || newValue === null) {
$scope.webhookCredential.id = null;
$scope.webhookCredential.name = null;
}
}
});
hashSetup({
scope: $scope,
master: master,
@ -182,6 +289,17 @@
});
}
function sync_webhook_service_select2() {
CreateSelect2({
element:'#webhook-service-select',
addNew: false,
multiple: false,
scope: $scope,
options: 'webhook_service_options',
model: 'webhook_service'
});
}
$scope.toggleForm = function(key) {
$scope[key] = !$scope[key];
};
@ -344,6 +462,10 @@
delete data.credential;
delete data.vault_credential;
delete data.webhook_url;
data.webhook_credential = $scope.webhookCredential.id;
if (!data.webhook_credential) {
data.webhook_service = null;
}
data.extra_vars = ToJSON($scope.parseType, $scope.extra_vars, true);

View File

@ -19,7 +19,7 @@ export default
'initSurvey', '$state', 'CreateSelect2', 'isNotificationAdmin',
'ToggleNotification','$q', 'InstanceGroupsService', 'InstanceGroupsData',
'MultiCredentialService', 'availableLabels', 'projectGetPermissionDenied',
'inventoryGetPermissionDenied', 'jobTemplateData', 'ParseVariableString', 'ConfigData',
'inventoryGetPermissionDenied', 'jobTemplateData', 'ParseVariableString', 'ConfigData', '$compile',
function(
$filter, $scope,
$stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
@ -29,7 +29,7 @@ export default
SurveyControllerInit, $state, CreateSelect2, isNotificationAdmin,
ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData,
MultiCredentialService, availableLabels, projectGetPermissionDenied,
inventoryGetPermissionDenied, jobTemplateData, ParseVariableString, ConfigData
inventoryGetPermissionDenied, jobTemplateData, ParseVariableString, ConfigData, $compile
) {
$scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) {
@ -63,7 +63,7 @@ export default
$scope.playbook_options = null;
$scope.webhook_service_options = null;
$scope.playbook = null;
$scope.webhook_service = null;
$scope.webhook_service = jobTemplateData.webhook_service;
$scope.webhook_url = '';
$scope.mode = 'edit';
$scope.parseType = 'yaml';
@ -77,6 +77,119 @@ export default
$scope.custom_virtualenvs_options = virtualEnvs;
$scope.webhook_url_help = i18n._('Webhook services can launch jobs with this job template by making a POST request to this URL.');
//
// webhook credential - all handlers, dynamic state, etc. live here
//
$scope.webhookCredential = {
id: _.get(jobTemplateData, ['summary_fields', 'webhook_credential', 'id']),
name: _.get(jobTemplateData, ['summary_fields', 'webhook_credential', 'name']),
isModalOpen: false,
isModalReady: false,
modalTitle: i18n._('Select Webhook Credential'),
modalBaseParams: {
order_by: 'name',
page_size: 5,
credential_type__namespace: `${jobTemplateData.webhook_service}_token`,
},
modalSelectedId: null,
modalSelectedName: null,
};
$scope.handleWebhookCredentialLookupClick = () => {
$scope.webhookCredential.modalSelectedId = $scope.webhookCredential.id;
$scope.webhookCredential.isModalOpen = true;
};
$scope.handleWebhookCredentialTagDelete = () => {
$scope.webhookCredential.id = null;
$scope.webhookCredential.name = null;
};
$scope.handleWebhookCredentialModalClose = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
};
$scope.handleWebhookCredentialModalReady = () => {
$scope.webhookCredential.isModalReady = true;
};
$scope.handleWebhookCredentialModalItemSelect = (item) => {
$scope.webhookCredential.modalSelectedId = item.id;
$scope.webhookCredential.modalSelectedName = item.name;
};
$scope.handleWebhookCredentialModalCancel = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
$scope.webhookCredential.modalSelectedId = null;
$scope.webhookCredential.modalSelectedName = null;
};
$scope.handleWebhookCredentialSelect = () => {
$scope.webhookCredential.isModalOpen = false;
$scope.webhookCredential.isModalReady = false;
$scope.webhookCredential.id = $scope.webhookCredential.modalSelectedId;
$scope.webhookCredential.name = $scope.webhookCredential.modalSelectedName;
$scope.webhookCredential.modalSelectedId = null;
$scope.webhookCredential.modalSelectedName = null;
};
$('#content-container').append($compile(`
<at-dialog
title="webhookCredential.modalTitle"
on-close="handleWebhookCredentialModalClose"
ng-if="webhookCredential.isModalOpen"
ng-show="webhookCredential.isModalOpen && webhookCredential.isModalReady"
>
<at-lookup-list
ng-show="webhookCredential.isModalOpen && webhookCredential.isModalReady"
resource-name="credential"
base-params="webhookCredential.modalBaseParams"
selected-id="webhookCredential.modalSelectedId"
on-ready="handleWebhookCredentialModalReady"
on-item-select="handleWebhookCredentialModalItemSelect"
/>
<at-action-group col="12" pos="right">
<at-action-button
variant="tertiary"
ng-click="handleWebhookCredentialModalCancel()"
>
${i18n._('CANCEL')}
</at-action-button>
<at-action-button
variant="primary"
ng-click="handleWebhookCredentialSelect()"
>
${i18n._('SELECT')}
</at-action-button>
</at-action-group>
</at-dialog>`)($scope));
$scope.$watch('webhook_service', (newValue, oldValue) => {
const newServiceValue = newValue && typeof newValue === 'object' ? newValue.value : newValue;
const oldServiceValue = oldValue && typeof oldValue === 'object' ? oldValue.value : oldValue;
if (newServiceValue) {
$scope.webhook_url = `${$scope.callback_server_path}${jobTemplateData.url}${newServiceValue}`;
} else {
$scope.webhook_url = '';
}
if (newServiceValue !== oldServiceValue || newServiceValue === newValue) {
$scope.webhook_service = { value: newServiceValue };
sync_webhook_service_select2();
$scope.webhookCredential.modalBaseParams.credential_type__namespace = newServiceValue ?
`${newServiceValue}_token` : null;
if (newServiceValue !== newValue || newValue === null) {
$scope.webhookCredential.id = null;
$scope.webhookCredential.name = null;
}
}
});
$scope.$watch('verbosity', sync_verbosity_select2);
SurveyControllerInit({
scope: $scope,
parent_scope: $scope,
@ -178,24 +291,6 @@ export default
}
}
});
// watch for changes to 'verbosity', ensure we keep our select2 in sync when it changes.
$scope.$watch('verbosity', sync_verbosity_select2);
$scope.$watch('webhook_service', (newValue) => {
if (newValue) {
// TODO: We'll need the host from the server.
const baseURL = window.location.origin;
if (typeof newValue === 'string') {
$scope.webhook_url = `${baseURL}${jobTemplateData.url}${newValue}`;
$scope.webhook_service = { value: newValue };
} else {
$scope.webhook_url = `${baseURL}${jobTemplateData.url}${newValue.value}`;
}
} else {
$scope.webhook_url = '';
}
sync_webhook_service_select2();
});
}
callback = function() {
@ -229,7 +324,7 @@ export default
scope: $scope,
options: 'webhook_service_options',
model: 'webhook_service'
}));
}));
}
function jobTemplateLoadFinished(){
@ -775,7 +870,12 @@ export default
data.job_tags = (Array.isArray($scope.job_tags)) ? _.uniq($scope.job_tags).join() : "";
data.skip_tags = (Array.isArray($scope.skip_tags)) ? _.uniq($scope.skip_tags).join() : "";
delete data.webhook_url;
data.webhook_credential = $scope.webhookCredential.id;
if (!data.webhook_credential) {
data.webhook_service = null;
}
Rest.setUrl(defaultUrl + $state.params.job_template_id);
Rest.patch(data)

View File

@ -419,6 +419,23 @@ function(NotificationsList, i18n) {
dataContainer: "body",
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
},
webhook_credential: {
label: i18n._('Webhook Credential'),
type: 'custom',
control: `
<webhook-credential-input
is-field-disabled="!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate) || !(webhookCredential.modalBaseParams.credential_type__namespace)"
tag-name="webhookCredential.name"
on-lookup-click="handleWebhookCredentialLookupClick"
on-tag-delete="handleWebhookCredentialTagDelete"
</webhook-credential-input>`,
awPopOver: "<p>" + i18n._("Select the credential to use with the webhook service.") + "</p>",
dataTitle: i18n._('Webhook Credential'),
dataPlacement: 'right',
dataContainer: "body",
ngDisabled: 'canAddJobTemplate',
required: false,
},
extra_vars: {
label: i18n._('Extra Variables'),
type: 'textarea',

View File

@ -1,13 +1,13 @@
import jobTemplateAdd from './add-job-template/main';
import jobTemplateEdit from './edit-job-template/main';
import multiCredential from './multi-credential/main';
import webhookCredential from './webhook-credential';
import hashSetup from './factories/hash-setup.factory';
import CallbackHelpInit from './factories/callback-help-init.factory';
import JobTemplateForm from './job-template.form';
export default
angular.module('jobTemplates', [jobTemplateAdd.name, jobTemplateEdit.name,
multiCredential.name])
.factory('hashSetup', hashSetup)
.factory('CallbackHelpInit', CallbackHelpInit)
.factory('JobTemplateForm', JobTemplateForm);
angular.module('jobTemplates', [jobTemplateAdd.name, jobTemplateEdit.name, multiCredential.name, webhookCredential.name])
.factory('hashSetup', hashSetup)
.factory('CallbackHelpInit', CallbackHelpInit)
.factory('JobTemplateForm', JobTemplateForm);

View File

@ -0,0 +1,4 @@
import webhookCredentialInput from './webhook-credential-input.component';
export default angular.module('webhookCredential', [])
.component('webhookCredentialInput', webhookCredentialInput);

View File

@ -0,0 +1,9 @@
import webhookCredential from './webhook-credential.directive';
import webhookCredentialModal from './webhook-credential-modal.directive';
import webhookCredentialService from './webhook-credential.service';
export default
angular.module('webhookCredential', [])
.directive('webhookCredential', webhookCredential)
.directive('webhookCredentialModal', webhookCredentialModal)
.service('WebhookCredentialService', webhookCredentialService);

View File

@ -0,0 +1,11 @@
const templateUrl = require('~src/templates/job_templates/webhook-credential/webhook-credential-input.partial.html');
export default {
templateUrl,
controllerAs: 'vm',
bindings: {
isFieldDisabled: '<',
tagName: '<',
onLookupClick: '<',
onTagDelete: '<',
},
};

View File

@ -0,0 +1,43 @@
<div class="input-group Form-mixedInputGroup">
<span class="input-group-btn Form-variableHeightButtonGroup input-group-prepend">
<button type="button"
class="Form-lookupButton
Form-lookupButton--variableHeight btn btn-default"
ng-click="vm.onLookupClick()"
ng-disabled="vm.isFieldDisabled">
<i class="fa fa-search"></i>
</button>
</span>
<span class="form-control Form-textInput Form-textInput--variableHeight input-medium lookup"
ng-disabled="vm.isFieldDisabled"
style="padding: 4px 6px;">
<div class="WebhookCredential-tags" ng-show="vm.tagName">
<div class="WebhookCredential-tagSection">
<div class="WebhookCredential-flexContainer">
<div class="WebhookCredential-tagContainer ng-scope"
ng-class="{'WebhookCredential-tagContainer--disabled': vm.tag.readOnly}">
<div class="WebhookCredential-iconContainer--disabled" ng-if="vm.isFieldDisabled">
<i class="fa fa-archive WebhookCredential-tagIcon"></i>
</div>
<div class="WebhookCredential-iconContainer" ng-if="!vm.isFieldDisabled">
<i class="fa fa-archive WebhookCredential-tagIcon"></i>
</div>
<div
class="WebhookCredential-tag"
ng-class="{'WebhookCredential-tag--deletable': !vm.isFieldDisabled, 'WebhookCredential-tag--disabled': vm.isFieldDisabled}"
>
<span class="WebhookCredential-name--label ng-binding">
{{ vm.tagName }}
</span>
</div>
<div class="WebhookCredential-deleteContainer"
ng-click="vm.onTagDelete()"
ng-hide="vm.isFieldDisabled">
<i class="fa fa-times WebhookCredential-tagDelete"></i>
</div>
</div>
</div>
</div>
</div>
</span>
</div>

View File

@ -0,0 +1,113 @@
.WebhookCredential-tags {
padding-left: 0px;
}
.WebhookCredential-flexContainer {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.WebhookCredential-tagContainer {
display: flex;
max-width: 100%;
background-color: @default-link;
color: @default-bg;
border-radius: 5px;
padding: 0px 0px 0px 10px;
margin: 3px 10px 3px 0px;
}
.WebhookCredential-tagContainer--disabled {
background-color: @default-icon;
}
.WebhookCredential-tag {
font-size: 12px;
margin-right: 10px;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding: 2px 0px 2px 15px;
}
.WebhookCredential-tag--disabled {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
padding-left: 10px;
}
.WebhookCredential-tag--deletable {
margin-right: 0px;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
border-right: 0;
max-width: ~"calc(100% - 23px)";
padding-left: 10px;
}
.WebhookCredential-deleteContainer {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
padding: 2px 5px;
align-items: center;
display: flex;
cursor: pointer;
}
.WebhookCredential-tagDelete {
font-size: 11px;
}
.WebhookCredential-iconContainer {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
padding: 0px 5px;
margin: 3px 0px;
margin-left: -3px;
align-items: center;
display: flex;
}
.WebhookCredential-iconContainer--disabled {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
padding: 0 5px;
padding-left: 10px;
margin: 3px 0px;
align-items: center;
display: flex;
}
.WebhookCredential-tagIcon {
margin: 0px 0px;
font-size: 12px;
}
.WebhookCredential-name {
flex: initial;
font-size: 12px;
max-width: 100%;
}
.WebhookCredential-name--label {
color: @default-list-header-bg;
font-size: 12px;
margin-left: -8px;
margin-right: 5px;
}
.WebhookCredential-tag--deletable > .WebhookCredential-name {
max-width: ~"calc(100% - 23px)";
}
.WebhookCredential-deleteContainer:hover {
border-color: @default-err;
background-color: @default-err!important;
}
.WebhookCredential-deleteContainer:hover > .WebhookCredential-tagDelete {
color: @default-bg;
}