Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Adalo Node): MVP Adalo node N8N-3263 #3102

Merged
merged 9 commits into from Sep 14, 2022
34 changes: 34 additions & 0 deletions packages/nodes-base/credentials/AdaloApi.credentials.ts
@@ -0,0 +1,34 @@
import { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';

export class AdaloApi implements ICredentialType {
name = 'adaloApi';
displayName = 'Adalo API';
documentationUrl = 'adalo';
properties: INodeProperties[] = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string',
default: '',
description:
'The Adalo API is available on paid Adalo plans, find more information <a href="https://help.adalo.com/integrations/the-adalo-api" target="_blank">here</a>',
},
{
displayName: 'App ID',
name: 'appId',
type: 'string',
default: '',
description:
'You can get App ID from the URL of your app. For example, if your app URL is <strong>https://app.adalo.com/apps/1234567890/screens</strong>, then your App ID is <strong>1234567890</strong>.',
},
];

authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
Authorization: '=Bearer {{$credentials.apiKey}}',
},
},
};
}
20 changes: 20 additions & 0 deletions packages/nodes-base/nodes/Adalo/Adalo.node.json
@@ -0,0 +1,20 @@
{
"node": "n8n-nodes-base.adalo",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Data & Storage"
],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/credentials/adalo"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/nodes/n8n-nodes-base.adalo/"
}
]
}
}
212 changes: 212 additions & 0 deletions packages/nodes-base/nodes/Adalo/Adalo.node.ts
@@ -0,0 +1,212 @@
import {
IDataObject,
IExecuteSingleFunctions,
IHttpRequestOptions,
IN8nHttpFullResponse,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { collectionFields } from './CollectionDescription';
import { FieldsUiValues } from './types';

export class Adalo implements INodeType {
description: INodeTypeDescription = {
displayName: 'Adalo',
name: 'adalo',
icon: 'file:adalo.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["collectionId"]}}',
description: 'Consume Adalo API',
defaults: {
name: 'Adalo',
color: '#4f44d7',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'adaloApi',
required: true,
},
],
requestDefaults: {
baseURL: '=https://api.adalo.com/v0/apps/{{$credentials.appId}}',
},
requestOperations: {
pagination: {
type: 'offset',
properties: {
limitParameter: 'limit',
offsetParameter: 'offset',
pageSize: 100,
type: 'query',
},
},
},
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
default: 'collection',
options: [
{
name: 'Collection',
value: 'collection',
},
],
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Create',
value: 'create',
description: 'Create a row',
routing: {
send: {
preSend: [this.presendCreateUpdate],
},
request: {
method: 'POST',
url: '=/collections/{{$parameter["collectionId"]}}',
},
},
action: 'Create a row',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a row',
routing: {
request: {
method: 'DELETE',
url: '=/collections/{{$parameter["collectionId"]}}/{{$parameter["rowId"]}}',
},
output: {
postReceive: [
{
type: 'set',
properties: {
value: '={{ { "success": true } }}',
},
},
],
},
},
action: 'Delete a row',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a row',
routing: {
request: {
method: 'GET',
url: '=/collections/{{$parameter["collectionId"]}}/{{$parameter["rowId"]}}',
},
},
action: 'Retrieve a row',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Retrieve many rows',
routing: {
request: {
method: 'GET',
url: '=/collections/{{$parameter["collectionId"]}}',
qs: {
limit: '={{$parameter["limit"]}}',
},
},
send: {
paginate: '={{$parameter["returnAll"]}}',
},
output: {
postReceive: [
{
type: 'rootProperty',
properties: {
property: 'records',
},
},
],
},
},
action: 'Retrieve all rows',
},
{
name: 'Update',
value: 'update',
description: 'Update a row',
routing: {
send: {
preSend: [this.presendCreateUpdate],
},
request: {
method: 'PUT',
url: '=/collections/{{$parameter["collectionId"]}}/{{$parameter["rowId"]}}',
},
},
action: 'Update a row',
},
],
default: 'getAll',
},
{
displayName: 'Collection ID',
name: 'collectionId',
type: 'string',
required: true,
default: '',
description:
'Open your Adalo application and click on the three buttons beside the collection name, then select API Documentation',
hint: "You can find information about app's collections on https://app.adalo.com/apps/<strong>your-app-id</strong>/api-docs",
displayOptions: {
show: {
resource: ['collection'],
},
},
},
...collectionFields,
],
};

async presendCreateUpdate(
this: IExecuteSingleFunctions,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
const dataToSend = this.getNodeParameter('dataToSend', 0) as 'defineBelow' | 'autoMapInputData';

requestOptions.body = {};

if (dataToSend === 'autoMapInputData') {
const inputData = this.getInputData();
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore') as string;

const inputKeysToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
const inputKeys = Object.keys(inputData.json).filter(
(key) => !inputKeysToIgnore.includes(key),
);

for (const key of inputKeys) {
(requestOptions.body as IDataObject)[key] = inputData.json[key];
}
} else {
const fields = this.getNodeParameter('fieldsUi.fieldValues') as FieldsUiValues;

for (const field of fields) {
(requestOptions.body as IDataObject)[field.fieldId] = field.fieldValue;
}
}

return requestOptions;
}
}