Skip to content

Commit

Permalink
feat(Adalo Node): MVP Adalo node N8N-3263 (n8n-io#3102)
Browse files Browse the repository at this point in the history
* ✨ Added Adalo node using declarative API.

* fix: Updated authentication headers.

* fix: Fixed node linting issues.

* ⚡ improvements

* fix: Fixed Adalo node pagination.

* fix: Fixed Adalo node linting issues.

Co-authored-by: Michael Kret <[email protected]>
  • Loading branch information
alexgrozav and michael-radency authored Sep 14, 2022
1 parent dac5e50 commit 9725935
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 0 deletions.
34 changes: 34 additions & 0 deletions packages/nodes-base/credentials/AdaloApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading

0 comments on commit 9725935

Please sign in to comment.