🔀 Merge scopes branch

This commit is contained in:
Iván Ovejero 2022-05-05 18:14:09 +02:00
commit a708b3195a
6 changed files with 54 additions and 0 deletions

View file

@ -296,6 +296,9 @@ export class CredentialsHelper extends ICredentialsHelper {
getScopes(type: string): string[] { getScopes(type: string): string[] {
const scopeProperty = this.getCredentialsProperties(type).find(({ name }) => name === 'scope'); const scopeProperty = this.getCredentialsProperties(type).find(({ name }) => name === 'scope');
// edge case: scope property exists but is required to be empty string, e.g. GoToWebinar
if (scopeProperty?.default === '') return [];
if (!scopeProperty?.default || typeof scopeProperty.default !== 'string') { if (!scopeProperty?.default || typeof scopeProperty.default !== 'string') {
const errorMessage = `No \`scope\` property found for credential type: ${type}`; const errorMessage = `No \`scope\` property found for credential type: ${type}`;

View file

@ -184,6 +184,7 @@ export interface IRestApi {
retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean>; retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean>;
getTimezones(): Promise<IDataObject>; getTimezones(): Promise<IDataObject>;
getBinaryBufferString(dataPath: string): Promise<string>; getBinaryBufferString(dataPath: string): Promise<string>;
getScopes: (credentialType: string) => Promise<string[]>;
} }
export interface INodeTranslationHeaders { export interface INodeTranslationHeaders {

View file

@ -77,6 +77,7 @@ import { showMessage } from '@/components/mixins/showMessage';
import { mapGetters } from "vuex"; import { mapGetters } from "vuex";
import mixins from 'vue-typed-mixins'; import mixins from 'vue-typed-mixins';
import { HTTP_REQUEST_NODE_TYPE } from '@/constants';
export default mixins( export default mixins(
genericHelpers, genericHelpers,
@ -126,6 +127,10 @@ export default mixins(
credentialTypesNodeDescription (): INodeCredentialDescription[] { credentialTypesNodeDescription (): INodeCredentialDescription[] {
const node = this.node as INodeUi; const node = this.node as INodeUi;
if (this.isHttpRequestNodeV2(this.node)) {
this.$emit('newHttpRequestNodeCredentialType', this.node.parameters.nodeCredentialType);
}
if (this.isGenericAuth) { if (this.isGenericAuth) {
const { genericAuthType } = this.node.parameters as { genericAuthType: string }; const { genericAuthType } = this.node.parameters as { genericAuthType: string };

View file

@ -23,6 +23,20 @@
</div> </div>
<div class="node-parameters-wrapper" v-if="node && nodeValid"> <div class="node-parameters-wrapper" v-if="node && nodeValid">
<div v-show="openPanel === 'params'"> <div v-show="openPanel === 'params'">
<n8n-notice
v-if="isHttpRequestNodeV2(node) && scopes.length > 0"
:truncate="true"
:content="$locale.baseText(
'nodeSettings.scopes',
{
adjustToNumber: scopes.length,
interpolate: {
activeCredential,
scopes: scopes.join(' '),
},
},
)"
/>
<node-webhooks <node-webhooks
:node="node" :node="node"
:nodeType="nodeType" :nodeType="nodeType"
@ -37,6 +51,7 @@
:node="node" :node="node"
@credentialSelected="credentialSelected" @credentialSelected="credentialSelected"
@newActiveCredentialType="checkIfSupportedByHttpRequestNode" @newActiveCredentialType="checkIfSupportedByHttpRequestNode"
@newHttpRequestNodeCredentialType="loadScopesNoticeData"
/> />
</parameter-input-list> </parameter-input-list>
<div v-if="parametersNoneSetting.length === 0" class="no-parameters"> <div v-if="parametersNoneSetting.length === 0" class="no-parameters">
@ -97,6 +112,7 @@ import { nodeHelpers } from '@/components/mixins/nodeHelpers';
import mixins from 'vue-typed-mixins'; import mixins from 'vue-typed-mixins';
import NodeExecuteButton from './NodeExecuteButton.vue'; import NodeExecuteButton from './NodeExecuteButton.vue';
import { mapGetters } from 'vuex';
export default mixins( export default mixins(
externalHooks, externalHooks,
@ -115,6 +131,7 @@ export default mixins(
NodeExecuteButton, NodeExecuteButton,
}, },
computed: { computed: {
...mapGetters('credentials', [ 'getCredentialTypeByName' ]),
customActionSelected (): boolean { customActionSelected (): boolean {
return ( return (
this.nodeValues.parameters !== undefined && this.nodeValues.parameters !== undefined &&
@ -210,6 +227,8 @@ export default mixins(
parameters: {}, parameters: {},
} as INodeParameters, } as INodeParameters,
isSupportedByHttpRequestNode: false, isSupportedByHttpRequestNode: false,
activeCredential: '',
scopes: [] as string[],
nodeSettings: [ nodeSettings: [
{ {
@ -322,6 +341,21 @@ export default mixins(
credentialType.authenticate !== undefined credentialType.authenticate !== undefined
); );
}, },
async loadScopesNoticeData(activeCredentialType: string) {
if (!this.isHttpRequestNodeV2(this.node)) return;
if (
!activeCredentialType ||
!activeCredentialType.endsWith('OAuth2Api')
) {
this.scopes = [];
return;
}
this.activeCredential = this.getCredentialTypeByName(activeCredentialType).displayName;
this.scopes = await this.restApi().getScopes(activeCredentialType);
},
onNodeExecute () { onNodeExecute () {
this.$emit('execute'); this.$emit('execute');
}, },
@ -620,6 +654,11 @@ export default mixins(
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
padding: 0 20px 200px 20px; padding: 0 20px 200px 20px;
// @TODO Revisit
> div > .notice[role=alert] {
margin-top: var(--spacing-s);
}
} }
} }

View file

@ -195,6 +195,11 @@ export const restApi = Vue.extend({
getBinaryBufferString: (dataPath: string): Promise<string> => { getBinaryBufferString: (dataPath: string): Promise<string> => {
return self.restApi().makeRestApiRequest('GET', `/data/${dataPath}`); return self.restApi().makeRestApiRequest('GET', `/data/${dataPath}`);
}, },
// Returns scopes for OAuth credential types
getScopes: (credentialType: string): Promise<string[]> => {
return self.restApi().makeRestApiRequest('GET', '/oauth2-credential/scopes', { credentialType });
},
}; };
}, },
}, },

View file

@ -412,6 +412,7 @@
"nodeSettings.waitBetweenTries.description": "How long to wait between each attempt (in milliseconds)", "nodeSettings.waitBetweenTries.description": "How long to wait between each attempt (in milliseconds)",
"nodeSettings.waitBetweenTries.displayName": "Wait Between Tries (ms)", "nodeSettings.waitBetweenTries.displayName": "Wait Between Tries (ms)",
"nodeSettings.youCanUseTheHttpRequestNode": "You can use the <b>HTTP Request</b> node to make a custom API call with your {nodeTypeDisplayName} credential. <a href=PENDING_WAITING_ON_DEB>Learn more</a>", "nodeSettings.youCanUseTheHttpRequestNode": "You can use the <b>HTTP Request</b> node to make a custom API call with your {nodeTypeDisplayName} credential. <a href=PENDING_WAITING_ON_DEB>Learn more</a>",
"nodeSettings.scopes": "Your <b>{activeCredential}</b> credential has access to the following scope:<br>{scopes} | Your <b>{activeCredential}</b> credential has access to the following scopes:<br>{scopes}",
"nodeView.addNode": "Add node", "nodeView.addNode": "Add node",
"nodeView.addSticky": "Click to add sticky note", "nodeView.addSticky": "Click to add sticky note",
"nodeView.confirmMessage.beforeRouteLeave.cancelButtonText": "Leave without saving", "nodeView.confirmMessage.beforeRouteLeave.cancelButtonText": "Leave without saving",