From ac2c79359b039e389e9c32e67c81fafe4c3abf59 Mon Sep 17 00:00:00 2001 From: Oleg Ivaniv Date: Thu, 2 Feb 2023 19:43:49 +0100 Subject: [PATCH] Revert "feat(core): Fix populating of node custom api call options (#5303)" This reverts commit e58bc41d241b3f4a1701191f69e5eadad969bc5f. --- cypress/e2e/5-ndv.cy.ts | 12 ---- cypress/pages/ndv.ts | 1 - packages/cli/src/api/nodeTypes.api.ts | 62 ++++++++++++++++++- packages/core/src/Constants.ts | 2 - packages/core/src/DirectoryLoader.ts | 54 ++-------------- .../Node/NodeCreator/TriggerHelperPanel.vue | 19 +++++- .../editor-ui/src/components/NodeSettings.vue | 6 +- packages/editor-ui/src/stores/nodeCreator.ts | 7 +-- 8 files changed, 85 insertions(+), 78 deletions(-) diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index f535ab363870f..9fead48e51a4c 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -87,16 +87,4 @@ describe('NDV', () => { cy.get('[class*=hasIssues]').should('have.length', 1); }); }); - - it('should show http node hint if node has custom api option', () => { - workflowPage.actions.addNodeToCanvas('Manual Trigger'); - workflowPage.actions.addNodeToCanvas('Slack', true, true); - ndv.getters.httpRequestNotice().should('not.exist'); - ndv.getters.parameterInput('operation').click(); - ndv.getters.parameterInput('operation').contains('Custom API').click(); - ndv.getters.httpRequestNotice().should('be.visible'); - ndv.getters.parameterInput('operation').click(); - ndv.getters.parameterInput('operation').contains('Post').click(); - ndv.getters.httpRequestNotice().should('not.exist'); - }); }); diff --git a/cypress/pages/ndv.ts b/cypress/pages/ndv.ts index 3761db326f3b9..ba38b940652e8 100644 --- a/cypress/pages/ndv.ts +++ b/cypress/pages/ndv.ts @@ -27,7 +27,6 @@ export class NDV extends BasePage { parameterInput: (parameterName: string) => cy.getByTestId(`parameter-input-${parameterName}`), nodeNameContainer: () => cy.getByTestId('node-title-container'), nodeRenameInput: () => cy.getByTestId('node-rename-input'), - httpRequestNotice: () => cy.getByTestId('node-parameters-http-notice'), }; actions = { diff --git a/packages/cli/src/api/nodeTypes.api.ts b/packages/cli/src/api/nodeTypes.api.ts index 6c55d195661be..1e0eb7c6227b4 100644 --- a/packages/cli/src/api/nodeTypes.api.ts +++ b/packages/cli/src/api/nodeTypes.api.ts @@ -2,13 +2,69 @@ import express from 'express'; import { readFile } from 'fs/promises'; import get from 'lodash.get'; -import type { INodeTypeDescription, INodeTypeNameVersion } from 'n8n-workflow'; +import type { ICredentialType, INodeTypeDescription, INodeTypeNameVersion } from 'n8n-workflow'; +import { CredentialTypes } from '@/CredentialTypes'; import config from '@/config'; import { NodeTypes } from '@/NodeTypes'; import * as ResponseHelper from '@/ResponseHelper'; import { getNodeTranslationPath } from '@/TranslationHelpers'; +function isOAuth(credType: ICredentialType) { + return ( + Array.isArray(credType.extends) && + credType.extends.some((parentType) => + ['oAuth2Api', 'googleOAuth2Api', 'oAuth1Api'].includes(parentType), + ) + ); +} + +/** + * Whether any of the node's credential types may be used to + * make a request from a node other than itself. + */ +function supportsProxyAuth(description: INodeTypeDescription) { + if (!description.credentials) return false; + + const credentialTypes = CredentialTypes(); + + return description.credentials.some(({ name }) => { + const credType = credentialTypes.getByName(name); + + if (credType.authenticate !== undefined) return true; + + return isOAuth(credType); + }); +} + +const CUSTOM_API_CALL_NAME = 'Custom API Call'; +const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__'; + +/** + * Inject a `Custom API Call` option into `resource` and `operation` + * parameters in a node that supports proxy auth. + */ +function injectCustomApiCallOption(description: INodeTypeDescription) { + if (!supportsProxyAuth(description)) return description; + + description.properties.forEach((p) => { + if ( + ['resource', 'operation'].includes(p.name) && + Array.isArray(p.options) && + p.options[p.options.length - 1].name !== CUSTOM_API_CALL_NAME + ) { + p.options.push({ + name: CUSTOM_API_CALL_NAME, + value: CUSTOM_API_CALL_KEY, + }); + } + + return p; + }); + + return description; +} + export const nodeTypesController = express.Router(); // Returns node information based on node names and versions @@ -22,7 +78,7 @@ nodeTypesController.post( if (defaultLocale === 'en') { return nodeInfos.reduce((acc, { name, version }) => { const { description } = NodeTypes().getByNameAndVersion(name, version); - acc.push(description); + acc.push(injectCustomApiCallOption(description)); return acc; }, []); } @@ -47,7 +103,7 @@ nodeTypesController.post( // ignore - no translation exists at path } - nodeTypes.push(description); + nodeTypes.push(injectCustomApiCallOption(description)); } const nodeTypes: INodeTypeDescription[] = []; diff --git a/packages/core/src/Constants.ts b/packages/core/src/Constants.ts index 45c1741dd020e..6d2fe99321336 100644 --- a/packages/core/src/Constants.ts +++ b/packages/core/src/Constants.ts @@ -11,8 +11,6 @@ export const PLACEHOLDER_EMPTY_EXECUTION_ID = '__UNKNOWN__'; export const PLACEHOLDER_EMPTY_WORKFLOW_ID = '__EMPTY__'; export const TUNNEL_SUBDOMAIN_ENV = 'N8N_TUNNEL_SUBDOMAIN'; export const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z'; -export const CUSTOM_API_CALL_NAME = 'Custom API Call'; -export const CUSTOM_API_CALL_KEY = '__CUSTOM_API_CALL__'; export const RESPONSE_ERROR_MESSAGES = { NO_ENCRYPTION_KEY: 'Encryption key is missing or was not set', diff --git a/packages/core/src/DirectoryLoader.ts b/packages/core/src/DirectoryLoader.ts index 0af2f534f230d..0682cfec7c9a9 100644 --- a/packages/core/src/DirectoryLoader.ts +++ b/packages/core/src/DirectoryLoader.ts @@ -15,7 +15,7 @@ import type { IVersionedNodeType, KnownNodesAndCredentials, } from 'n8n-workflow'; -import { CUSTOM_NODES_CATEGORY, CUSTOM_API_CALL_KEY, CUSTOM_API_CALL_NAME } from './Constants'; +import { CUSTOM_NODES_CATEGORY } from './Constants'; import type { n8n } from './Interfaces'; import { loadClassInIsolation } from './ClassLoader'; @@ -54,48 +54,6 @@ export abstract class DirectoryLoader { return path.resolve(this.directory, file); } - /** - * Whether any of the node's credential types may be used to - * make a request from a node other than itself. - */ - private supportsProxyAuth(description: INodeTypeDescription) { - if (!description.credentials) return false; - - return description.credentials.some(({ name }) => { - const credType = this.credentialTypes[name].type; - - if (credType.authenticate !== undefined) return true; - - return ( - Array.isArray(credType.extends) && - credType.extends.some((parentType) => - ['oAuth2Api', 'googleOAuth2Api', 'oAuth1Api'].includes(parentType), - ) - ); - }); - } - - /** - * Inject a `Custom API Call` option into `resource` and `operation` - * parameters in a node that supports proxy auth. - */ - private injectCustomApiCallOption(description: INodeTypeDescription) { - if (!this.supportsProxyAuth(description)) return; - - description.properties.forEach((p) => { - if ( - ['resource', 'operation'].includes(p.name) && - Array.isArray(p.options) && - p.options[p.options.length - 1].name !== CUSTOM_API_CALL_NAME - ) { - p.options.push({ - name: CUSTOM_API_CALL_NAME, - value: CUSTOM_API_CALL_KEY, - }); - } - }); - } - protected loadNodeFromFile(packageName: string, nodeName: string, filePath: string) { let tempNode: INodeType | IVersionedNodeType; let nodeVersion = 1; @@ -131,7 +89,6 @@ export abstract class DirectoryLoader { const currentVersionNode = tempNode.nodeVersions[tempNode.currentVersion]; this.addCodex({ node: currentVersionNode, filePath, isCustom: packageName === 'CUSTOM' }); - this.injectCustomApiCallOption(currentVersionNode.description); nodeVersion = tempNode.currentVersion; if (currentVersionNode.hasOwnProperty('executeSingle')) { @@ -142,11 +99,10 @@ export abstract class DirectoryLoader { } } else { // Short renaming to avoid type issues - - this.injectCustomApiCallOption(tempNode.description); - nodeVersion = Array.isArray(tempNode.description.version) - ? tempNode.description.version.slice(-1)[0] - : tempNode.description.version; + const tmpNode = tempNode; + nodeVersion = Array.isArray(tmpNode.description.version) + ? tmpNode.description.version.slice(-1)[0] + : tmpNode.description.version; } this.known.nodes[fullNodeName] = { diff --git a/packages/editor-ui/src/components/Node/NodeCreator/TriggerHelperPanel.vue b/packages/editor-ui/src/components/Node/NodeCreator/TriggerHelperPanel.vue index 3ce89f63d167c..ad6d2dfaa7dbd 100644 --- a/packages/editor-ui/src/components/Node/NodeCreator/TriggerHelperPanel.vue +++ b/packages/editor-ui/src/components/Node/NodeCreator/TriggerHelperPanel.vue @@ -233,7 +233,7 @@ const telemetry = instance?.proxy.$telemetry; const { categorizedItems: allNodes, isTriggerNode } = useNodeTypesStore(); const containsAPIAction = computed( () => - activeNodeActions.value?.properties.some((p) => + state.latestNodeData?.properties.some((p) => p.options?.find((o) => o.name === CUSTOM_API_CALL_NAME), ) === true, ); @@ -338,10 +338,27 @@ function getCustomAPICallHintLocale(key: string) { interpolate: { nodeNameTitle }, }); } +// The nodes.json doesn't contain API CALL option so we need to fetch the node detail +// to determine if need to render the API CALL hint +async function fetchNodeDetails() { + if (!state.activeNodeActions) return; + + const { getNodesInformation } = useNodeTypesStore(); + const { version, name } = state.activeNodeActions; + const payload = { + name, + version: Array.isArray(version) ? version?.slice(-1)[0] : version, + } as INodeTypeNameVersion; + + const nodesInfo = await getNodesInformation([payload], false); + + state.latestNodeData = nodesInfo[0]; +} function setActiveActionsNodeType(nodeType: INodeTypeDescription | null) { state.activeNodeActions = nodeType; setShowTabs(false); + fetchNodeDetails(); if (nodeType) trackActionsView(); } diff --git a/packages/editor-ui/src/components/NodeSettings.vue b/packages/editor-ui/src/components/NodeSettings.vue index b1673a6f13217..e533e20f8c050 100644 --- a/packages/editor-ui/src/components/NodeSettings.vue +++ b/packages/editor-ui/src/components/NodeSettings.vue @@ -116,11 +116,7 @@ -
+