From 09409ad9f0799e75f41cdd08f6b2f9abf04a57ec Mon Sep 17 00:00:00 2001 From: Dana Lee Date: Mon, 27 Jan 2025 16:31:38 +0100 Subject: [PATCH] Refactor rendering of Form Node and Form Completion Node --- packages/nodes-base/nodes/Form/Form.node.ts | 102 ++---------------- .../nodes/Form/formCompletionUtils.ts | 41 +++++++ .../nodes-base/nodes/Form/formNodeUtils.ts | 80 ++++++++++++++ 3 files changed, 128 insertions(+), 95 deletions(-) create mode 100644 packages/nodes-base/nodes/Form/formCompletionUtils.ts create mode 100644 packages/nodes-base/nodes/Form/formNodeUtils.ts diff --git a/packages/nodes-base/nodes/Form/Form.node.ts b/packages/nodes-base/nodes/Form/Form.node.ts index 03f27219fe..82d8d4c7e4 100644 --- a/packages/nodes-base/nodes/Form/Form.node.ts +++ b/packages/nodes-base/nodes/Form/Form.node.ts @@ -5,6 +5,7 @@ import type { INodeProperties, INodeTypeDescription, IWebhookFunctions, + IWebhookResponseData, NodeTypeAndVersion, } from 'n8n-workflow'; import { @@ -15,12 +16,13 @@ import { FORM_TRIGGER_NODE_TYPE, tryToParseJsonToFormFields, NodeConnectionType, - WAIT_NODE_TYPE, WAIT_INDEFINITELY, } from 'n8n-workflow'; +import { renderFormCompletion } from './formCompletionUtils'; +import { renderFormNode } from './formNodeUtils'; import { formDescription, formFields, formTitle } from '../Form/common.descriptions'; -import { prepareFormReturnItem, renderForm, resolveRawData } from '../Form/utils'; +import { prepareFormReturnItem, resolveRawData } from '../Form/utils'; export const formFieldsProperties: INodeProperties[] = [ { @@ -235,7 +237,7 @@ export class Form extends Node { ], }; - async webhook(context: IWebhookFunctions) { + async webhook(context: IWebhookFunctions): Promise { const res = context.getResponseObject(); const operation = context.getNodeParameter('operation', '') as string; @@ -280,36 +282,7 @@ export class Form extends Node { const method = context.getRequestObject().method; if (operation === 'completion' && method === 'GET') { - const completionTitle = context.getNodeParameter('completionTitle', '') as string; - const completionMessage = context.getNodeParameter('completionMessage', '') as string; - const redirectUrl = context.getNodeParameter('redirectUrl', '') as string; - const options = context.getNodeParameter('options', {}) as { formTitle: string }; - - if (redirectUrl) { - res.send( - ``, - ); - return { noWebhookResponse: true }; - } - - let title = options.formTitle; - if (!title) { - title = context.evaluateExpression( - `{{ $('${trigger?.name}').params.formTitle }}`, - ) as string; - } - const appendAttribution = context.evaluateExpression( - `{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`, - ) as boolean; - - res.render('form-trigger-completion', { - title: completionTitle, - message: completionMessage, - formTitle: title, - appendAttribution, - }); - - return { noWebhookResponse: true }; + return await renderFormCompletion(context, res, trigger); } if (operation === 'completion' && method === 'POST') { @@ -319,68 +292,7 @@ export class Form extends Node { } if (method === 'GET') { - const options = context.getNodeParameter('options', {}) as { - formTitle: string; - formDescription: string; - buttonLabel: string; - }; - - let title = options.formTitle; - if (!title) { - title = context.evaluateExpression( - `{{ $('${trigger?.name}').params.formTitle }}`, - ) as string; - } - - let description = options.formDescription; - if (!description) { - description = context.evaluateExpression( - `{{ $('${trigger?.name}').params.formDescription }}`, - ) as string; - } - - let buttonLabel = options.buttonLabel; - if (!buttonLabel) { - buttonLabel = - (context.evaluateExpression( - `{{ $('${trigger?.name}').params.options?.buttonLabel }}`, - ) as string) || 'Submit'; - } - - const responseMode = 'onReceived'; - - let redirectUrl; - - const connectedNodes = context.getChildNodes(context.getNode().name); - - const hasNextPage = connectedNodes.some( - (node) => !node.disabled && (node.type === FORM_NODE_TYPE || node.type === WAIT_NODE_TYPE), - ); - - if (hasNextPage) { - redirectUrl = context.evaluateExpression('{{ $execution.resumeFormUrl }}') as string; - } - - const appendAttribution = context.evaluateExpression( - `{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`, - ) as boolean; - - renderForm({ - context, - res, - formTitle: title, - formDescription: description, - formFields: fields, - responseMode, - mode, - redirectUrl, - appendAttribution, - buttonLabel, - }); - - return { - noWebhookResponse: true, - }; + return await renderFormNode(context, res, trigger, fields, mode); } let useWorkflowTimezone = context.evaluateExpression( diff --git a/packages/nodes-base/nodes/Form/formCompletionUtils.ts b/packages/nodes-base/nodes/Form/formCompletionUtils.ts new file mode 100644 index 0000000000..b1dab0c68c --- /dev/null +++ b/packages/nodes-base/nodes/Form/formCompletionUtils.ts @@ -0,0 +1,41 @@ +import { type Response } from 'express'; +import { + type NodeTypeAndVersion, + type IWebhookFunctions, + type IWebhookResponseData, +} from 'n8n-workflow'; + +export const renderFormCompletion = async ( + context: IWebhookFunctions, + res: Response, + trigger: NodeTypeAndVersion, +): Promise => { + const completionTitle = context.getNodeParameter('completionTitle', '') as string; + const completionMessage = context.getNodeParameter('completionMessage', '') as string; + const redirectUrl = context.getNodeParameter('redirectUrl', '') as string; + const options = context.getNodeParameter('options', {}) as { formTitle: string }; + + if (redirectUrl) { + res.send( + ``, + ); + return { noWebhookResponse: true }; + } + + let title = options.formTitle; + if (!title) { + title = context.evaluateExpression(`{{ $('${trigger?.name}').params.formTitle }}`) as string; + } + const appendAttribution = context.evaluateExpression( + `{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`, + ) as boolean; + + res.render('form-trigger-completion', { + title: completionTitle, + message: completionMessage, + formTitle: title, + appendAttribution, + }); + + return { noWebhookResponse: true }; +}; diff --git a/packages/nodes-base/nodes/Form/formNodeUtils.ts b/packages/nodes-base/nodes/Form/formNodeUtils.ts new file mode 100644 index 0000000000..ff8a01a6dc --- /dev/null +++ b/packages/nodes-base/nodes/Form/formNodeUtils.ts @@ -0,0 +1,80 @@ +import { type Response } from 'express'; +import { + type NodeTypeAndVersion, + type IWebhookFunctions, + FORM_NODE_TYPE, + WAIT_NODE_TYPE, + type FormFieldsParameter, + type IWebhookResponseData, +} from 'n8n-workflow'; + +import { renderForm } from './utils'; + +export const renderFormNode = async ( + context: IWebhookFunctions, + res: Response, + trigger: NodeTypeAndVersion, + fields: FormFieldsParameter, + mode: 'test' | 'production', +): Promise => { + const options = context.getNodeParameter('options', {}) as { + formTitle: string; + formDescription: string; + buttonLabel: string; + }; + + let title = options.formTitle; + if (!title) { + title = context.evaluateExpression(`{{ $('${trigger?.name}').params.formTitle }}`) as string; + } + + let description = options.formDescription; + if (!description) { + description = context.evaluateExpression( + `{{ $('${trigger?.name}').params.formDescription }}`, + ) as string; + } + + let buttonLabel = options.buttonLabel; + if (!buttonLabel) { + buttonLabel = + (context.evaluateExpression( + `{{ $('${trigger?.name}').params.options?.buttonLabel }}`, + ) as string) || 'Submit'; + } + + const responseMode = 'onReceived'; + + let redirectUrl; + + const connectedNodes = context.getChildNodes(context.getNode().name); + + const hasNextPage = connectedNodes.some( + (node) => !node.disabled && (node.type === FORM_NODE_TYPE || node.type === WAIT_NODE_TYPE), + ); + + if (hasNextPage) { + redirectUrl = context.evaluateExpression('{{ $execution.resumeFormUrl }}') as string; + } + + const appendAttribution = context.evaluateExpression( + `{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`, + ) as boolean; + + renderForm({ + context, + res, + formTitle: title, + formDescription: description, + formFields: fields, + responseMode, + mode, + redirectUrl, + appendAttribution, + buttonLabel, + }); + + return { + noWebhookResponse: true, + }; +};