Skip to content

Commit

Permalink
Refactor to use CredentialsSelect param (#3304)
Browse files Browse the repository at this point in the history
* ⚡ Refactor into cred type param

* ⚡ Componentize scopes notice

* 🔥 Remove unused data

* 🔥 Remove unused `loadOptions`

* ⚡ Componentize `NodeCredentialType`

* 🐛 Fix param validation

* 🔥 Remove dup methods

* ⚡ Refactor all references to `isHttpRequestNodeV2`

* 🎨 Fix styling

* 🔥 Remove unused import

* 🔥 Remove unused properties

* 🎨 Fix spacing for Pipedrive Trigger node

* 🎨 Undo Webhook node styling change

* 🔥 Remove unused style

* ⚡ Cover `httpHeaderAuth` edge case

* 🐛 Fix `this.node` reference

* 🚚 Rename to `credentialsSelect`

* 🐛 Fix mistaken renaming

* ⚡ Set one attribute per line

* ⚡ Move condition to instantiation site

* 🚚 Rename prop

* ⚡ Refactor away `prepareScopesNotice`

* ✏️ Rename i18n keys

* ✏️ Update i18n calls

* ✏️ Add more i18n keys

* 🔥 Remove unused props

* ✏️ Add explanatory comment

* ⚡ Adjust check in `hasProxyAuth`

* ⚡ Refactor `credentialSelected` from prop to event

* ⚡ Eventify `valueChanged`, `setFocus`, `onBlur`

* ⚡ Eventify `optionSelected`

* ⚡ Add `noDataExpression`

* 🔥 Remove logging

* 🔥 Remove URL from scopes

* ⚡ Disregard expressions for display

* 🎨 Use CSS modules

* 📘 Tigthen interface

* 🐛 Fix generic auth display

* 🐛 Fix generic auth validation

* 📘 Loosen type

* 🚚 Move event params to end

* ⚡ Generalize reference

* ⚡ Refactor generic auth as `credentialsSelect` param

* ⏪ Restore check for `httpHeaderAuth `

* 🚚 Rename `existing` to `predefined`
  • Loading branch information
ivov authored May 19, 2022
1 parent 333506a commit 2ac022e
Show file tree
Hide file tree
Showing 21 changed files with 462 additions and 274 deletions.
152 changes: 152 additions & 0 deletions packages/editor-ui/src/components/CredentialsSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<template>
<div>
<div :class="$style['parameter-value-container']">
<n8n-select
:size="inputSize"
filterable
:value="displayValue"
:placeholder="parameter.placeholder ? getPlaceholder() : $locale.baseText('parameterInput.select')"
:title="displayTitle"
@change="(value) => $emit('valueChanged', value)"
@keydown.stop
@focus="$emit('setFocus')"
@blur="$emit('onBlur')"
>
<n8n-option
v-for="credType in supportedCredentialTypes"
:value="credType.name"
:key="credType.name"
>
<div class="list-option">
<div class="option-headline">
{{ credType.displayName }}
</div>
<div
v-if="credType.description"
class="option-description"
v-html="credType.description"
/>
</div>
</n8n-option>
</n8n-select>
<slot name="issues-and-options" />
</div>

<scopes-notice
v-if="scopes.length > 0"
:activeCredentialType="activeCredentialType"
:scopes="scopes"
/>
<div>
<node-credentials
:node="node"
:overrideCredType="node.parameters[parameter.name]"
@credentialSelected="(updateInformation) => $emit('credentialSelected', updateInformation)"
/>
</div>
</div>
</template>

<script lang="ts">
import { ICredentialType } from 'n8n-workflow';
import Vue from 'vue';
import { mapGetters } from 'vuex';
import ScopesNotice from '@/components/ScopesNotice.vue';
import NodeCredentials from '@/components/NodeCredentials.vue';
export default Vue.extend({
name: 'CredentialsSelect',
components: {
ScopesNotice,
NodeCredentials,
},
props: [
'activeCredentialType',
'node',
'parameter',
'inputSize',
'displayValue',
'isReadOnly',
'displayTitle',
],
computed: {
...mapGetters('credentials', ['allCredentialTypes', 'getScopesByCredentialType']),
scopes(): string[] {
if (!this.activeCredentialType) return [];
return this.getScopesByCredentialType(this.activeCredentialType);
},
supportedCredentialTypes(): ICredentialType[] {
return this.allCredentialTypes.filter((c: ICredentialType) => this.isSupported(c.name));
},
},
methods: {
/**
* Check if a credential type belongs to one of the supported sets defined
* in the `credentialTypes` key in a `credentialsSelect` parameter
*/
isSupported(name: string): boolean {
const supported = this.getSupportedSets(this.parameter.credentialTypes);
const checkedCredType = this.$store.getters['credentials/getCredentialTypeByName'](name);
for (const property of supported.has) {
if (checkedCredType[property] !== undefined) {
// edge case: `httpHeaderAuth` has `authenticate` auth but belongs to generic auth
if (name === 'httpHeaderAuth' && property === 'authenticate') continue;
return true;
}
}
if (
checkedCredType.extends &&
checkedCredType.extends.some(
(parentType: string) => supported.extends.includes(parentType),
)
) {
return true;
}
if (checkedCredType.extends && supported.extends.length) {
// recurse upward until base credential type
// e.g. microsoftDynamicsOAuth2Api -> microsoftOAuth2Api -> oAuth2Api
return checkedCredType.extends.reduce(
(acc: boolean, parentType: string) => acc || this.isSupported(parentType),
false,
);
}
return false;
},
getSupportedSets(credentialTypes: string[]) {
return credentialTypes.reduce<{ extends: string[]; has: string[] }>((acc, cur) => {
const _extends = cur.split('extends:');
if (_extends.length === 2) {
acc.extends.push(_extends[1]);
return acc;
}
const _has = cur.split('has:');
if (_has.length === 2) {
acc.has.push(_has[1]);
return acc;
}
return acc;
}, { extends: [], has: [] });
},
},
});
</script>

<style module lang="scss">
.parameter-value-container {
display: flex;
align-items: center;
}
</style>
27 changes: 4 additions & 23 deletions packages/editor-ui/src/components/NodeCredentials.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default mixins(
name: 'NodeCredentials',
props: [
'node', // INodeUi
'overrideCredType', // cred type
],
data () {
return {
Expand All @@ -99,14 +100,6 @@ export default mixins(
credentialOptions: 'allCredentialsByType',
getCredentialTypeByName: 'getCredentialTypeByName',
}),
isProxyAuth(): boolean {
return this.isHttpRequestNodeV2(this.node) &&
this.node.parameters.authentication === 'existingCredentialType';
},
isGenericAuth(): boolean {
return this.isHttpRequestNodeV2(this.node) &&
this.node.parameters.authentication === 'genericCredentialType';
},
credentialTypesNode (): string[] {
return this.credentialTypesNodeDescription
.map((credentialTypeDescription) => credentialTypeDescription.name);
Expand All @@ -120,17 +113,9 @@ export default mixins(
credentialTypesNodeDescription (): INodeCredentialDescription[] {
const node = this.node as INodeUi;
if (this.isGenericAuth) {
const { genericAuthType } = this.node.parameters as { genericAuthType: string };
return [this.getCredentialTypeByName(genericAuthType)];
}
const credType = this.getCredentialTypeByName(this.overrideCredType);
if (this.isProxyAuth) {
const { nodeCredentialType } = this.node.parameters as { nodeCredentialType?: string };
if (nodeCredentialType) return [this.getCredentialTypeByName(nodeCredentialType)];
}
if (credType) return [credType];
const activeNodeType = this.$store.getters.nodeType(node.type, node.typeVersion) as INodeTypeDescription | null;
if (activeNodeType && activeNodeType.credentials) {
Expand Down Expand Up @@ -321,11 +306,7 @@ export default mixins(

<style lang="scss" module>
.container {
margin: 0;
> * {
margin-bottom: var(--spacing-xs);
}
margin-top: var(--spacing-xs);
}
.warning {
Expand Down
76 changes: 0 additions & 76 deletions packages/editor-ui/src/components/NodeSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@
:hideDelete="true"
:nodeValues="nodeValues" path="parameters" @valueChanged="valueChanged"
>
<n8n-notice
v-if="isHttpRequestNodeV2(node) && this.activeCredential.scopes.length > 0"
:content="scopesShortContent"
:fullContent="scopesFullContent"
/>
<node-credentials
:node="node"
@credentialSelected="credentialSelected"
Expand Down Expand Up @@ -95,7 +90,6 @@ import { nodeHelpers } from '@/components/mixins/nodeHelpers';
import mixins from 'vue-typed-mixins';
import NodeExecuteButton from './NodeExecuteButton.vue';
import { mapGetters } from 'vuex';
export default mixins(
externalHooks,
Expand All @@ -114,10 +108,6 @@ export default mixins(
NodeExecuteButton,
},
computed: {
...mapGetters('credentials', [
'getCredentialTypeByName',
'getScopesByCredentialType',
]),
nodeType (): INodeTypeDescription | null {
if (this.node) {
return this.$store.getters.nodeType(this.node.type, this.node.typeVersion);
Expand Down Expand Up @@ -178,31 +168,6 @@ export default mixins(
return this.nodeType.properties;
},
scopesShortContent (): string {
return this.$locale.baseText(
'nodeSettings.scopes.notice',
{
adjustToNumber: this.activeCredential.scopes.length,
interpolate: {
activeCredential: this.activeCredential.shortDisplayName,
},
},
);
},
scopesFullContent (): string {
return this.$locale.baseText(
'nodeSettings.scopes.expandedNoticeWithScopes',
{
adjustToNumber: this.activeCredential.scopes.length,
interpolate: {
activeCredential: this.activeCredential.shortDisplayName,
scopes: this.activeCredential.scopes.map(
(scope: string) => scope.replace(/\//g, '/<wbr>'),
).join('<br>'),
},
},
);
},
},
props: {
eventBus: {
Expand All @@ -225,10 +190,6 @@ export default mixins(
notes: '',
parameters: {},
} as INodeParameters,
activeCredential: {
shortDisplayName: '',
scopes: [] as string[],
},
nodeSettings: [
{
Expand Down Expand Up @@ -330,28 +291,6 @@ export default mixins(
},
},
methods: {
async prepareScopesNotice(credentialTypeName: string) {
if (
!this.isHttpRequestNodeV2(this.node) ||
!credentialTypeName || !credentialTypeName.endsWith('OAuth2Api')
) {
this.activeCredential.scopes = [];
return;
}
const { name, displayName } = this.getCredentialTypeByName(credentialTypeName);
this.activeCredential.scopes = this.getScopesByCredentialType(name);
this.activeCredential.shortDisplayName = this.shortenCredentialDisplayName(displayName);
},
shortenCredentialDisplayName (credentialDisplayName: string) {
const oauth1Api = this.$locale.baseText('nodeSettings.oauth1Api');
const oauth2Api = this.$locale.baseText('nodeSettings.oauth2Api');
return credentialDisplayName
.replace(new RegExp(`${oauth1Api}|${oauth2Api}`), '')
.trim();
},
onNodeExecute () {
this.$emit('execute');
},
Expand Down Expand Up @@ -428,13 +367,6 @@ export default mixins(
});
},
valueChanged (parameterData: IUpdateInformation) {
if (
this.isHttpRequestNodeV2(this.node) &&
parameterData.name === 'parameters.nodeCredentialType'
) {
this.prepareScopesNotice(parameterData.value as string);
}
let newValue: NodeParameterValue;
if (parameterData.hasOwnProperty('value')) {
// New value is given
Expand Down Expand Up @@ -613,14 +545,6 @@ export default mixins(
},
mounted () {
this.setNodeValues();
if (
this.isHttpRequestNodeV2(this.node) &&
this.node.parameters.authentication === 'existingCredentialType'
) {
this.prepareScopesNotice(this.node.parameters.nodeCredentialType as string);
}
if (this.eventBus) {
(this.eventBus as Vue).$on('openSettings', () => {
this.openPanel = 'settings';
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/components/NodeWebhooks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default mixins(
.webhoooks {
padding-bottom: var(--spacing-xs);
margin: var(--spacing-xs) 0 0 0;
margin: var(--spacing-xs) 0;
border-bottom: 1px solid #ccc;
.headline {
Expand Down
Loading

0 comments on commit 2ac022e

Please sign in to comment.