mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
✨ Add Bubble.io Node (#1493)
* 🎉 Register node and credentials * 🎨 Add SVG icon * 🎨 Fix SVG icon size and positioning * ⚡ Add API credentials * ⚡ Add description for object * ⚡ Add generic functions * ⚡ Add preliminary node * ⚡ Improvements * ⚡ Minor improvements Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
70
packages/nodes-base/credentials/BubbleApi.credentials.ts
Normal file
70
packages/nodes-base/credentials/BubbleApi.credentials.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
ICredentialType,
|
||||||
|
NodePropertyTypes,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export class BubbleApi implements ICredentialType {
|
||||||
|
name = 'bubbleApi';
|
||||||
|
displayName = 'Bubble API';
|
||||||
|
documentationUrl = 'bubble';
|
||||||
|
properties = [
|
||||||
|
{
|
||||||
|
displayName: 'API Token',
|
||||||
|
name: 'apiToken',
|
||||||
|
type: 'string' as NodePropertyTypes,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'App Name',
|
||||||
|
name: 'appName',
|
||||||
|
type: 'string' as NodePropertyTypes,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Environment',
|
||||||
|
name: 'environment',
|
||||||
|
type: 'options' as NodePropertyTypes,
|
||||||
|
default: 'live',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Development',
|
||||||
|
value: 'development',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Live',
|
||||||
|
value: 'live',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Hosting',
|
||||||
|
name: 'hosting',
|
||||||
|
type: 'options' as NodePropertyTypes,
|
||||||
|
default: 'bubbleHosted',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Bubble-hosted',
|
||||||
|
value: 'bubbleHosted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Self-hosted',
|
||||||
|
value: 'selfHosted',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Domain',
|
||||||
|
name: 'domain',
|
||||||
|
type: 'string' as NodePropertyTypes,
|
||||||
|
placeholder: 'mydomain.com',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
hosting: [
|
||||||
|
'selfHosted',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
206
packages/nodes-base/nodes/Bubble/Bubble.node.ts
Normal file
206
packages/nodes-base/nodes/Bubble/Bubble.node.ts
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import {
|
||||||
|
IExecuteFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IDataObject,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import {
|
||||||
|
bubbleApiRequest,
|
||||||
|
bubbleApiRequestAllItems,
|
||||||
|
validateJSON,
|
||||||
|
} from './GenericFunctions';
|
||||||
|
|
||||||
|
import {
|
||||||
|
objectFields,
|
||||||
|
objectOperations,
|
||||||
|
} from './ObjectDescription';
|
||||||
|
|
||||||
|
export class Bubble implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'Bubble',
|
||||||
|
name: 'bubble',
|
||||||
|
icon: 'file:bubble.svg',
|
||||||
|
group: ['transform'],
|
||||||
|
version: 1,
|
||||||
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
|
description: 'Consume the Bubble Data API',
|
||||||
|
defaults: {
|
||||||
|
name: 'Bubble',
|
||||||
|
color: '#0205d3',
|
||||||
|
},
|
||||||
|
inputs: ['main'],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'bubbleApi',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Resource',
|
||||||
|
name: 'resource',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Object',
|
||||||
|
value: 'object',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'object',
|
||||||
|
description: 'Resource to consume',
|
||||||
|
},
|
||||||
|
...objectOperations,
|
||||||
|
...objectFields,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const items = this.getInputData();
|
||||||
|
|
||||||
|
const resource = this.getNodeParameter('resource', 0) as string;
|
||||||
|
const operation = this.getNodeParameter('operation', 0) as string;
|
||||||
|
|
||||||
|
let responseData;
|
||||||
|
const qs: IDataObject = {};
|
||||||
|
const returnData: IDataObject[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
|
||||||
|
if (resource === 'object') {
|
||||||
|
|
||||||
|
// *********************************************************************
|
||||||
|
// object
|
||||||
|
// *********************************************************************
|
||||||
|
|
||||||
|
// https://bubble.io/reference#API
|
||||||
|
|
||||||
|
if (operation === 'create') {
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: create
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const typeNameInput = this.getNodeParameter('typeName', i) as string;
|
||||||
|
const typeName = typeNameInput.replace(/\s/g, '').toLowerCase();
|
||||||
|
|
||||||
|
const { property } = this.getNodeParameter('properties', i) as {
|
||||||
|
property: [
|
||||||
|
{ key: string; value: string; },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const body = {} as IDataObject;
|
||||||
|
|
||||||
|
property.forEach(data => body[data.key] = data.value);
|
||||||
|
|
||||||
|
responseData = await bubbleApiRequest.call(this, 'POST', `/obj/${typeName}`, body, {});
|
||||||
|
|
||||||
|
} else if (operation === 'delete') {
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: delete
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const typeNameInput = this.getNodeParameter('typeName', i) as string;
|
||||||
|
const typeName = typeNameInput.replace(/\s/g, '').toLowerCase();
|
||||||
|
const objectId = this.getNodeParameter('objectId', i) as string;
|
||||||
|
|
||||||
|
const endpoint = `/obj/${typeName}/${objectId}`;
|
||||||
|
responseData = await bubbleApiRequest.call(this, 'DELETE', endpoint, {}, {});
|
||||||
|
responseData = { success: true };
|
||||||
|
|
||||||
|
} else if (operation === 'get') {
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: get
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const typeNameInput = this.getNodeParameter('typeName', i) as string;
|
||||||
|
const typeName = typeNameInput.replace(/\s/g, '').toLowerCase();
|
||||||
|
const objectId = this.getNodeParameter('objectId', i) as string;
|
||||||
|
|
||||||
|
const endpoint = `/obj/${typeName}/${objectId}`;
|
||||||
|
responseData = await bubbleApiRequest.call(this, 'GET', endpoint, {}, {});
|
||||||
|
responseData = responseData.response;
|
||||||
|
|
||||||
|
} else if (operation === 'getAll') {
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: getAll
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
|
||||||
|
const typeNameInput = this.getNodeParameter('typeName', i) as string;
|
||||||
|
const typeName = typeNameInput.replace(/\s/g, '').toLowerCase();
|
||||||
|
|
||||||
|
const endpoint = `/obj/${typeName}`;
|
||||||
|
|
||||||
|
const jsonParameters = this.getNodeParameter('jsonParameters', 0) as boolean;
|
||||||
|
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||||
|
|
||||||
|
if (jsonParameters === false) {
|
||||||
|
if (options.filters) {
|
||||||
|
const { filter } = options.filters as IDataObject;
|
||||||
|
qs.constraints = JSON.stringify(filter);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const filter = options.filtersJson as string;
|
||||||
|
const data = validateJSON(filter);
|
||||||
|
if (data === undefined) {
|
||||||
|
throw new Error('Filters must be a valid JSON');
|
||||||
|
}
|
||||||
|
qs.constraints = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.sort) {
|
||||||
|
const { sortValue } = options.sort as IDataObject;
|
||||||
|
Object.assign(qs, sortValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnAll === true) {
|
||||||
|
responseData = await bubbleApiRequestAllItems.call(this, 'GET', endpoint, {}, qs);
|
||||||
|
} else {
|
||||||
|
qs.limit = this.getNodeParameter('limit', 0) as number;
|
||||||
|
responseData = await bubbleApiRequest.call(this, 'GET', endpoint, {}, qs);
|
||||||
|
responseData = responseData.response.results;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (operation === 'update') {
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: update
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const typeNameInput = this.getNodeParameter('typeName', i) as string;
|
||||||
|
const typeName = typeNameInput.replace(/\s/g, '').toLowerCase();
|
||||||
|
const objectId = this.getNodeParameter('objectId', i) as string;
|
||||||
|
const endpoint = `/obj/${typeName}/${objectId}`;
|
||||||
|
const { property } = this.getNodeParameter('properties', i) as {
|
||||||
|
property: [
|
||||||
|
{ key: string; value: string; },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const body = {} as IDataObject;
|
||||||
|
|
||||||
|
property.forEach(data => body[data.key] = data.value);
|
||||||
|
responseData = await bubbleApiRequest.call(this, 'PATCH', endpoint, body, {});
|
||||||
|
responseData = { sucess: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.isArray(responseData)
|
||||||
|
? returnData.push(...responseData)
|
||||||
|
: returnData.push(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [this.helpers.returnJsonArray(returnData)];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
101
packages/nodes-base/nodes/Bubble/GenericFunctions.ts
Normal file
101
packages/nodes-base/nodes/Bubble/GenericFunctions.ts
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import {
|
||||||
|
IExecuteFunctions,
|
||||||
|
IHookFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IDataObject,
|
||||||
|
ILoadOptionsFunctions,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import {
|
||||||
|
OptionsWithUri,
|
||||||
|
} from 'request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an authenticated API request to Bubble.
|
||||||
|
*/
|
||||||
|
export async function bubbleApiRequest(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||||
|
method: string,
|
||||||
|
endpoint: string,
|
||||||
|
body: IDataObject,
|
||||||
|
qs: IDataObject,
|
||||||
|
) {
|
||||||
|
|
||||||
|
const { apiToken, appName, domain, environment, hosting } = this.getCredentials('bubbleApi') as {
|
||||||
|
apiToken: string,
|
||||||
|
appName: string,
|
||||||
|
domain: string,
|
||||||
|
environment: 'development' | 'live',
|
||||||
|
hosting: 'bubbleHosted' | 'selfHosted',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rootUrl = hosting === 'bubbleHosted' ? `https://${appName}.bubbleapps.io` : domain;
|
||||||
|
const urlSegment = environment === 'development' ? '/version-test/api/1.1' : '/api/1.1';
|
||||||
|
|
||||||
|
const options: OptionsWithUri = {
|
||||||
|
headers: {
|
||||||
|
'user-agent': 'n8n',
|
||||||
|
'Authorization': `Bearer ${apiToken}`,
|
||||||
|
},
|
||||||
|
method,
|
||||||
|
uri: `${rootUrl}${urlSegment}${endpoint}`,
|
||||||
|
qs,
|
||||||
|
body,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!Object.keys(body).length) {
|
||||||
|
delete options.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(qs).length) {
|
||||||
|
delete options.qs;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await this.helpers.request!(options);
|
||||||
|
} catch (error) {
|
||||||
|
if (error?.response?.body?.body?.message) {
|
||||||
|
const errorMessage = error.response.body.body.message;
|
||||||
|
throw new Error(`Bubble.io error response [${error.statusCode}]: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an authenticated API request to Bubble and return all results.
|
||||||
|
*/
|
||||||
|
export async function bubbleApiRequestAllItems(
|
||||||
|
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||||
|
method: string,
|
||||||
|
endpoint: string,
|
||||||
|
body: IDataObject,
|
||||||
|
qs: IDataObject,
|
||||||
|
) {
|
||||||
|
const returnData: IDataObject[] = [];
|
||||||
|
|
||||||
|
let responseData;
|
||||||
|
qs.limit = 100;
|
||||||
|
do {
|
||||||
|
responseData = await bubbleApiRequest.call(this, method, endpoint, body, qs);
|
||||||
|
qs.cursor = responseData.cursor;
|
||||||
|
returnData.push.apply(returnData, responseData['response']['results']);
|
||||||
|
} while (
|
||||||
|
responseData.response.remaining !== 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = JSON.parse(json!);
|
||||||
|
} catch (exception) {
|
||||||
|
result = undefined;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
517
packages/nodes-base/nodes/Bubble/ObjectDescription.ts
Normal file
517
packages/nodes-base/nodes/Bubble/ObjectDescription.ts
Normal file
@@ -0,0 +1,517 @@
|
|||||||
|
import {
|
||||||
|
INodeProperties,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export const objectOperations = [
|
||||||
|
{
|
||||||
|
displayName: 'Operation',
|
||||||
|
name: 'operation',
|
||||||
|
type: 'options',
|
||||||
|
default: 'get',
|
||||||
|
description: 'Operation to perform',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Create',
|
||||||
|
value: 'create',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Delete',
|
||||||
|
value: 'delete',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Get',
|
||||||
|
value: 'get',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Get All',
|
||||||
|
value: 'getAll',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Update',
|
||||||
|
value: 'update',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as INodeProperties[];
|
||||||
|
|
||||||
|
export const objectFields = [
|
||||||
|
// ----------------------------------
|
||||||
|
// object: create
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Type Name',
|
||||||
|
name: 'typeName',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'Name of data type of the object to create.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Properties',
|
||||||
|
name: 'properties',
|
||||||
|
placeholder: 'Add Property',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Property',
|
||||||
|
name: 'property',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Key',
|
||||||
|
name: 'key',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Field to set for the object to create.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value',
|
||||||
|
name: 'value',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Value to set for the object to create.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: get
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Type Name',
|
||||||
|
name: 'typeName',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'Name of data type of the object to retrieve.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'get',
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Object ID',
|
||||||
|
name: 'objectId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'ID of the object to retrieve.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'get',
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object: update
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Type Name',
|
||||||
|
name: 'typeName',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'Name of data type of the object to update.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Object ID',
|
||||||
|
name: 'objectId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'ID of the object to update.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Properties',
|
||||||
|
name: 'properties',
|
||||||
|
placeholder: 'Add Property',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Property',
|
||||||
|
name: 'property',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Key',
|
||||||
|
name: 'key',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Field to set for the object to create.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value',
|
||||||
|
name: 'value',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Value to set for the object to create.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// object:getAll
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Type Name',
|
||||||
|
name: 'typeName',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'Name of data type of the object to create.',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'getAll',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Return All',
|
||||||
|
name: 'returnAll',
|
||||||
|
type: 'boolean',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'getAll',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: false,
|
||||||
|
description: 'If all results should be returned or only up to a given limit.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Limit',
|
||||||
|
name: 'limit',
|
||||||
|
type: 'number',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'getAll',
|
||||||
|
],
|
||||||
|
returnAll: [
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typeOptions: {
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 100,
|
||||||
|
},
|
||||||
|
default: 100,
|
||||||
|
description: 'How many results to return.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'JSON Parameters',
|
||||||
|
name: 'jsonParameters',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
operation: [
|
||||||
|
'getAll',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Options',
|
||||||
|
name: 'options',
|
||||||
|
type: 'collection',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'getAll',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Filters',
|
||||||
|
name: 'filters',
|
||||||
|
placeholder: 'Add Filter',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: true,
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'/jsonParameters': [
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Filter',
|
||||||
|
name: 'filter',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Key',
|
||||||
|
name: 'key',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'Field to set for the object to create.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Constrain',
|
||||||
|
name: 'constraint_type',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Equals',
|
||||||
|
value: 'equals',
|
||||||
|
description: 'Use to test strict equality, for all field types.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Equal',
|
||||||
|
value: 'not equal',
|
||||||
|
description: 'Use to test strict equality, for all field types',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Empty',
|
||||||
|
value: 'is_empty',
|
||||||
|
description: `Use to test whether a thing's given field is empty, for all field types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Is Not Empty',
|
||||||
|
value: 'is_not_empty',
|
||||||
|
description: `Use to test whether a thing's given field is not empty, for all field types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Text Contains',
|
||||||
|
value: 'text contains',
|
||||||
|
description: 'Use to test if a text field contains a string, for text fields only',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Text Contains',
|
||||||
|
value: 'not text contains',
|
||||||
|
description: 'Use to test if a text field does not contain a string, for text fields only',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Greater Than',
|
||||||
|
value: 'greater than',
|
||||||
|
description: `Use to compare a thing's field value relative to a string or number, for text, number, and date fields`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Less Than',
|
||||||
|
value: 'less than',
|
||||||
|
description: `Use to compare a thing's field value relative to a string or number, for text, number, and date fields`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'In',
|
||||||
|
value: 'in',
|
||||||
|
description: `Use to test whether a thing's field is in a list, for all field types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not In',
|
||||||
|
value: 'not in',
|
||||||
|
description: `Use to test whether a thing's field is not in a list, for all field types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Contains',
|
||||||
|
value: 'contains',
|
||||||
|
description: `Use to test whether a list field contains an entry, for list fields only`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Contains',
|
||||||
|
value: 'not contains',
|
||||||
|
description: `Use to test whether a list field does not contains an entry, for list fields only`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Empty',
|
||||||
|
value: 'empty',
|
||||||
|
description: `Use to test whether a list field is empty, for list fields only`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Not Empty',
|
||||||
|
value: 'not empty',
|
||||||
|
description: `Use to test whether a list field is not empty, for list fields only`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Geographic Search',
|
||||||
|
value: 'geographic_search',
|
||||||
|
description: `Use to test if the current thing is within a radius from a central address. To use this, the value sent with the constraint must have an address and a range. See <a href="https://manual.bubble.io/core-resources/api/data-api" target="_blank">link</a>.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value',
|
||||||
|
name: 'value',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
hide: {
|
||||||
|
constraint_type: [
|
||||||
|
'is_empty',
|
||||||
|
'is_not_empty',
|
||||||
|
'empty',
|
||||||
|
'not empty',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'Value to set for the object to create.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Filters (JSON)',
|
||||||
|
name: 'filtersJson',
|
||||||
|
type: 'json',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'/jsonParameters': [
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
placeholder: `[ { "key": "name", "constraint_type": "text contains", "value": "cafe" } , { "key": "address", "constraint_type": "geographic_search", "value": { "range":10, "origin_address":"New York" } } ]`,
|
||||||
|
description: 'Refine the list that is returned by the Data API with search constraints, exactly as you define a search in Bubble. See <a href="https://manual.bubble.io/core-resources/api/data-api#search-constraints" target="_blank">link</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Sort',
|
||||||
|
name: 'sort',
|
||||||
|
placeholder: 'Add Sort',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: false,
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Sort',
|
||||||
|
name: 'sortValue',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'Sort Field',
|
||||||
|
name: 'sort_field',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Specify the field to use for sorting. Either use a fielddefined for</br>
|
||||||
|
the current typeor use _random_sorting to get the entries in a random order`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Descending',
|
||||||
|
name: 'descending',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Geo Reference',
|
||||||
|
name: 'geo_reference',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `When the field's type is geographic address, you need to add another parameter geo_reference and provide an address as a string`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as INodeProperties[];
|
||||||
1
packages/nodes-base/nodes/Bubble/bubble.svg
Normal file
1
packages/nodes-base/nodes/Bubble/bubble.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-16 -10 85 85" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#A" x=".5" y=".5"/><symbol id="A" overflow="visible"><path d="M145.432 17.494c-6.051 0-12.034 2.596-16.584 7.719V0h-9.017v42.455c0 13.786 11.174 24.961 24.961 24.961s24.961-11.174 24.961-24.961-10.534-24.961-24.32-24.961zm-.657 40.298a15.34 15.34 0 0 1-15.337-15.337c0-8.461 6.876-15.337 15.337-15.337a15.34 15.34 0 0 1 15.337 15.337c0 8.461-6.86 15.337-15.337 15.337zm56.562-40.298c-6.051 0-12.034 2.596-16.584 7.719V0h-9.017v42.455c0 13.786 11.174 24.961 24.961 24.961s24.961-11.174 24.961-24.961-10.551-24.961-24.32-24.961zm-.657 40.298a15.34 15.34 0 0 1-15.337-15.337c0-8.461 6.876-15.337 15.337-15.337a15.34 15.34 0 0 1 15.337 15.337 15.34 15.34 0 0 1-15.337 15.337zM69.067 46.821V18.843h9.674v27.893c0 7.129 4.129 11.697 11.09 11.697 7.045 0 11.09-4.399 11.09-11.697V18.843h9.758v27.978c0 12.927-7.837 20.579-20.848 20.579-12.674.017-20.764-7.905-20.764-20.579zM243.101 66.27h-9.674V0h9.674v66.27zm54.775-19.972h-37.028c1.416 7.382 6.59 12.404 15.741 12.404 5.36 0 11.882-2.022 16.096-5.107l4.045 7.129c-4.837 3.607-12.489 6.59-20.494 6.59-17.764 0-25.416-12.404-25.416-24.893 0-7.129 2.191-13.011 6.691-17.68 4.483-4.669 10.382-7.045 17.511-7.045 6.775 0 12.405 2.107 16.719 6.421s6.506 10.112 6.506 17.511c-.034 1.331-.118 2.916-.371 4.669zm-37.045-7.921h27.624c-.792-7.483-6.337-12.32-13.466-12.32-7.298 0-12.742 4.938-14.157 12.32zM38.343 17.494c-6.051 0-12.034 2.596-16.584 7.719V0h-9.034v42.455c0 13.786 11.174 24.961 24.961 24.961s24.961-11.174 24.961-24.961-10.534-24.961-24.303-24.961zm-.657 40.298a15.34 15.34 0 0 1-15.337-15.337c0-8.461 6.876-15.337 15.337-15.337a15.34 15.34 0 0 1 15.337 15.337 15.34 15.34 0 0 1-15.337 15.337z" fill="#000" fill-rule="nonzero" stroke="none"/><path d="M0 61.231c0-3.417 2.751-6.169 6.169-6.169s6.168 2.751 6.168 6.169-2.751 6.169-6.168 6.169S0 64.648 0 61.231z" fill="#00f" fill-rule="nonzero" stroke="none"/></symbol></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -47,6 +47,7 @@
|
|||||||
"dist/credentials/BitwardenApi.credentials.js",
|
"dist/credentials/BitwardenApi.credentials.js",
|
||||||
"dist/credentials/BoxOAuth2Api.credentials.js",
|
"dist/credentials/BoxOAuth2Api.credentials.js",
|
||||||
"dist/credentials/BrandfetchApi.credentials.js",
|
"dist/credentials/BrandfetchApi.credentials.js",
|
||||||
|
"dist/credentials/BubbleApi.credentials.js",
|
||||||
"dist/credentials/ChargebeeApi.credentials.js",
|
"dist/credentials/ChargebeeApi.credentials.js",
|
||||||
"dist/credentials/CircleCiApi.credentials.js",
|
"dist/credentials/CircleCiApi.credentials.js",
|
||||||
"dist/credentials/ClearbitApi.credentials.js",
|
"dist/credentials/ClearbitApi.credentials.js",
|
||||||
@@ -288,6 +289,7 @@
|
|||||||
"dist/nodes/Box/Box.node.js",
|
"dist/nodes/Box/Box.node.js",
|
||||||
"dist/nodes/Box/BoxTrigger.node.js",
|
"dist/nodes/Box/BoxTrigger.node.js",
|
||||||
"dist/nodes/Brandfetch/Brandfetch.node.js",
|
"dist/nodes/Brandfetch/Brandfetch.node.js",
|
||||||
|
"dist/nodes/Bubble/Bubble.node.js",
|
||||||
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
||||||
"dist/nodes/Chargebee/Chargebee.node.js",
|
"dist/nodes/Chargebee/Chargebee.node.js",
|
||||||
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user