mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-16 01:24:05 -08:00
b6de910cbe
This change ensures that things like `encryptionKey` and `instanceId` are always available directly where they are needed, instead of passing them around throughout the code.
283 lines
8.3 KiB
TypeScript
283 lines
8.3 KiB
TypeScript
import type {
|
|
IDataObject,
|
|
INodeType,
|
|
INodeTypeDescription,
|
|
IWebhookResponseData,
|
|
IWebhookFunctions,
|
|
} from 'n8n-workflow';
|
|
import { FORM_TRIGGER_PATH_IDENTIFIER, jsonParse } from 'n8n-workflow';
|
|
|
|
import type { FormField } from './interfaces';
|
|
import { prepareFormData } from './utils';
|
|
|
|
export class FormTrigger implements INodeType {
|
|
description: INodeTypeDescription = {
|
|
displayName: 'n8n Form Trigger',
|
|
name: 'formTrigger',
|
|
icon: 'file:form.svg',
|
|
group: ['trigger'],
|
|
version: 1,
|
|
description: 'Runs the flow when an n8n generated webform is submitted',
|
|
defaults: {
|
|
name: 'n8n Form Trigger',
|
|
},
|
|
inputs: [],
|
|
outputs: ['main'],
|
|
webhooks: [
|
|
{
|
|
name: 'setup',
|
|
httpMethod: 'GET',
|
|
responseMode: 'onReceived',
|
|
path: FORM_TRIGGER_PATH_IDENTIFIER,
|
|
ndvHideUrl: true,
|
|
},
|
|
{
|
|
name: 'default',
|
|
httpMethod: 'POST',
|
|
responseMode: '={{$parameter["responseMode"]}}',
|
|
path: FORM_TRIGGER_PATH_IDENTIFIER,
|
|
ndvHideMethod: true,
|
|
},
|
|
],
|
|
eventTriggerDescription: 'Waiting for you to submit the form',
|
|
activationMessage: 'You can now make calls to your production Form URL.',
|
|
triggerPanel: {
|
|
header: 'Pull in a test form submission',
|
|
executionsHelp: {
|
|
inactive:
|
|
"Form Trigger has two modes: test and production. <br /> <br /> <b>Use test mode while you build your workflow</b>. Click the 'Test Step' button, then fill out the test form that opens in a popup tab. The executions will show up in the editor.<br /> <br /> <b>Use production mode to run your workflow automatically</b>. <a data-key=\"activate\">Activate</a> the workflow, then make requests to the production URL. Then every time there's a form submission via the Production Form URL, the workflow will execute. These executions will show up in the executions list, but not in the editor.",
|
|
active:
|
|
"Form Trigger has two modes: test and production. <br /> <br /> <b>Use test mode while you build your workflow</b>. Click the 'Test Step' button, then fill out the test form that opens in a popup tab. The executions will show up in the editor.<br /> <br /> <b>Use production mode to run your workflow automatically</b>. <a data-key=\"activate\">Activate</a> the workflow, then make requests to the production URL. Then every time there's a form submission via the Production Form URL, the workflow will execute. These executions will show up in the executions list, but not in the editor.",
|
|
},
|
|
activationHint: {
|
|
active:
|
|
"This node will also trigger automatically on new form submissions (but those executions won't show up here).",
|
|
inactive:
|
|
'<a data-key="activate">Activate</a> this workflow to have it also run automatically for new form submissions created via the Production URL.',
|
|
},
|
|
},
|
|
properties: [
|
|
{
|
|
displayName: 'Form Title',
|
|
name: 'formTitle',
|
|
type: 'string',
|
|
default: '',
|
|
placeholder: 'e.g. Contact us',
|
|
required: true,
|
|
description: 'Shown at the top of the form',
|
|
},
|
|
{
|
|
displayName: 'Form Description',
|
|
name: 'formDescription',
|
|
type: 'string',
|
|
default: '',
|
|
placeholder: "e.g. We'll get back to you soon",
|
|
description:
|
|
'Shown underneath the Form Title. Can be used to prompt the user on how to complete the form.',
|
|
},
|
|
{
|
|
displayName: 'Form Fields',
|
|
name: 'formFields',
|
|
placeholder: 'Add Form Field',
|
|
type: 'fixedCollection',
|
|
default: { values: [{ label: '', fieldType: 'text' }] },
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
sortable: true,
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Values',
|
|
name: 'values',
|
|
values: [
|
|
{
|
|
displayName: 'Field Label',
|
|
name: 'fieldLabel',
|
|
type: 'string',
|
|
default: '',
|
|
placeholder: 'e.g. What is your name?',
|
|
description: 'Label appears above the input field',
|
|
required: true,
|
|
},
|
|
{
|
|
displayName: 'Field Type',
|
|
name: 'fieldType',
|
|
type: 'options',
|
|
default: 'text',
|
|
description: 'The type of field to add to the form',
|
|
options: [
|
|
{
|
|
name: 'Text',
|
|
value: 'text',
|
|
},
|
|
{
|
|
name: 'Number',
|
|
value: 'number',
|
|
},
|
|
{
|
|
name: 'Date',
|
|
value: 'date',
|
|
},
|
|
{
|
|
name: 'Dropdown List',
|
|
value: 'dropdown',
|
|
},
|
|
],
|
|
required: true,
|
|
},
|
|
{
|
|
displayName: 'Field Options',
|
|
name: 'fieldOptions',
|
|
placeholder: 'Add Field Option',
|
|
description: 'List of options that can be selected from the dropdown',
|
|
type: 'fixedCollection',
|
|
default: { values: [{ option: '' }] },
|
|
required: true,
|
|
displayOptions: {
|
|
show: {
|
|
fieldType: ['dropdown'],
|
|
},
|
|
},
|
|
typeOptions: {
|
|
multipleValues: true,
|
|
sortable: true,
|
|
},
|
|
options: [
|
|
{
|
|
displayName: 'Values',
|
|
name: 'values',
|
|
values: [
|
|
{
|
|
displayName: 'Option',
|
|
name: 'option',
|
|
type: 'string',
|
|
default: '',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Multiple Choice',
|
|
name: 'multiselect',
|
|
type: 'boolean',
|
|
default: false,
|
|
description:
|
|
'Whether to allow the user to select multiple options from the dropdown list',
|
|
displayOptions: {
|
|
show: {
|
|
fieldType: ['dropdown'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
displayName: 'Required Field',
|
|
name: 'requiredField',
|
|
type: 'boolean',
|
|
default: false,
|
|
description:
|
|
'Whether to require the user to enter a value for this field before submitting the form',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
displayName: 'Respond When',
|
|
name: 'responseMode',
|
|
type: 'options',
|
|
options: [
|
|
{
|
|
name: 'Form Is Submitted',
|
|
value: 'onReceived',
|
|
description: 'As soon as this node receives the form submission',
|
|
},
|
|
{
|
|
name: 'Workflow Finishes',
|
|
value: 'lastNode',
|
|
description: 'When the last node of the workflow is executed',
|
|
},
|
|
],
|
|
default: 'onReceived',
|
|
description: 'When to respond to the form submission',
|
|
},
|
|
{
|
|
displayName: 'Options',
|
|
name: 'options',
|
|
type: 'collection',
|
|
placeholder: 'Add Option',
|
|
default: {},
|
|
options: [
|
|
{
|
|
displayName: 'Form Submitted Text',
|
|
name: 'formSubmittedText',
|
|
description: 'The text displayed to users after they filled the form',
|
|
type: 'string',
|
|
default: 'Your response has been recorded',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
|
const webhookName = this.getWebhookName();
|
|
const mode = this.getMode() === 'manual' ? 'test' : 'production';
|
|
const formFields = this.getNodeParameter('formFields.values', []) as FormField[];
|
|
|
|
//Show the form on GET request
|
|
if (webhookName === 'setup') {
|
|
const formTitle = this.getNodeParameter('formTitle', '') as string;
|
|
const formDescription = this.getNodeParameter('formDescription', '') as string;
|
|
const instanceId = this.getInstanceId();
|
|
const { formSubmittedText } = this.getNodeParameter('options', {}) as IDataObject;
|
|
|
|
const data = prepareFormData(
|
|
formTitle,
|
|
formDescription,
|
|
formSubmittedText as string,
|
|
formFields,
|
|
mode === 'test',
|
|
instanceId,
|
|
);
|
|
|
|
const res = this.getResponseObject();
|
|
res.render('form-trigger', data);
|
|
return {
|
|
noWebhookResponse: true,
|
|
};
|
|
}
|
|
|
|
const bodyData = (this.getBodyData().data as IDataObject) ?? {};
|
|
|
|
const returnData: IDataObject = {};
|
|
for (const [index, field] of formFields.entries()) {
|
|
const key = `field-${index}`;
|
|
let value = bodyData[key] ?? null;
|
|
|
|
if (value === null) returnData[field.fieldLabel] = null;
|
|
|
|
if (field.fieldType === 'number') {
|
|
value = Number(value);
|
|
}
|
|
if (field.fieldType === 'text') {
|
|
value = String(value).trim();
|
|
}
|
|
if (field.multiselect && typeof value === 'string') {
|
|
value = jsonParse(value);
|
|
}
|
|
|
|
returnData[field.fieldLabel] = value;
|
|
}
|
|
returnData.submittedAt = new Date().toISOString();
|
|
returnData.formMode = mode;
|
|
|
|
const webhookResponse: IDataObject = { status: 200 };
|
|
|
|
return {
|
|
webhookResponse,
|
|
workflowData: [this.helpers.returnJsonArray(returnData)],
|
|
};
|
|
}
|
|
}
|