From 7b4980690f3f916607c131218f339b6ae8e10817 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Mon, 11 May 2020 20:22:31 +0200 Subject: [PATCH] :zap: Improve AgileCrm-Node --- package.json | 7 +- .../nodes/AgileCrm/AgileCrm.node.ts | 141 +-- .../nodes/AgileCrm/CompanyDescription.ts | 135 +- .../nodes/AgileCrm/ContactDescription.ts | 1122 ++++++++--------- .../nodes/AgileCrm/ContactInterface.ts | 41 +- .../nodes/AgileCrm/DealDescription.ts | 898 +++++++------ .../nodes/AgileCrm/DealInterface.ts | 22 +- .../nodes/AgileCrm/GenericFunctions.ts | 70 +- .../nodes-base/nodes/AgileCrm/agilecrm.png | Bin 20236 -> 1218 bytes 9 files changed, 1173 insertions(+), 1263 deletions(-) diff --git a/package.json b/package.json index 3b96e2de5d..b045830f51 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,5 @@ "lerna": "^3.13.1", "run-script-os": "^1.0.7" }, - "postcss": {}, - "dependencies": { - "@typescript-eslint/parser": "^2.31.0", - "tslint-eslint-rules": "^5.4.0", - "typescript-tslint-plugin": "^0.5.5" - } + "postcss": {} } diff --git a/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts b/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts index b26316f475..6090aa7796 100644 --- a/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts +++ b/packages/nodes-base/nodes/AgileCrm/AgileCrm.node.ts @@ -22,7 +22,7 @@ import { } from './DealDescription'; import { IContact, IContactUpdate } from './ContactInterface'; -import { agileCrmApiRequest, agileCrmApiRequestUpdate, validateJSON} from './GenericFunctions'; +import { agileCrmApiRequest, agileCrmApiRequestUpdate, validateJSON } from './GenericFunctions'; import { IDeal } from './DealInterface'; @@ -90,36 +90,31 @@ export class AgileCrm implements INodeType { const items = this.getInputData(); const returnData: IDataObject[] = []; - const length = items.length as unknown as number; let responseData; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; - for (let i = 0; i < length; i++) { + for (let i = 0; i < items.length; i++) { - if(resource === 'contact' || resource === 'company'){ + if (resource === 'contact' || resource === 'company') { const idGetter = resource === 'contact' ? 'contactId' : 'companyId'; - if(operation === 'get'){ + if (operation === 'get') { const contactId = this.getNodeParameter(idGetter, i) as string; const endpoint = `api/contacts/${contactId}`; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); - - } - if(operation === 'delete'){ + } else if (operation === 'delete') { const contactId = this.getNodeParameter(idGetter, i) as string; const endpoint = `api/contacts/${contactId}`; responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {}); - - } - if(operation === 'getAll'){ + } else if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; - - if(resource === 'contact'){ + + if (resource === 'contact') { if (returnAll) { const endpoint = 'api/contacts'; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); @@ -139,17 +134,15 @@ export class AgileCrm implements INodeType { } } - } - - if(operation === 'create'){ + } else if (operation === 'create') { const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const body: IContact = {}; - const properties : IDataObject[] = []; + const properties: IDataObject[] = []; if (jsonParameters) { const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; - if (additionalFieldsJson !== '' ) { + if (additionalFieldsJson !== '') { if (validateJSON(additionalFieldsJson) !== undefined) { @@ -165,7 +158,7 @@ export class AgileCrm implements INodeType { const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; // if company, add 'company' as type. default is person - if(resource === 'company'){ + if (resource === 'company') { body.type = 'COMPANY'; } if (additionalFields.starValue) { @@ -176,36 +169,36 @@ export class AgileCrm implements INodeType { } // Contact specific properties - if(resource === 'contact'){ - if(additionalFields.firstName){ + if (resource === 'contact') { + if (additionalFields.firstName) { properties.push({ type: 'SYSTEM', name: 'first_name', value: additionalFields.firstName as string } as IDataObject); } - if(additionalFields.lastName){ + if (additionalFields.lastName) { properties.push({ type: 'SYSTEM', name: 'last_name', value: additionalFields.lastName as string } as IDataObject); } - if(additionalFields.company){ + if (additionalFields.company) { properties.push({ type: 'SYSTEM', name: 'company', value: additionalFields.company as string } as IDataObject); } - if(additionalFields.title){ + if (additionalFields.title) { properties.push({ type: 'SYSTEM', name: 'title', value: additionalFields.title as string } as IDataObject); } - if(additionalFields.emailOptions){ + if (additionalFields.emailOptions) { //@ts-ignore additionalFields.emailOptions.emailProperties.map(property => { properties.push({ @@ -216,7 +209,7 @@ export class AgileCrm implements INodeType { } as IDataObject); }); } - if(additionalFields.addressOptions){ + if (additionalFields.addressOptions) { //@ts-ignore additionalFields.addressOptions.addressProperties.map(property => { properties.push({ @@ -228,7 +221,7 @@ export class AgileCrm implements INodeType { }); } - if(additionalFields.phoneOptions){ + if (additionalFields.phoneOptions) { //@ts-ignore additionalFields.phoneOptions.phoneProperties.map(property => { properties.push({ @@ -240,7 +233,7 @@ export class AgileCrm implements INodeType { }); } } else if (resource === 'company') { - if(additionalFields.email){ + if (additionalFields.email) { properties.push({ type: 'SYSTEM', name: 'email', @@ -248,7 +241,7 @@ export class AgileCrm implements INodeType { } as IDataObject); } - if(additionalFields.address){ + if (additionalFields.address) { properties.push({ type: 'SYSTEM', name: 'address', @@ -256,7 +249,7 @@ export class AgileCrm implements INodeType { } as IDataObject); } - if(additionalFields.phone){ + if (additionalFields.phone) { properties.push({ type: 'SYSTEM', name: 'phone', @@ -266,7 +259,7 @@ export class AgileCrm implements INodeType { } - if(additionalFields.websiteOptions){ + if (additionalFields.websiteOptions) { //@ts-ignore additionalFields.websiteOptions.websiteProperties.map(property => { properties.push({ @@ -278,7 +271,7 @@ export class AgileCrm implements INodeType { }); } - if(additionalFields.customProperties){ + if (additionalFields.customProperties) { //@ts-ignore additionalFields.customProperties.customProperty.map(property => { properties.push({ @@ -294,19 +287,18 @@ export class AgileCrm implements INodeType { } const endpoint = 'api/contacts'; responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body); - } - if(operation === 'update') { + } else if (operation === 'update') { const contactId = this.getNodeParameter(idGetter, i) as string; - const contactUpdatePayload : IContactUpdate = {id: contactId}; + const contactUpdatePayload: IContactUpdate = { id: contactId }; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const body: IContact = {}; - const properties : IDataObject[] = []; + const properties: IDataObject[] = []; if (jsonParameters) { const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; - if (additionalFieldsJson !== '' ) { + if (additionalFieldsJson !== '') { if (validateJSON(additionalFieldsJson) !== undefined) { @@ -327,41 +319,41 @@ export class AgileCrm implements INodeType { } // Contact specific properties - if(resource === 'contact'){ + if (resource === 'contact') { if (additionalFields.leadScore) { body.lead_score = additionalFields.leadScore as string; } - - if(additionalFields.firstName){ + + if (additionalFields.firstName) { properties.push({ type: 'SYSTEM', name: 'first_name', value: additionalFields.firstName as string } as IDataObject); } - if(additionalFields.lastName){ + if (additionalFields.lastName) { properties.push({ type: 'SYSTEM', name: 'last_name', value: additionalFields.lastName as string } as IDataObject); } - if(additionalFields.company){ + if (additionalFields.company) { properties.push({ type: 'SYSTEM', name: 'company', value: additionalFields.company as string } as IDataObject); } - if(additionalFields.title){ + if (additionalFields.title) { properties.push({ type: 'SYSTEM', name: 'title', value: additionalFields.title as string } as IDataObject); } - if(additionalFields.emailOptions){ + if (additionalFields.emailOptions) { //@ts-ignore additionalFields.emailOptions.emailProperties.map(property => { properties.push({ @@ -372,7 +364,7 @@ export class AgileCrm implements INodeType { } as IDataObject); }); } - if(additionalFields.addressOptions){ + if (additionalFields.addressOptions) { //@ts-ignore additionalFields.addressOptions.addressProperties.map(property => { properties.push({ @@ -384,7 +376,7 @@ export class AgileCrm implements INodeType { }); } - if(additionalFields.phoneOptions){ + if (additionalFields.phoneOptions) { //@ts-ignore additionalFields.phoneOptions.phoneProperties.map(property => { properties.push({ @@ -396,7 +388,7 @@ export class AgileCrm implements INodeType { }); } } else if (resource === 'company') { - if(additionalFields.email){ + if (additionalFields.email) { properties.push({ type: 'SYSTEM', name: 'email', @@ -404,7 +396,7 @@ export class AgileCrm implements INodeType { } as IDataObject); } - if(additionalFields.address){ + if (additionalFields.address) { properties.push({ type: 'SYSTEM', name: 'address', @@ -412,7 +404,7 @@ export class AgileCrm implements INodeType { } as IDataObject); } - if(additionalFields.phone){ + if (additionalFields.phone) { properties.push({ type: 'SYSTEM', name: 'phone', @@ -422,7 +414,7 @@ export class AgileCrm implements INodeType { } - if(additionalFields.websiteOptions){ + if (additionalFields.websiteOptions) { //@ts-ignore additionalFields.websiteOptions.websiteProperties.map(property => { properties.push({ @@ -433,7 +425,7 @@ export class AgileCrm implements INodeType { } as IDataObject); }); } - if(additionalFields.customProperties){ + if (additionalFields.customProperties) { //@ts-ignore additionalFields.customProperties.customProperty.map(property => { properties.push({ @@ -453,26 +445,23 @@ export class AgileCrm implements INodeType { } - } - if(resource === 'deal'){ + } else if (resource === 'deal') { - if(operation === 'get'){ + if (operation === 'get') { const dealId = this.getNodeParameter('dealId', i) as string; const endpoint = `api/opportunity/${dealId}`; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); - } - if(operation === 'delete'){ + } else if (operation === 'delete') { const contactId = this.getNodeParameter('dealId', i) as string; const endpoint = `api/opportunity/${contactId}`; responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {}); - } - if(operation === 'getAll'){ + } else if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; - + if (returnAll) { const endpoint = 'api/opportunity'; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); @@ -481,9 +470,8 @@ export class AgileCrm implements INodeType { const endpoint = `api/opportunity?page_size=${limit}`; responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); } - } - if(operation === 'create'){ + } else if (operation === 'create') { const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const body: IDeal = {}; @@ -491,12 +479,9 @@ export class AgileCrm implements INodeType { if (jsonParameters) { const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; - if (additionalFieldsJson !== '' ) { - + if (additionalFieldsJson !== '') { if (validateJSON(additionalFieldsJson) !== undefined) { - Object.assign(body, JSON.parse(additionalFieldsJson)); - } else { throw new Error('Additional fields must be a valid JSON'); } @@ -504,18 +489,18 @@ export class AgileCrm implements INodeType { } else { const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; - + body.close_date = new Date(this.getNodeParameter('closeDate', i) as string).getTime(); body.expected_value = this.getNodeParameter('expectedValue', i) as number; body.milestone = this.getNodeParameter('milestone', i) as string; body.probability = this.getNodeParameter('probability', i) as number; body.name = this.getNodeParameter('name', i) as string; - if(additionalFields.contactIds){ + if (additionalFields.contactIds) { body.contactIds = additionalFields.contactIds as string[]; } - if(additionalFields.customData){ + if (additionalFields.customData) { // @ts-ignore body.customData = additionalFields.customData.customProperty as IDealCustomProperty[]; } @@ -524,9 +509,8 @@ export class AgileCrm implements INodeType { const endpoint = 'api/opportunity'; responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body); - } - if(operation === 'update'){ + } else if (operation === 'update') { const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const body: IDeal = {}; @@ -534,14 +518,14 @@ export class AgileCrm implements INodeType { if (jsonParameters) { const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; - if (additionalFieldsJson !== '' ) { + if (additionalFieldsJson !== '') { if (validateJSON(additionalFieldsJson) !== undefined) { Object.assign(body, JSON.parse(additionalFieldsJson)); } else { - throw new Error('Additional fields must be a valid JSON'); + throw new Error('Additional fields must be valid JSON'); } } @@ -549,23 +533,23 @@ export class AgileCrm implements INodeType { const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; body.id = this.getNodeParameter('dealId', i) as number; - if(additionalFields.expectedValue){ + if (additionalFields.expectedValue) { body.expected_value = additionalFields.expectedValue as number; } - if(additionalFields.name){ + if (additionalFields.name) { body.name = additionalFields.name as string; } - if(additionalFields.probability){ + if (additionalFields.probability) { body.probability = additionalFields.probability as number; } - if(additionalFields.contactIds){ + if (additionalFields.contactIds) { body.contactIds = additionalFields.contactIds as string[]; } - if(additionalFields.customData){ + if (additionalFields.customData) { // @ts-ignore body.customData = additionalFields.customData.customProperty as IDealCustomProperty[]; } @@ -577,7 +561,6 @@ export class AgileCrm implements INodeType { } } - if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else { @@ -588,5 +571,5 @@ export class AgileCrm implements INodeType { return [this.helpers.returnJsonArray(returnData)]; } - + } diff --git a/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts b/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts index a3bfaafc3f..08b45d2090 100644 --- a/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts +++ b/packages/nodes-base/nodes/AgileCrm/CompanyDescription.ts @@ -45,11 +45,11 @@ export const companyOperations = [ }, ] as INodeProperties[]; export const companyFields = [ -/* -------------------------------------------------------------------------- */ -/* company:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* company:get */ + /* -------------------------------------------------------------------------- */ { - displayName: 'company ID', + displayName: 'Company ID', name: 'companyId', type: 'string', required: true, @@ -66,7 +66,7 @@ export const companyFields = [ default: '', description: 'Unique identifier for a particular company', }, - + /* -------------------------------------------------------------------------- */ /* company:get all */ /* -------------------------------------------------------------------------- */ @@ -147,7 +147,6 @@ export const companyFields = [ ], }, }, - description: 'Object of values to set as described here.', }, { @@ -174,18 +173,14 @@ export const companyFields = [ displayName: 'Address', name: 'email', type: 'string', - default: '', - placeholder: 'Company address', description: 'Company address.', }, { displayName: 'Email', name: 'email', type: 'string', - default: '', - placeholder: 'Company email', description: 'Company email.', }, { @@ -193,16 +188,13 @@ export const companyFields = [ name: 'name', type: 'string', default: '', - placeholder: 'Company name', description: 'Company name.', }, { displayName: 'Phone', name: 'phone', type: 'string', - default: '', - placeholder: 'Company phone', description: 'Company phone.', }, { @@ -247,14 +239,12 @@ export const companyFields = [ multipleValueButtonText: 'Add Tag', }, default: [], - placeholder: 'Tag', description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', }, { displayName: 'Website', name: 'websiteOptions', type: 'fixedCollection', - description: 'Companies websites.', typeOptions: { multipleValues: true, @@ -273,35 +263,35 @@ export const companyFields = [ description: 'Type of website.', options: [ { - name: 'FACEBOOK', + name: 'Facebook', value: 'facebook', }, { - name: 'FEED', + name: 'Feed', value: 'feed', }, { - name: 'FLICKR', + name: 'Flickr', value: 'flickr', }, { - name: 'LINKEDIN', - value: 'linkedin', - }, - { - name: 'GITHUB', + name: 'Github', value: 'github', }, { - name: 'GOOGLE_PLUS', + name: 'Google Plus', value: 'googlePlus', }, { - name: 'SKYPE', + name: 'LinkedIn', + value: 'linkedin', + }, + { + name: 'Skype', value: 'skype', }, { - name: 'TWITTER', + name: 'Twitter', value: 'twitter', }, { @@ -309,14 +299,14 @@ export const companyFields = [ value: 'url', }, { - name: 'XING', + name: 'Xing', value: 'xing', }, { - name: 'YOUTUBE', + name: 'YouTube', value: 'youtube', }, - ] + ], }, { displayName: 'URL', @@ -324,19 +314,16 @@ export const companyFields = [ type: 'string', required: true, default: '', - description: 'Website URL', - } - ] + }, + ], }, - - ] + ], }, { displayName: 'Custom Properties', name: 'customProperties', type: 'fixedCollection', - description: 'Custom Properties', typeOptions: { multipleValues: true, @@ -352,33 +339,29 @@ export const companyFields = [ type: 'string', required: true, default: '', - description: 'Property name.' }, { displayName: 'Sub Type', name: 'subtype', type: 'string', - default: '', - description: 'Property sub type.', }, { displayName: 'Value', name: 'value', type: 'string', - default: '', - description: 'Property value.', - } - ] + }, + ], }, - ] + ], }, ], }, + /* -------------------------------------------------------------------------- */ /* company:delete */ /* -------------------------------------------------------------------------- */ @@ -400,11 +383,12 @@ export const companyFields = [ default: '', description: 'ID of company to delete', }, + /* -------------------------------------------------------------------------- */ /* company:update */ /* -------------------------------------------------------------------------- */ { - displayName: 'company ID', + displayName: 'Company ID', name: 'companyId', type: 'string', required: true, @@ -459,7 +443,6 @@ export const companyFields = [ ], }, }, - description: 'Object of values to set as described here.', }, { @@ -487,7 +470,6 @@ export const companyFields = [ name: 'email', type: 'string', default: '', - placeholder: 'Company address', description: 'Company address.', }, { @@ -495,7 +477,6 @@ export const companyFields = [ name: 'email', type: 'string', default: '', - placeholder: 'Company email', description: 'Company email.', }, { @@ -507,29 +488,29 @@ export const companyFields = [ options: [ { name: '0', - value: 0 + value: 0, }, { name: '1', - value: 1 + value: 1, }, { name: '2', - value: 2 + value: 2, }, { name: '3', - value: 3 + value: 3, }, { name: '4', - value: 4 + value: 4, }, { name: '5', - value: 5 + value: 5, }, - ] + ], }, { displayName: 'Tags', @@ -540,7 +521,6 @@ export const companyFields = [ multipleValueButtonText: 'Add Tag', }, default: [], - placeholder: 'Tag', description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', }, { @@ -548,7 +528,6 @@ export const companyFields = [ name: 'name', type: 'string', default: '', - placeholder: 'Company name', description: 'Company name.', }, { @@ -556,14 +535,13 @@ export const companyFields = [ name: 'phone', type: 'string', default: '', - placeholder: 'Company phone', description: 'Company phone.', }, { displayName: 'Website', name: 'websiteOptions', type: 'fixedCollection', - description: 'companys websites.', + description: 'Companys websites.', typeOptions: { multipleValues: true, }, @@ -581,35 +559,35 @@ export const companyFields = [ description: 'Type of website.', options: [ { - name: 'FACEBOOK', + name: 'Facebook', value: 'facebook', }, { - name: 'FEED', + name: 'Feed', value: 'feed', }, { - name: 'FLICKR', + name: 'Flickr', value: 'flickr', }, { - name: 'LINKEDIN', - value: 'linkedin', - }, - { - name: 'GITHUB', + name: 'Github', value: 'github', }, { - name: 'GOOGLE_PLUS', + name: 'Google Plus', value: 'googlePlus', }, { - name: 'SKYPE', + name: 'LinkedIn', + value: 'linkedin', + }, + { + name: 'Skype', value: 'skype', }, { - name: 'TWITTER', + name: 'Twitter', value: 'twitter', }, { @@ -617,14 +595,14 @@ export const companyFields = [ value: 'url', }, { - name: 'XING', + name: 'Xing', value: 'xing', }, { - name: 'YOUTUBE', + name: 'YouTube', value: 'youtube', }, - ] + ], }, { displayName: 'URL', @@ -633,10 +611,10 @@ export const companyFields = [ required: true, default: '', description: 'Website URL', - } - ] + }, + ], }, - ] + ], }, { displayName: 'Custom Properties', @@ -657,7 +635,7 @@ export const companyFields = [ type: 'string', required: true, default: '', - description: 'Property name.' + description: 'Property name.', }, { displayName: 'Sub Type', @@ -672,10 +650,9 @@ export const companyFields = [ type: 'string', default: '', description: 'Property value.', - } - ] + }, + ], }, - ] }, ], diff --git a/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts b/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts index 88b38c403d..5043e05b4a 100644 --- a/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts +++ b/packages/nodes-base/nodes/AgileCrm/ContactDescription.ts @@ -47,9 +47,9 @@ export const contactOperations = [ ] as INodeProperties[]; export const contactFields = [ -/* -------------------------------------------------------------------------- */ -/* contact:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Contact ID', name: 'contactId', @@ -68,9 +68,9 @@ export const contactFields = [ default: '', description: 'Unique identifier for a particular contact', }, -/* -------------------------------------------------------------------------- */ -/* contact:get all */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* contact:get all */ + /* -------------------------------------------------------------------------- */ { displayName: 'Limit', name: 'limit', @@ -88,7 +88,7 @@ export const contactFields = [ false, ], }, - } + }, }, { displayName: 'Return All', @@ -150,7 +150,7 @@ export const contactFields = [ ], }, }, - + description: `Object of values to set as described here.`, }, @@ -192,44 +192,40 @@ export const contactFields = [ name: 'subtype', type: 'options', required: true, - default: "", - + default: '', description: 'Type of address.', options: [ { name: 'Home', - value: 'home' + value: 'home', }, { name: 'Postal', - value: 'postal' - } - , + value: 'postal', + }, { name: 'Office', value: 'office' - } - ] + }, + ], }, { displayName: 'Address', name: 'address', type: 'string', required: true, - default: "", + default: '', description: 'Full address.', - } - ] + }, + ], }, - - ] + ], }, { displayName: 'Company', name: 'company', type: 'string', - default: "", - placeholder: 'Company', + default: '', description: 'Company Name.', }, { @@ -250,46 +246,43 @@ export const contactFields = [ name: 'subtype', type: 'options', required: true, - default: "", + default: '', description: 'Type of Email', options: [ { name: 'Work', - value: 'work' + value: 'work', }, { name: 'Personal', - value: 'personal' - } - ] + value: 'personal', + }, + ], }, { displayName: 'Email', name: 'email', type: 'string', required: true, - default: "", + default: '', description: 'Email', - } - ] + }, + ], }, - - ] + ], }, { displayName: 'First Name', name: 'firstName', type: 'string', - default: "", - placeholder: 'First Name', + default: '', description: 'Contact first name.', }, { displayName: 'Last Name', name: 'lastName', type: 'string', - default: "", - placeholder: 'Last Name', + default: '', description: 'Contact last name.', }, { @@ -299,8 +292,8 @@ export const contactFields = [ default: '', description: 'Lead score of contact', typeOptions: { - minValue: 0 - } + minValue: 0, + }, }, { displayName: 'Star Value', @@ -311,29 +304,29 @@ export const contactFields = [ options: [ { name: '0', - value: 0 + value: 0, }, { name: '1', - value: 1 + value: 1, }, { name: '2', - value: 2 + value: 2, }, { name: '3', - value: 3 + value: 3, }, { name: '4', - value: 4 + value: 4, }, { name: '5', - value: 5 + value: 5, }, - ] + ], }, { displayName: 'Phone', @@ -353,52 +346,50 @@ export const contactFields = [ name: 'subtype', type: 'options', required: true, - default: "", + default: '', description: 'Type of phone number.', options: [ { name: 'Home', - value: 'home' - }, - { - name: 'Work', - value: 'work' - } - , - { - name: 'Mobile', - value: 'mobile' - }, - { - name: 'Main', - value: 'main' + value: 'home', }, { name: 'Home Fax', - value: 'homeFax' + value: 'homeFax', }, { - name: 'Work Fax', - value: 'workFax' + name: 'Main', + value: 'main', + }, + { + name: 'Mobile', + value: 'mobile', }, { name: 'Other', - value: 'other' + value: 'other', }, - ] + { + name: 'Work Fax', + value: 'workFax', + }, + { + name: 'Work', + value: 'work', + }, + ], }, { displayName: 'Number', name: 'number', type: 'string', required: true, - default: "", + default: '', description: 'Phone number.', - } - ] + }, + ], }, - - ] + ], }, { displayName: 'Tags', @@ -409,15 +400,13 @@ export const contactFields = [ multipleValueButtonText: 'Add Tag', }, default: [], - placeholder: 'Tag', description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.', - }, + }, { displayName: 'Title', name: 'title', type: 'string', - default: "", - placeholder: 'Title', + default: '', description: 'Professional title.', }, { @@ -438,67 +427,66 @@ export const contactFields = [ name: 'subtype', type: 'options', required: true, - default: "", + default: '', description: 'Type of website.', options: [ + { + name: 'Facebook', + value: 'facebook', + }, + { + name: 'Feed', + value: 'feed', + }, + { + name: 'Flickr', + value: 'flickr', + }, + { + name: 'Github', + value: 'github', + }, + { + name: 'Google Plus', + value: 'googlePlus', + }, + { + name: 'LinkedIn', + value: 'linkedin', + }, + { + name: 'Skype', + value: 'skype', + }, + { + name: 'Twitter', + value: 'twitter', + }, { name: 'URL', value: 'url', }, { - name: 'SKYPE', - value: 'skype', - }, - { - name: 'TWITTER', - value: 'twitter', - }, - { - name: 'LINKEDIN', - value: 'linkedin', - }, - { - name: 'FACEBOOK', - value: 'facebook', - }, - { - name: 'XING', + name: 'Xing', value: 'xing', }, { - name: 'FEED', - value: 'feed', - }, - { - name: 'GOOGLE_PLUS', - value: 'googlePlus', - }, - { - name: 'FLICKR', - value: 'flickr', - }, - { - name: 'GITHUB', - value: 'github', - }, - { - name: 'YOUTUBE', + name: 'YouTube', value: 'youtube', }, - ] + ], }, { displayName: 'URL', name: 'url', type: 'string', required: true, - default: "", + default: '', description: 'Website URL', - } - ] + }, + ], }, - - ] + ], }, { displayName: 'Custom Properties', @@ -518,30 +506,30 @@ export const contactFields = [ name: 'name', type: 'string', required: true, - default: "", - description: 'Property name.' + default: '', + description: 'Property name.', }, { displayName: 'Sub Type', name: 'subtype', type: 'string', - default: "", + default: '', description: 'Property sub type.', }, { displayName: 'Value', name: 'value', type: 'string', - default: "", + default: '', description: 'Property value.', - } - ] + }, + ], }, - - ] + ], }, ], }, + /* -------------------------------------------------------------------------- */ /* contact:delete */ /* -------------------------------------------------------------------------- */ @@ -563,455 +551,441 @@ export const contactFields = [ default: '', description: 'Id of contact to delete.', }, -/* -------------------------------------------------------------------------- */ -/* contact:update */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Contact ID', - name: 'contactId', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'contact', - ], - operation: [ - 'update', - ], - }, - }, - default: '', - description: 'Unique identifier for a particular contact', -}, -{ - displayName: 'JSON Parameters', - name: 'jsonParameters', - type: 'boolean', - default: false, - description: '', - displayOptions: { - show: { - resource: [ - 'contact', - ], - operation: [ - 'update', - ], - }, - }, -}, -{ - displayName: ' Additional Fields', - name: 'additionalFieldsJson', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - default: '', - displayOptions: { - show: { - resource: [ - 'contact', - ], - operation: [ - 'update', - ], - jsonParameters: [ - true, - ], - }, - }, - - description: `Object of values to set as described here.`, -}, -{ - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, - displayOptions: { - show: { - resource: [ - 'contact', - ], - operation: [ - 'update', - ], - jsonParameters: [ - false, - ], - }, - }, - options: [ - { - displayName: 'Address', - name: 'addressOptions', - type: 'fixedCollection', - description: 'Contacts address.', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Address Properties', - name: 'addressProperties', - values: [ - { - displayName: 'Type', - name: 'subtype', - type: 'options', - required: true, - default: "", - - description: 'Type of address.', - options: [ - { - name: 'Home', - value: 'home' - }, - { - name: 'Postal', - value: 'postal' - } - , - { - name: 'Office', - value: 'office' - } - ] - }, - { - displayName: 'Address', - name: 'address', - type: 'string', - required: true, - default: "", - description: 'Full address.', - } - ] - }, - - ] - }, - { - displayName: 'Company', - name: 'company', - type: 'string', - default: "", - placeholder: 'Company', - description: 'Company Name.', - }, - { - displayName: 'Email', - name: 'emailOptions', - type: 'fixedCollection', - description: 'Contact email.', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Email Properties', - name: 'emailProperties', - values: [ - { - displayName: 'Type', - name: 'subtype', - type: 'options', - required: true, - default: "", - description: 'Type of Email', - options: [ - { - name: 'Work', - value: 'work' - }, - { - name: 'Personal', - value: 'personal' - } - ] - }, - { - displayName: 'Email', - name: 'email', - type: 'string', - required: true, - default: "", - description: 'Email', - } - ] - }, - - ] - }, - { - displayName: 'First Name', - name: 'firstName', - type: 'string', - default: "", - placeholder: 'First Name', - description: 'Contact first name.', - }, - { - displayName: 'Last Name', - name: 'lastName', - type: 'string', - default: "", - placeholder: 'Last Name', - description: 'Contact last name.', - }, - { - displayName: 'Lead Score', - name: 'leadScore', - type: 'number', - default: '', - description: 'Lead score of contact', - typeOptions: { - minValue: 0 - } - }, - { - displayName: 'Star Value', - name: 'starValue', - type: 'options', - default: '', - description: 'Rating of contact (Max value 5). This is not applicable for companies.', - options: [ - { - name: '0', - value: 0 - }, - { - name: '1', - value: 1 - }, - { - name: '2', - value: 2 - }, - { - name: '3', - value: 3 - }, - { - name: '4', - value: 4 - }, - { - name: '5', - value: 5 - }, - ] - }, - { - displayName: 'Phone', - name: 'phoneOptions', - type: 'fixedCollection', - description: 'Contacts phone.', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Phone properties', - name: 'phoneProperties', - values: [ - { - displayName: 'Type', - name: 'subtype', - type: 'options', - required: true, - default: "", - description: 'Type of phone number.', - options: [ - { - name: 'Home', - value: 'home' - }, - { - name: 'Work', - value: 'work' - } - , - { - name: 'Mobile', - value: 'mobile' - }, - { - name: 'Main', - value: 'main' - }, - { - name: 'Home Fax', - value: 'homeFax' - }, - { - name: 'Work Fax', - value: 'workFax' - }, - { - name: 'Other', - value: 'other' - }, - ] - }, - { - displayName: 'Number', - name: 'number', - type: 'string', - required: true, - default: "", - description: 'Phone number.', - } - ] - }, - - ] - }, - { - displayName: 'Tags', - name: 'tags', - type: 'string', - typeOptions: { - multipleValues: true, - multipleValueButtonText: 'Add Tag', - }, - default: [], - placeholder: 'Tag', - description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.', - }, - { - displayName: 'Title', - name: 'title', - type: 'string', - default: "", - placeholder: 'Title', - description: 'Professional title.', - }, - { - displayName: 'Website', - name: 'websiteOptions', - type: 'fixedCollection', - description: 'Contacts websites.', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Website properties.', - name: 'websiteProperties', - values: [ - { - displayName: 'Type', - name: 'subtype', - type: 'options', - required: true, - default: "", - description: 'Type of website.', - options: [ - { - name: 'URL', - value: 'url', - }, - { - name: 'SKYPE', - value: 'skype', - }, - { - name: 'TWITTER', - value: 'twitter', - }, - { - name: 'LINKEDIN', - value: 'linkedin', - }, - { - name: 'FACEBOOK', - value: 'facebook', - }, - { - name: 'XING', - value: 'xing', - }, - { - name: 'FEED', - value: 'feed', - }, - { - name: 'GOOGLE_PLUS', - value: 'googlePlus', - }, - { - name: 'FLICKR', - value: 'flickr', - }, - { - name: 'GITHUB', - value: 'github', - }, - { - name: 'YOUTUBE', - value: 'youtube', - }, - ] - }, - { - displayName: 'URL', - name: 'url', - type: 'string', - required: true, - default: "", - description: 'Website URL', - } - ] - }, - - ] - }, - { - displayName: 'Custom Properties', - name: 'customProperties', - type: 'fixedCollection', - description: 'Custom Properties', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Property', - name: 'customProperty', - values: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - default: "", - description: 'Property name.' - }, - { - displayName: 'Sub Type', - name: 'subtype', - type: 'string', - default: "", - description: 'Property sub type.', - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: "", - description: 'Property value.', - } - ] - }, - - ] - }, - ], -}, + /* -------------------------------------------------------------------------- */ + /* contact:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Contact ID', + name: 'contactId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'update', + ], + }, + }, + default: '', + description: 'Unique identifier for a particular contact', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: ' Additional Fields', + name: 'additionalFieldsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'update', + ], + jsonParameters: [ + true, + ], + }, + }, + description: `Object of values to set as described here.`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'contact', + ], + operation: [ + 'update', + ], + jsonParameters: [ + false, + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'addressOptions', + type: 'fixedCollection', + description: 'Contacts address.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Address Properties', + name: 'addressProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: '', + description: 'Type of address.', + options: [ + { + name: 'Home', + value: 'home' + }, + { + name: 'Office', + value: 'office' + }, + { + name: 'Postal', + value: 'postal' + }, + ], + }, + { + displayName: 'Address', + name: 'address', + type: 'string', + required: true, + default: '', + description: 'Full address.', + }, + ], + }, + ], + }, + { + displayName: 'Company', + name: 'company', + type: 'string', + default: '', + description: 'Company Name.', + }, + { + displayName: 'Email', + name: 'emailOptions', + type: 'fixedCollection', + description: 'Contact email.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Email Properties', + name: 'emailProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: '', + description: 'Type of Email', + options: [ + { + name: 'Work', + value: 'work', + }, + { + name: 'Personal', + value: 'personal', + } + ] + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + required: true, + default: '', + description: 'Email', + }, + ], + }, + ], + }, + { + displayName: 'First Name', + name: 'firstName', + type: 'string', + default: '', + description: 'Contact first name.', + }, + { + displayName: 'Last Name', + name: 'lastName', + type: 'string', + default: '', + description: 'Contact last name.', + }, + { + displayName: 'Lead Score', + name: 'leadScore', + type: 'number', + default: '', + description: 'Lead score of contact', + typeOptions: { + minValue: 0, + } + }, + { + displayName: 'Star Value', + name: 'starValue', + type: 'options', + default: '', + description: 'Rating of contact (Max value 5). This is not applicable for companies.', + options: [ + { + name: '0', + value: 0, + }, + { + name: '1', + value: 1, + }, + { + name: '2', + value: 2, + }, + { + name: '3', + value: 3, + }, + { + name: '4', + value: 4, + }, + { + name: '5', + value: 5, + }, + ], + }, + { + displayName: 'Phone', + name: 'phoneOptions', + type: 'fixedCollection', + description: 'Contacts phone.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Phone properties', + name: 'phoneProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: '', + description: 'Type of phone number.', + options: [ + { + name: 'Home', + value: 'home', + }, + { + name: 'Home Fax', + value: 'homeFax', + }, + { + name: 'Main', + value: 'main', + }, + { + name: 'Mobile', + value: 'mobile', + }, + { + name: 'Other', + value: 'other', + }, + { + name: 'Work Fax', + value: 'workFax', + }, + { + name: 'Work', + value: 'work', + }, + ], + }, + { + displayName: 'Number', + name: 'number', + type: 'string', + required: true, + default: '', + description: 'Phone number.', + }, + ], + }, + ], + }, + { + displayName: 'Tags', + name: 'tags', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Tag', + }, + default: [], + description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'Professional title.', + }, + { + displayName: 'Website', + name: 'websiteOptions', + type: 'fixedCollection', + description: 'Contacts websites.', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Website properties.', + name: 'websiteProperties', + values: [ + { + displayName: 'Type', + name: 'subtype', + type: 'options', + required: true, + default: '', + description: 'Type of website.', + options: [ + { + name: 'Facebook', + value: 'facebook', + }, + { + name: 'Feed', + value: 'feed', + }, + { + name: 'Flickr', + value: 'flickr', + }, + { + name: 'Github', + value: 'github', + }, + { + name: 'Google Plus', + value: 'googlePlus', + }, + { + name: 'LinkedIn', + value: 'linkedin', + }, + { + name: 'Skype', + value: 'skype', + }, + { + name: 'Twitter', + value: 'twitter', + }, + { + name: 'URL', + value: 'url', + }, + { + name: 'Xing', + value: 'xing', + }, + { + name: 'YouTube', + value: 'youtube', + }, + ], + }, + { + displayName: 'URL', + name: 'url', + type: 'string', + required: true, + default: '', + description: 'Website URL', + }, + ], + }, + ], + }, + { + displayName: 'Custom Properties', + name: 'customProperties', + type: 'fixedCollection', + description: 'Custom Properties', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Property', + name: 'customProperty', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + description: 'Property name.' + }, + { + displayName: 'Sub Type', + name: 'subtype', + type: 'string', + default: '', + description: 'Property sub type.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'Property value.', + }, + ], + }, + ], + }, + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts b/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts index 373786bafb..3a18ed3e15 100644 --- a/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts +++ b/packages/nodes-base/nodes/AgileCrm/ContactInterface.ts @@ -1,27 +1,26 @@ import { IDataObject, - } from 'n8n-workflow'; +} from 'n8n-workflow'; - export interface IProperty { - type: string; - name: string; - subtype?: string; - value?: string; +export interface IProperty { + type: string; + name: string; + subtype?: string; + value?: string; } - export interface IContact { - type?: string; - star_value?: string; - lead_score?: string; - tags?: string[]; - properties?: IDataObject[]; - } - - export interface IContactUpdate { - id: string; - properties?: IDataObject[]; - star_value?: string; - lead_score?: string; - tags?: string[]; - } +export interface IContact { + type?: string; + star_value?: string; + lead_score?: string; + tags?: string[]; + properties?: IDataObject[]; +} +export interface IContactUpdate { + id: string; + properties?: IDataObject[]; + star_value?: string; + lead_score?: string; + tags?: string[]; +} diff --git a/packages/nodes-base/nodes/AgileCrm/DealDescription.ts b/packages/nodes-base/nodes/AgileCrm/DealDescription.ts index 673fe68524..443017cfd6 100644 --- a/packages/nodes-base/nodes/AgileCrm/DealDescription.ts +++ b/packages/nodes-base/nodes/AgileCrm/DealDescription.ts @@ -1,6 +1,6 @@ import { INodeProperties, - } from 'n8n-workflow'; +} from 'n8n-workflow'; export const dealOperations = [ { @@ -15,12 +15,12 @@ export const dealOperations = [ }, }, options: [ - { + { name: 'Create', value: 'create', description: 'Create a new deal', - }, - { + }, + { name: 'Delete', value: 'delete', description: 'Delete a deal', @@ -48,9 +48,9 @@ export const dealOperations = [ ] as INodeProperties[]; export const dealFields = [ -/* -------------------------------------------------------------------------- */ -/* deal:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* deal:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Deal ID', name: 'dealId', @@ -69,455 +69,447 @@ export const dealFields = [ default: '', description: 'Unique identifier for a particular deal', }, - - -/* -------------------------------------------------------------------------- */ -/* deal:get all */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Limit', - name: 'limit', - type: 'number', - default: 20, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'getAll', - ], - returnAll: [ - false, - ], - }, - } - }, - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'getAll', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, -/* -------------------------------------------------------------------------- */ -/* deal:create */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Close Date', - name: 'closeDate', - type: 'dateTime', - required: true, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - default: '', - description: 'Closing date of deal.', - }, - { - displayName: 'Expected Value', - name: 'expectedValue', - type: 'number', - required: true, - typeOptions: { - minValue: 0, - maxValue: 1000000000000 - }, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - default: 1, - description: 'Expected Value of deal.', - }, - { - displayName: 'Milestone', - name: 'milestone', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - default: '', - description: 'Milestone of deal.', - }, - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - default: '', - description: 'Name of deal.', - }, - { - displayName: 'Probability', - name: 'probability', - type: 'number', - required: true, - typeOptions: { - minValue: 0, - maxValue: 100 - }, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - default: 50, - description: 'Expected probability.', - }, - { - displayName: 'JSON Parameters', - name: 'jsonParameters', - type: 'boolean', - default: false, - description: '', - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - }, - }, - }, - { - displayName: ' Additional Fields', - name: 'additionalFieldsJson', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - default: '', - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - true, - ], - }, - }, - - description: `Object of values to set as described here.`, - }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'create', - ], - jsonParameters: [ - false, - ], - }, - }, - options: [ - { - displayName: 'Contact Ids', - name: 'contactIds', - type: 'string', - typeOptions: { - multipleValues: true, - multipleValueButtonText: 'Add ID', - }, - default: [], - placeholder: 'ID', - description: 'Unique contact identifiers.', - }, - { - displayName: 'Custom Data', - name: 'customData', - type: 'fixedCollection', - - description: 'Custom Data', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Property', - name: 'customProperty', - values: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - default: "", - description: 'Property name.' - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: "", - description: 'Property value.', - } - ] - }, - - ] - }, - ] - }, + /* -------------------------------------------------------------------------- */ + /* deal:get all */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 20, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, -/* -------------------------------------------------------------------------- */ -/* deal:delete */ -/* -------------------------------------------------------------------------- */ -{ - displayName: 'Deal ID', - name: 'dealId', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'delete', - ], - }, - }, - default: '', - description: 'ID of deal to delete', -}, - -/* -------------------------------------------------------------------------- */ -/* deal:update */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Deal ID', - name: 'dealId', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'update', - ], - }, - }, - default: '', - description: 'Id of deal to update', - }, - { - displayName: 'JSON Parameters', - name: 'jsonParameters', - type: 'boolean', - default: false, - description: '', - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'update', - ], - }, - }, - }, - { - displayName: 'Additional Fields', - name: 'additionalFieldsJson', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - default: '', - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'update', - ], - jsonParameters: [ - true, - ], - }, - }, - - description: `Object of values to set as described here.`, - }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, - displayOptions: { - show: { - resource: [ - 'deal', - ], - operation: [ - 'update', - ], - jsonParameters: [ - false, - ], - }, - }, - options: [ - { - displayName: 'Expected Value', - name: 'expectedValue', - type: 'number', - typeOptions: { - minValue: 0, - maxValue: 10000 - }, - default: '', - description: 'Expected Value of deal.', - }, - { - displayName: 'Name', - name: 'name', - type: 'string', - default: '', - description: 'Name of deal.', - }, - { - displayName: 'Probability', - name: 'probability', - type: 'number', - typeOptions: { - minValue: 0, - maxValue: 100 - }, - default: 50, - description: 'Expected Value of deal.', - }, - { - displayName: 'Contact Ids', - name: 'contactIds', - type: 'string', - typeOptions: { - multipleValues: true, - multipleValueButtonText: 'Add ID', - }, - default: [], - placeholder: 'ID', - description: 'Unique contact identifiers.', - }, - { - displayName: 'Custom Data', - name: 'customData', - type: 'fixedCollection', - description: 'Custom Data', - typeOptions: { - multipleValues: true, - }, - options: [ - { - displayName: 'Property', - name: 'customProperty', - values: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - default: "", - description: 'Property name.' - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: "", - description: 'Property value.', - } - ] - }, - - ] - }, - ] - }, + /* -------------------------------------------------------------------------- */ + /* deal:create */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Close Date', + name: 'closeDate', + type: 'dateTime', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + default: '', + description: 'Closing date of deal.', + }, + { + displayName: 'Expected Value', + name: 'expectedValue', + type: 'number', + required: true, + typeOptions: { + minValue: 0, + maxValue: 1000000000000 + }, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + default: 1, + description: 'Expected Value of deal.', + }, + { + displayName: 'Milestone', + name: 'milestone', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + default: '', + description: 'Milestone of deal.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + default: '', + description: 'Name of deal.', + }, + { + displayName: 'Probability', + name: 'probability', + type: 'number', + required: true, + typeOptions: { + minValue: 0, + maxValue: 100 + }, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + default: 50, + description: 'Expected probability.', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: ' Additional Fields', + name: 'additionalFieldsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + true, + ], + }, + }, + description: `Object of values to set as described here.`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'create', + ], + jsonParameters: [ + false, + ], + }, + }, + options: [ + { + displayName: 'Contact Ids', + name: 'contactIds', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add ID', + }, + default: [], + description: 'Unique contact identifiers.', + }, + { + displayName: 'Custom Data', + name: 'customData', + type: 'fixedCollection', + description: 'Custom Data', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Property', + name: 'customProperty', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + description: 'Property name.' + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'Property value.', + }, + ], + }, + ], + }, + ], + }, + /* -------------------------------------------------------------------------- */ + /* deal:delete */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Deal ID', + name: 'dealId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'delete', + ], + }, + }, + default: '', + description: 'ID of deal to delete', + }, + + /* -------------------------------------------------------------------------- */ + /* deal:update */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Deal ID', + name: 'dealId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + }, + }, + default: '', + description: 'Id of deal to update', + }, + { + displayName: 'JSON Parameters', + name: 'jsonParameters', + type: 'boolean', + default: false, + description: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFieldsJson', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + jsonParameters: [ + true, + ], + }, + }, + + description: `Object of values to set as described here.`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'deal', + ], + operation: [ + 'update', + ], + jsonParameters: [ + false, + ], + }, + }, + options: [ + { + displayName: 'Expected Value', + name: 'expectedValue', + type: 'number', + typeOptions: { + minValue: 0, + maxValue: 10000 + }, + default: '', + description: 'Expected Value of deal.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of deal.', + }, + { + displayName: 'Probability', + name: 'probability', + type: 'number', + typeOptions: { + minValue: 0, + maxValue: 100 + }, + default: 50, + description: 'Expected Value of deal.', + }, + { + displayName: 'Contact Ids', + name: 'contactIds', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add ID', + }, + default: [], + description: 'Unique contact identifiers.', + }, + { + displayName: 'Custom Data', + name: 'customData', + type: 'fixedCollection', + description: 'Custom Data', + typeOptions: { + multipleValues: true, + }, + options: [ + { + displayName: 'Property', + name: 'customProperty', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + description: 'Property name.' + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'Property value.', + }, + ], + }, + ], + }, + ] + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/AgileCrm/DealInterface.ts b/packages/nodes-base/nodes/AgileCrm/DealInterface.ts index 930831a870..5b34f9fb7d 100644 --- a/packages/nodes-base/nodes/AgileCrm/DealInterface.ts +++ b/packages/nodes-base/nodes/AgileCrm/DealInterface.ts @@ -1,15 +1,15 @@ export interface IDealCustomProperty { - name: string; - value: string; + name: string; + value: string; } export interface IDeal { - id?: number; - expected_value?: number; - probability?: number; - name?: string; - close_date?: number; - milestone?: string; - contactIds?: string[]; - customData?: IDealCustomProperty[]; -} \ No newline at end of file + id?: number; + expected_value?: number; + probability?: number; + name?: string; + close_date?: number; + milestone?: string; + contactIds?: string[]; + customData?: IDealCustomProperty[]; +} diff --git a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts index 9a762044cd..8be59de7f5 100644 --- a/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts +++ b/packages/nodes-base/nodes/AgileCrm/GenericFunctions.ts @@ -1,6 +1,6 @@ import { OptionsWithUri - } from 'request'; +} from 'request'; import { IExecuteFunctions, @@ -12,81 +12,74 @@ import { import { IDataObject, } from 'n8n-workflow'; -import { IContactUpdate, IProperty } from './ContactInterface'; +import { IContactUpdate } from './ContactInterface'; -export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { +export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('agileCrmApi'); + const credentials = this.getCredentials('agileCrmApi'); const options: OptionsWithUri = { method, headers: { 'Accept': 'application/json', }, - auth: { + auth: { username: credentials!.email as string, password: credentials!.apiKey as string }, uri: uri || `https://n8nio.agilecrm.com/dev/${endpoint}`, - json: true + json: true, }; // Only add Body property if method not GET or DELETE to avoid 400 response - if(method !== "GET" && method !== "DELETE"){ + if (method !== 'GET' && method !== 'DELETE') { options.body = body; } - try { return await this.helpers.request!(options); } catch (error) { - - if (error.response && error.response.body && error.response.body.errors) { - const errorMessages = error.response.body.errors.map((e: IDataObject) => e.message); - throw new Error(`AgileCRM error response [${error.statusCode}]: ${errorMessages.join(' | ')}`); - } - - throw error; + throw new Error(`AgileCRM error response: ${error.message}`); } } -export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method = 'PUT', endpoint?: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { +export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method = 'PUT', endpoint?: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise { // tslint:disable-line:no-any const baseUri = 'https://n8nio.agilecrm.com/dev/'; - const credentials = this.getCredentials('agileCrmApi'); + const credentials = this.getCredentials('agileCrmApi'); const options: OptionsWithUri = { method, headers: { 'Accept': 'application/json', }, - body: {id: body.id}, - auth: { + body: { id: body.id }, + auth: { username: credentials!.email as string, - password: credentials!.apiKey as string + password: credentials!.apiKey as string, }, uri: uri || baseUri, - json: true + json: true, }; - const successfulUpdates = []; - let lastSuccesfulUpdateReturn : any; - const payload : IContactUpdate = body; - + const successfulUpdates = []; + let lastSuccesfulUpdateReturn: any; // tslint:disable-line:no-any + const payload: IContactUpdate = body; + try { // Due to API, we must update each property separately. For user it looks like one seamless update - if(payload.properties){ + if (payload.properties) { options.body.properties = payload.properties; options.uri = baseUri + 'api/contacts/edit-properties'; lastSuccesfulUpdateReturn = await this.helpers.request!(options); // Iterate trough properties and show them as individial updates instead of only vague "properties" - payload.properties?.map((property : any) => { - successfulUpdates.push(`${property.name} `); + payload.properties?.map((property: any) => { // tslint:disable-line:no-any + successfulUpdates.push(`${property.name}`); }); delete options.body.properties; } - if(payload.lead_score){ + if (payload.lead_score) { options.body.lead_score = payload.lead_score; options.uri = baseUri + 'api/contacts/edit/lead-score'; lastSuccesfulUpdateReturn = await this.helpers.request!(options); @@ -95,18 +88,18 @@ export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFu delete options.body.lead_score; } - if(body.tags){ + if (body.tags) { options.body.tags = payload.tags; options.uri = baseUri + 'api/contacts/edit/tags'; lastSuccesfulUpdateReturn = await this.helpers.request!(options); - payload.tags?.map((tag : string) => { - successfulUpdates.push(`(Tag) ${tag} `); + payload.tags?.map((tag: string) => { + successfulUpdates.push(`(Tag) ${tag}`); }); delete options.body.tags; } - if(body.star_value){ + if (body.star_value) { options.body.star_value = payload.star_value; options.uri = baseUri + 'api/contacts/edit/add-star'; lastSuccesfulUpdateReturn = await this.helpers.request!(options); @@ -119,13 +112,11 @@ export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFu return lastSuccesfulUpdateReturn; } catch (error) { - - if (error.response && error.response.body && error.response.body.errors) { - const errorMessages = error.response.body.errors.map((e: IDataObject) => e.message); - throw new Error(`AgileCRM error response [${error.statusCode}]: ${errorMessages.join(' | ')}`); + if (successfulUpdates.length === 0) { + throw new Error(`AgileCRM error response: ${error.message}`); + } else { + throw new Error(`Not all properties updated. Updated properties: ${successfulUpdates.join(', ')} \n \nAgileCRM error response: ${error.message}`); } - - throw new Error(`Not all items updated. Updated items: ${successfulUpdates.join(' , ')} \n \n` + error); } } @@ -139,4 +130,3 @@ export function validateJSON(json: string | undefined): any { // tslint:disable- } return result; } - diff --git a/packages/nodes-base/nodes/AgileCrm/agilecrm.png b/packages/nodes-base/nodes/AgileCrm/agilecrm.png index ef6ac995a32b776d569b203cbdd1969d99aa977b..711d2dc3b14cf5bab8dc1c4a234b9b1e1583ace4 100644 GIT binary patch delta 1210 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 UrKTU<{!