From dd6d523b85ed14ed200d91b02e7525e03652b36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 2 Apr 2021 19:12:19 +0200 Subject: [PATCH] :sparkles: Add Copper node (#1571) * :tada: Register regular node * :art: Replace PNG with SVG icon * :sparkles: Add Copper regular node * :zap: Add user and customer sources * :shirt: Appease linter * :zap: Handle listings in getAll operations * :zap: Implement continueOnFail * :zap: Simplify pagination * :hammer: Fix fields adjustments for person * zap: Improvements * :zap: Minor fixes * :zap: Fix Lead Email update & Minor improvements Co-authored-by: ricardo Co-authored-by: Jan Oberhauser --- .../nodes-base/nodes/Copper/Copper.node.ts | 704 ++++++++++++ .../nodes/Copper/CopperTrigger.node.ts | 4 +- .../nodes/Copper/GenericFunctions.ts | 169 ++- packages/nodes-base/nodes/Copper/copper.png | Bin 2145 -> 0 bytes packages/nodes-base/nodes/Copper/copper.svg | 25 + .../Copper/descriptions/CompanyDescription.ts | 289 +++++ .../descriptions/CustomerSourceDescription.ts | 73 ++ .../Copper/descriptions/LeadDescription.ts | 274 +++++ .../descriptions/OpportunityDescription.ts | 284 +++++ .../Copper/descriptions/PersonDescription.ts | 286 +++++ .../Copper/descriptions/ProjectDescription.ts | 308 +++++ .../Copper/descriptions/TaskDescription.ts | 346 ++++++ .../Copper/descriptions/UserDescription.ts | 73 ++ .../nodes/Copper/descriptions/index.ts | 8 + .../nodes/Copper/utils/isoCountryCodes.ts | 1000 +++++++++++++++++ .../nodes/Copper/utils/sharedFields.ts | 140 +++ .../nodes-base/nodes/Copper/utils/types.d.ts | 23 + packages/nodes-base/package.json | 1 + 18 files changed, 3995 insertions(+), 12 deletions(-) create mode 100644 packages/nodes-base/nodes/Copper/Copper.node.ts delete mode 100644 packages/nodes-base/nodes/Copper/copper.png create mode 100644 packages/nodes-base/nodes/Copper/copper.svg create mode 100644 packages/nodes-base/nodes/Copper/descriptions/CompanyDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/CustomerSourceDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/LeadDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/OpportunityDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/PersonDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/ProjectDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/TaskDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/UserDescription.ts create mode 100644 packages/nodes-base/nodes/Copper/descriptions/index.ts create mode 100644 packages/nodes-base/nodes/Copper/utils/isoCountryCodes.ts create mode 100644 packages/nodes-base/nodes/Copper/utils/sharedFields.ts create mode 100644 packages/nodes-base/nodes/Copper/utils/types.d.ts diff --git a/packages/nodes-base/nodes/Copper/Copper.node.ts b/packages/nodes-base/nodes/Copper/Copper.node.ts new file mode 100644 index 0000000000..b0361dcd0c --- /dev/null +++ b/packages/nodes-base/nodes/Copper/Copper.node.ts @@ -0,0 +1,704 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + adjustCompanyFields, + adjustLeadFields, + adjustPersonFields, + adjustTaskFields, + copperApiRequest, + handleListing, +} from './GenericFunctions'; + +import { + companyFields, + companyOperations, + customerSourceFields, + customerSourceOperations, + leadFields, + leadOperations, + opportunityFields, + opportunityOperations, + personFields, + personOperations, + projectFields, + projectOperations, + taskFields, + taskOperations, + userFields, + userOperations, +} from './descriptions'; + +export class Copper implements INodeType { + description: INodeTypeDescription = { + displayName: 'Copper', + name: 'copper', + icon: 'file:copper.svg', + group: ['transform'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume the Copper API', + defaults: { + name: 'Copper', + color: '#ff2564', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'copperApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Company', + value: 'company', + }, + { + name: 'Customer Source', + value: 'customerSource', + }, + { + name: 'Lead', + value: 'lead', + }, + { + name: 'Opportunity', + value: 'opportunity', + }, + { + name: 'Person', + value: 'person', + }, + { + name: 'Project', + value: 'project', + }, + { + name: 'Task', + value: 'task', + }, + { + name: 'User', + value: 'user', + }, + ], + default: 'company', + description: 'Resource to consume', + }, + ...companyOperations, + ...companyFields, + ...customerSourceOperations, + ...customerSourceFields, + ...leadOperations, + ...leadFields, + ...opportunityOperations, + ...opportunityFields, + ...personOperations, + ...personFields, + ...projectOperations, + ...projectFields, + ...taskOperations, + ...taskFields, + ...userOperations, + ...userFields, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + + let responseData; + + for (let i = 0; i < items.length; i++) { + + try { + + if (resource === 'company') { + + // ********************************************************************** + // company + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // company: create + // ---------------------------------------- + + // https://developer.copper.com/companies/create-a-new-company.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + }; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, adjustCompanyFields(additionalFields)); + } + + responseData = await copperApiRequest.call(this, 'POST', '/companies', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // company: delete + // ---------------------------------------- + + // https://developer.copper.com/companies/delete-a-company.html + + const companyId = this.getNodeParameter('companyId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/companies/${companyId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // company: get + // ---------------------------------------- + + // https://developer.copper.com/companies/fetch-a-company-by-id.html + + const companyId = this.getNodeParameter('companyId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/companies/${companyId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // company: getAll + // ---------------------------------------- + + // https://developer.copper.com/companies/list-companies-search.html + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, filterFields); + } + + responseData = await handleListing.call(this, 'POST', '/companies/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // company: update + // ---------------------------------------- + + // https://developer.copper.com/companies/update-a-company.html + + const companyId = this.getNodeParameter('companyId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, adjustCompanyFields(updateFields)); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/companies/${companyId}`, body); + + } + + } else if (resource === 'customerSource') { + + // ********************************************************************** + // customerSource + // ********************************************************************** + + if (operation === 'getAll') { + + // ---------------------------------------- + // customerSource: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/customer_sources'); + + } + + } else if (resource === 'lead') { + + // ********************************************************************** + // lead + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // lead: create + // ---------------------------------------- + + // https://developer.copper.com/leads/create-a-new-lead.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + }; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, adjustLeadFields(additionalFields)); + } + + responseData = await copperApiRequest.call(this, 'POST', '/leads', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // lead: delete + // ---------------------------------------- + + // https://developer.copper.com/leads/delete-a-lead.html + + const leadId = this.getNodeParameter('leadId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/leads/${leadId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // lead: get + // ---------------------------------------- + + // https://developer.copper.com/leads/fetch-a-lead-by-id.html + + const leadId = this.getNodeParameter('leadId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/leads/${leadId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // lead: getAll + // ---------------------------------------- + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, filterFields); + } + + responseData = await handleListing.call(this, 'POST', '/leads/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // lead: update + // ---------------------------------------- + + // https://developer.copper.com/leads/update-a-lead.html + + const leadId = this.getNodeParameter('leadId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, adjustLeadFields(updateFields)); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/leads/${leadId}`, body); + + } + + } else if (resource === 'opportunity') { + + // ********************************************************************** + // opportunity + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // opportunity: create + // ---------------------------------------- + + // https://developer.copper.com/opportunities/create-a-new-opportunity.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + customer_source_id: this.getNodeParameter('customerSourceId', i), + primary_contact_id: this.getNodeParameter('primaryContactId', i), + }; + + responseData = await copperApiRequest.call(this, 'POST', '/opportunities', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // opportunity: delete + // ---------------------------------------- + + // https://developer.copper.com/opportunities/delete-an-opportunity.html + + const opportunityId = this.getNodeParameter('opportunityId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/opportunities/${opportunityId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // opportunity: get + // ---------------------------------------- + + // https://developer.copper.com/opportunities/fetch-an-opportunity-by-id.html + + const opportunityId = this.getNodeParameter('opportunityId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/opportunities/${opportunityId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // opportunity: getAll + // ---------------------------------------- + + // https://developer.copper.com/opportunities/list-opportunities-search.html + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, filterFields); + } + + responseData = await handleListing.call(this, 'POST', '/opportunities/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // opportunity: update + // ---------------------------------------- + + // https://developer.copper.com/opportunities/update-an-opportunity.html + + const opportunityId = this.getNodeParameter('opportunityId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, updateFields); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/opportunities/${opportunityId}`, body); + + } + + } else if (resource === 'person') { + + // ********************************************************************** + // person + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // person: create + // ---------------------------------------- + + // https://developer.copper.com/people/create-a-new-person.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + }; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, adjustPersonFields(additionalFields)); + } + + responseData = await copperApiRequest.call(this, 'POST', '/people', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // person: delete + // ---------------------------------------- + + // https://developer.copper.com/people/delete-a-person.html + + const personId = this.getNodeParameter('personId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/people/${personId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // person: get + // ---------------------------------------- + + // https://developer.copper.com/people/fetch-a-person-by-id.html + + const personId = this.getNodeParameter('personId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/people/${personId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // person: getAll + // ---------------------------------------- + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, filterFields); + } + + responseData = await handleListing.call(this, 'POST', '/people/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // person: update + // ---------------------------------------- + + // https://developer.copper.com/people/update-a-person.html + + const personId = this.getNodeParameter('personId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, adjustPersonFields(updateFields)); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/people/${personId}`, body); + + } + + } else if (resource === 'project') { + + // ********************************************************************** + // project + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // project: create + // ---------------------------------------- + + // https://developer.copper.com/projects/create-a-new-project.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + }; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await copperApiRequest.call(this, 'POST', '/projects', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // project: delete + // ---------------------------------------- + + // https://developer.copper.com/projects/delete-a-project.html + + const projectId = this.getNodeParameter('projectId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/projects/${projectId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // project: get + // ---------------------------------------- + + // https://developer.copper.com/projects/fetch-a-project-by-id.html + + const projectId = this.getNodeParameter('projectId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/projects/${projectId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // project: getAll + // ---------------------------------------- + + // https://developer.copper.com/projects/list-projects-search.html + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, filterFields); + } + + responseData = await handleListing.call(this, 'POST', '/projects/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // project: update + // ---------------------------------------- + + // https://developer.copper.com/projects/update-a-project.html + + const projectId = this.getNodeParameter('projectId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, updateFields); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/projects/${projectId}`, body); + + } + + } else if (resource === 'task') { + + // ********************************************************************** + // task + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // task: create + // ---------------------------------------- + + // https://developer.copper.com/tasks/create-a-new-task.html + + const body: IDataObject = { + name: this.getNodeParameter('name', i), + }; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await copperApiRequest.call(this, 'POST', '/tasks', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // task: delete + // ---------------------------------------- + + // https://developer.copper.com/tasks/delete-a-task.html + + const taskId = this.getNodeParameter('taskId', i); + + responseData = await copperApiRequest.call(this, 'DELETE', `/tasks/${taskId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // task: get + // ---------------------------------------- + + // https://developer.copper.com/tasks/fetch-a-task-by-id.html + + const taskId = this.getNodeParameter('taskId', i); + + responseData = await copperApiRequest.call(this, 'GET', `/tasks/${taskId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // task: getAll + // ---------------------------------------- + + // https://developer.copper.com/tasks/list-tasks-search.html + + const body: IDataObject = {}; + const filterFields = this.getNodeParameter('filterFields', i) as IDataObject; + + if (Object.keys(filterFields).length) { + Object.assign(body, adjustTaskFields(filterFields)); + } + + responseData = await handleListing.call(this, 'POST', '/tasks/search', body); + + } else if (operation === 'update') { + + // ---------------------------------------- + // task: update + // ---------------------------------------- + + // https://developer.copper.com/tasks/update-a-task.html + + const taskId = this.getNodeParameter('taskId', i); + + const body: IDataObject = {}; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + if (Object.keys(updateFields).length) { + Object.assign(body, updateFields); + } + + responseData = await copperApiRequest.call(this, 'PUT', `/tasks/${taskId}`, body); + } + + } else if (resource === 'user') { + + // ********************************************************************** + // user + // ********************************************************************** + + if (operation === 'getAll') { + + // ---------------------------------------- + // user: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'POST', '/users/search'); + + } + } + + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ error: error.toString() }); + continue; + } + + throw error; + } + + Array.isArray(responseData) + ? returnData.push(...responseData) + : returnData.push(responseData); + + } + + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts index 36ab84d6da..cfaf575f38 100644 --- a/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts +++ b/packages/nodes-base/nodes/Copper/CopperTrigger.node.ts @@ -19,7 +19,7 @@ export class CopperTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Copper Trigger', name: 'copperTrigger', - icon: 'file:copper.png', + icon: 'file:copper.svg', group: ['trigger'], version: 1, description: 'Handle Copper events via webhooks', @@ -147,7 +147,7 @@ export class CopperTrigger implements INodeType { const endpoint = `/webhooks/${webhookData.webhookId}`; try { await copperApiRequest.call(this, 'DELETE', endpoint); - } catch(error) { + } catch (error) { return false; } delete webhookData.webhookId; diff --git a/packages/nodes-base/nodes/Copper/GenericFunctions.ts b/packages/nodes-base/nodes/Copper/GenericFunctions.ts index 9fc46f9d96..2fbf4f315d 100644 --- a/packages/nodes-base/nodes/Copper/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Copper/GenericFunctions.ts @@ -1,5 +1,10 @@ -import { createHash } from 'crypto'; -import { OptionsWithUri } from 'request'; +import { + createHash, +} from 'crypto'; + +import { + OptionsWithUri, +} from 'request'; import { IExecuteFunctions, @@ -8,16 +13,37 @@ import { ILoadOptionsFunctions, IWebhookFunctions, } from 'n8n-core'; + import { ICredentialDataDecryptedObject, IDataObject, } from 'n8n-workflow'; -export async function copperApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any - const credentials = this.getCredentials('copperApi'); - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } +import { + flow, + omit, +} from 'lodash'; + +import { + AddressFixedCollection, + EmailFixedCollection, + EmailsFixedCollection, + PhoneNumbersFixedCollection, +} from './utils/types'; + +/** + * Make an authenticated API request to Copper. + */ +export async function copperApiRequest( + this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, + method: string, + resource: string, + body: IDataObject = {}, + qs: IDataObject = {}, + uri = '', + option: IDataObject = {}, +) { + const credentials = this.getCredentials('copperApi') as { apiKey: string, email: string }; let options: OptionsWithUri = { headers: { @@ -29,10 +55,16 @@ export async function copperApiRequest(this: IHookFunctions | IExecuteFunctions method, qs, body, - uri: uri ||`https://api.prosperworks.com/developer_api/v1${resource}`, + uri: uri || `https://api.prosperworks.com/developer_api/v1${resource}`, json: true, }; + options = Object.assign({}, options, option); + + if (!Object.keys(qs).length) { + delete options.qs; + } + if (Object.keys(options.body).length === 0) { delete options.body; } @@ -41,11 +73,11 @@ export async function copperApiRequest(this: IHookFunctions | IExecuteFunctions return await this.helpers.request!(options); } catch (error) { let errorMessage = error.message; - if (error.response.body && error.response.body.message) { + if (error.response.body?.message) { errorMessage = error.response.body.message; } - throw new Error('Copper Error: ' + errorMessage); + throw new Error(`Copper error response [${error.statusCode}]: ${errorMessage}`); } } @@ -61,3 +93,120 @@ export function getAutomaticSecret(credentials: ICredentialDataDecryptedObject) const data = `${credentials.email},${credentials.apiKey}`; return createHash('md5').update(data).digest('hex'); } + +export function adjustAddress(fixedCollection: AddressFixedCollection) { + if (!fixedCollection.address) return fixedCollection; + + const adjusted: { address?: object } = omit(fixedCollection, ['address']); + + if (fixedCollection.address) { + adjusted.address = fixedCollection.address.addressFields; + } + + return adjusted; +} + +export function adjustPhoneNumbers(fixedCollection: PhoneNumbersFixedCollection) { + if (!fixedCollection.phone_numbers) return fixedCollection; + + const adjusted: { phone_numbers?: object } = omit(fixedCollection, ['phone_numbers']); + + if (fixedCollection.phone_numbers) { + adjusted.phone_numbers = fixedCollection.phone_numbers.phoneFields; + } + + return adjusted; +} + +export function adjustEmails(fixedCollection: EmailsFixedCollection) { + if (!fixedCollection.emails) return fixedCollection; + + const adjusted: { emails?: object } = omit(fixedCollection, ['emails']); + + if (fixedCollection.emails) { + adjusted.emails = fixedCollection.emails.emailFields; + } + + return adjusted; +} + +export function adjustProjectIds(fields: { project_ids?: string }) { + if (!fields.project_ids) return fields; + + const adjusted: { project_ids?: string[] } = omit(fields, ['project_ids']); + + adjusted.project_ids = fields.project_ids.includes(',') + ? fields.project_ids.split(',') + : [fields.project_ids]; + + return adjusted; +} + +export function adjustEmail(fixedCollection: EmailFixedCollection) { + if (!fixedCollection.email) return fixedCollection; + + const adjusted: { email?: object } = omit(fixedCollection, ['email']); + + if (fixedCollection.email) { + adjusted.email = fixedCollection.email.emailFields; + } + + return adjusted; +} + +export const adjustCompanyFields = flow(adjustAddress, adjustPhoneNumbers); +export const adjustLeadFields = flow(adjustCompanyFields, adjustEmail); +export const adjustPersonFields = flow(adjustCompanyFields, adjustEmails); +export const adjustTaskFields = flow(adjustLeadFields, adjustProjectIds); + +/** + * Handle a Copper listing by returning all items or up to a limit. + */ +export async function handleListing( + this: IExecuteFunctions, + method: string, + endpoint: string, + qs: IDataObject = {}, + body: IDataObject = {}, + uri = '', +) { + let responseData; + + const returnAll = this.getNodeParameter('returnAll', 0); + + const option = { resolveWithFullResponse: true }; + + if (returnAll) { + return await copperApiRequestAllItems.call(this, method, endpoint, body, qs, uri, option); + } + + const limit = this.getNodeParameter('limit', 0) as number; + responseData = await copperApiRequestAllItems.call(this, method, endpoint, body, qs, uri, option); + return responseData.slice(0, limit); +} + +/** + * Make an authenticated API request to Copper and return all items. + */ +export async function copperApiRequestAllItems( + this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions, + method: string, + resource: string, + body: IDataObject = {}, + qs: IDataObject = {}, + uri = '', + option: IDataObject = {}, +) { + let responseData; + qs.page_size = 200; + let totalItems = 0; + const returnData: IDataObject[] = []; + + do { + responseData = await copperApiRequest.call(this, method, resource, body, qs, uri, option); + totalItems = responseData.headers['x-pw-total']; + returnData.push(...responseData.body); + } while (totalItems > returnData.length); + + return returnData; +} diff --git a/packages/nodes-base/nodes/Copper/copper.png b/packages/nodes-base/nodes/Copper/copper.png deleted file mode 100644 index 0ef15b8c66610dee3d45ee5317e1177bcd319fc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2145 zcmW-ic|6oz7r;kkSG?)T_DGiOWtkz7B?iOT*X-L^vW=x^Dr<Y`^o2zMpeH_uPB#Ip^MU|2Xl+hB|D_Jj^H*iVdf$WlEh@4hJLc;f|oV zItoQIVT?D&QkNj_3bKYE?*=+ihdNa-Zcsl6oqZtX3}`pN5a5D4h}(cH)#?VrQwYWd zLUKWm2+E!ikpbubcu`L(5dK7PgQ_M_atDkD>;p7+?>a>T6{=Oj5s2}K4GAQiASx3` zDUeeRSU*trK6K0|g*(}ZQy7HaM~Z5Y`vnN`E@*fo_&_B03E~@vl+=M!I7DVadI>yl z1Dl(0*_V1HB)JHQ&ja+I?8F4n@&k-3Qc@2oC6G`6Yn%J^?R)w`Ff@e>O&mUfikvGP z9KaPdxC3CkLEIc9TtU(qSl0`0A)X9;sXqhK|sP`#l(yt{~4qdL2M4<6NA{@gmbR2zKJX? zBOg8@@28-p8+q~q9+W~@8vOVP!2SD(V3v;1)_2iI9j0ot4Xk_p&9Ccc9(8%XOE6{Z^&eS zZ+E~*;Ml>z{w}4pp*A)OFCidsf_;B~XXiJCGEZe_Xz1MlmHyV&hKAajVk)s=VPOOU z!ORdZDJei8h)kLhP^hC6oR)^UZf{H$gXXv~d&CKs3OP6ul|Zkg5OLYi$JRSM&y{aRU@-#u9d>;>R3u^TEpsoGs-=?$`gMPviXZazt4H+6B=12MW4oy@yx5lOSImpQo;+jOG;FtBD}CyxB|k;lpNpI~ zeQIPa!1L{QRURF8?zX6PhAJV8V7BQ%)|nmw!)x~uIZ`y!&x_{=A5LGYyn~!ns+4H- z(z|MHxs*RT#hrnnUrcn#9IemS^E@f^<65VoXKF?z>05LUC8CK&?Jl#_5K&k%zMBYf z1r^^5>PG*`K|bl?Erqij97CC$&00ndXcl-g^U?Hr_Qhhuw?4d(nUhYiFI|i`pD9)B zZ48be(=Al96coBC%kA;^8Iyk1IM3yNkdDfTJ(2iV|!y0)ptvI=6gZjkL7{`Y=AP-4eD)i|R)4M}EAi zSrl__r|O>Asy$77NUMoY!`vue`I*>;WH-iN2TVCnCElKzu>G!ml(kq*X-u*VTdYK< z`oD(lbNf$=O)pqw`7$(#f9J_ek9HB$`uR#nnD1_`L~wj4>o2oKe9V)}1H*yyZ)YP| zp4G{^)2Wo4p~X7u=6o)xY;C6v9MVtgt=0YX(k8njH7r;ofvl|Vwm9wX$8ZOK6w4R9 zq=-6SmtSDiEV7X6wK8jGT_^uo-&q8c=u#FRk@ENEmFdFPP~$TkBdNi%*}o4g@o~he z^f{d#|3}M>^r7WVf@GA^h7N<}JE^DB0{924?$)zDe4pnFLG=Kf)!udw(|y!j0Z03_?s%1jS%{{nboaVx%Kw5 z{tv&-26yJ*@W$DeA(L=Qn&`d5i?Pu1|NHCMl?l>p7GFbB@8F=A(3L5kRTwQheUL$hdzB_8$*nXE?Somnoqj|iEYfyga4OJF z6m4c|&aH)gmd50g+-RKHrpnJS$K|1tCc$}2wQ-IqdsN!MBvRB%i1&oTTb9uu(uoAL zo3wz;0L%C#ypDh1q}0%?=9$$WIERir+WwVs-qTJ!1kWd#|C0EKCAL^WbhUr@F&oM7 z!nMljYYt00Ju)LKY1Px~bPp!gl6V@A76j}T8 zJDF%b7aVfx;j(4#=%k{;n&-2{foPv9|GCjxjvEb}2Mm@;nT + + + + + + + diff --git a/packages/nodes-base/nodes/Copper/descriptions/CompanyDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/CompanyDescription.ts new file mode 100644 index 0000000000..99f1c6df73 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/CompanyDescription.ts @@ -0,0 +1,289 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + isoCountryCodes, +} from '../utils/isoCountryCodes'; + +import { + addressFixedCollection, + phoneNumbersFixedCollection, +} from '../utils/sharedFields'; + +export const companyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'company', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const companyFields = [ + // ---------------------------------------- + // company: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the company to create.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + addressFixedCollection, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description of the company to create.', + }, + { + displayName: 'Email Domain', + name: 'email_domain', + type: 'string', + default: '', + }, + phoneNumbersFixedCollection, + ], + }, + + // ---------------------------------------- + // company: delete + // ---------------------------------------- + { + displayName: 'Company ID', + name: 'companyId', + description: 'ID of the company to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // company: get + // ---------------------------------------- + { + displayName: 'Company ID', + name: 'companyId', + description: 'ID of the company to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // company: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Country', + name: 'country', + type: 'options', + options: isoCountryCodes.map(({ name, alpha2 }) => ({ name, value: alpha2 })), + default: '', + description: 'Country of the company to filter by.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the company to filter by.', + }, + ], + }, + + // ---------------------------------------- + // company: update + // ---------------------------------------- + { + displayName: 'Company ID', + name: 'companyId', + description: 'ID of the company to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + addressFixedCollection, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the company.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the company.', + }, + phoneNumbersFixedCollection, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/CustomerSourceDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/CustomerSourceDescription.ts new file mode 100644 index 0000000000..d9d706beba --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/CustomerSourceDescription.ts @@ -0,0 +1,73 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const customerSourceOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'customerSource', + ], + }, + }, + options: [ + { + name: 'Get All', + value: 'getAll', + }, + ], + default: 'getAll', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const customerSourceFields = [ + // ---------------------------------------- + // customerSource: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'customerSource', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'customerSource', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/LeadDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/LeadDescription.ts new file mode 100644 index 0000000000..be2b567d59 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/LeadDescription.ts @@ -0,0 +1,274 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + addressFixedCollection, + emailFixedCollection, + phoneNumbersFixedCollection, +} from '../utils/sharedFields'; + +export const leadOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'lead', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const leadFields = [ + // ---------------------------------------- + // lead: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the lead to create.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + default: {}, + placeholder: 'Add Field', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + addressFixedCollection, + emailFixedCollection, + phoneNumbersFixedCollection, + ], + }, + + // ---------------------------------------- + // lead: delete + // ---------------------------------------- + { + displayName: 'Lead ID', + name: 'leadId', + description: 'ID of the lead to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // lead: get + // ---------------------------------------- + { + displayName: 'Lead ID', + name: 'leadId', + description: 'ID of the lead to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // lead: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Country', + name: 'country', + type: 'string', + default: '', + description: 'Name of the country to filter by.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the lead to filter by.', + }, + ], + }, + + // ---------------------------------------- + // lead: update + // ---------------------------------------- + { + displayName: 'Lead ID', + name: 'leadId', + description: 'ID of the lead to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'lead', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + addressFixedCollection, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the lead.', + }, + emailFixedCollection, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the lead.', + }, + phoneNumbersFixedCollection, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/OpportunityDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/OpportunityDescription.ts new file mode 100644 index 0000000000..0117672e05 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/OpportunityDescription.ts @@ -0,0 +1,284 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const opportunityOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const opportunityFields = [ + // ---------------------------------------- + // opportunity: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the opportunity to create.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Customer Source ID', + name: 'customerSourceId', + type: 'string', + default: '', + description: 'ID of the customer source that generated this opportunity.', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Primary Contact ID', + name: 'primaryContactId', + type: 'string', + default: '', + description: 'ID of the primary company associated with this opportunity.', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'create', + ], + }, + }, + }, + + // ---------------------------------------- + // opportunity: delete + // ---------------------------------------- + { + displayName: 'Opportunity ID', + name: 'opportunityId', + description: 'ID of the opportunity to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // opportunity: get + // ---------------------------------------- + { + displayName: 'Opportunity ID', + name: 'opportunityId', + description: 'ID of the opportunity to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // opportunity: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Company IDs', + name: 'company_ids', + type: 'string', + default: '', + description: 'Comma-separated IDs of the primary companies to filter by.', + }, + { + displayName: 'Customer Source IDs', + name: 'customer_source_ids', + type: 'string', + default: '', + description: 'Comma-separated IDs of the customer sources to filter by.', + }, + ], + }, + + // ---------------------------------------- + // opportunity: update + // ---------------------------------------- + { + displayName: 'Opportunity ID', + name: 'opportunityId', + description: 'ID of the opportunity to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'opportunity', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Customer Source ID', + name: 'customer_source_id', + type: 'string', + default: '', + description: 'ID of the primary company associated with this opportunity.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the opportunity.', + }, + { + displayName: 'Primary Contact ID', + name: 'primary_contact_id', + type: 'string', + default: '', + description: 'ID of the customer source that generated this opportunity.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/PersonDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/PersonDescription.ts new file mode 100644 index 0000000000..7ffa3b4da3 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/PersonDescription.ts @@ -0,0 +1,286 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + addressFixedCollection, + emailsFixedCollection, + phoneNumbersFixedCollection, +} from '../utils/sharedFields'; + +export const personOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'person', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const personFields = [ + // ---------------------------------------- + // person: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the person to create.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + addressFixedCollection, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the person.', + }, + { + displayName: 'Email Domain', + name: 'email_domain', + type: 'string', + default: '', + }, + emailsFixedCollection, + phoneNumbersFixedCollection, + ], + }, + + // ---------------------------------------- + // person: delete + // ---------------------------------------- + { + displayName: 'Person ID', + name: 'personId', + description: 'ID of the person to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // person: get + // ---------------------------------------- + { + displayName: 'Person ID', + name: 'personId', + description: 'ID of the person to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // person: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the person to filter by.', + }, + ], + }, + + // ---------------------------------------- + // person: update + // ---------------------------------------- + { + displayName: 'Person ID', + name: 'personId', + description: 'ID of the person to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + addressFixedCollection, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the person.', + }, + { + displayName: 'Email Domain', + name: 'email_domain', + type: 'string', + default: '', + }, + emailsFixedCollection, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the person.', + }, + phoneNumbersFixedCollection, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/ProjectDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/ProjectDescription.ts new file mode 100644 index 0000000000..0a07010aee --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/ProjectDescription.ts @@ -0,0 +1,308 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const projectOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'project', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const projectFields = [ + // ---------------------------------------- + // project: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the project to create.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Assignee ID', + name: 'assignee_id', + type: 'string', + default: '', + description: 'ID of the user who will own the project to create.', + }, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description of the project to create.', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Completed', + value: 'Completed', + }, + { + name: 'Open', + value: 'Open', + }, + ], + }, + ], + }, + + // ---------------------------------------- + // project: delete + // ---------------------------------------- + { + displayName: 'Project ID', + name: 'projectId', + description: 'ID of the project to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // project: get + // ---------------------------------------- + { + displayName: 'Project ID', + name: 'projectId', + description: 'ID of the project to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // project: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + default: {}, + placeholder: 'Add Filter', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the project to filter by.', + }, + ], + }, + + // ---------------------------------------- + // project: update + // ---------------------------------------- + { + displayName: 'Project ID', + name: 'projectId', + description: 'ID of the project to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'project', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Assignee ID', + name: 'assignee_id', + type: 'string', + default: '', + description: 'ID of the user who will own the project.', + }, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the project.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the project.', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Completed', + value: 'Completed', + }, + { + name: 'Open', + value: 'Open', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/TaskDescription.ts new file mode 100644 index 0000000000..39af835c08 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/TaskDescription.ts @@ -0,0 +1,346 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const taskOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'task', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + }, + { + name: 'Delete', + value: 'delete', + }, + { + name: 'Get', + value: 'get', + }, + { + name: 'Get All', + value: 'getAll', + }, + { + name: 'Update', + value: 'update', + }, + ], + default: 'create', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const taskFields = [ + // ---------------------------------------- + // task: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Assignee ID', + name: 'assignee_id', + type: 'string', + default: '', + description: 'ID of the user who will own the task to create.', + }, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description of the task to create.', + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 'High', + options: [ + { + name: 'High', + value: 'High', + }, + { + name: 'None', + value: 'None', + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Completed', + value: 'Completed', + }, + { + name: 'Open', + value: 'Open', + }, + ], + }, + ], + }, + + // ---------------------------------------- + // task: delete + // ---------------------------------------- + { + displayName: 'Task ID', + name: 'taskId', + description: 'ID of the task to delete.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // task: get + // ---------------------------------------- + { + displayName: 'Task ID', + name: 'taskId', + description: 'ID of the task to retrieve.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // task: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filterFields', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Assignee IDs', + name: 'assignee_ids', + type: 'string', + default: '', + description: 'Comma-separated IDs of assignee IDs to filter by.', + }, + { + displayName: 'Project IDs', + name: 'project_ids', + type: 'string', + default: '', + description: 'Comma-separated IDs of project IDs to filter by.', + }, + ], + }, + + // ---------------------------------------- + // task: update + // ---------------------------------------- + { + displayName: 'Task ID', + name: 'taskId', + description: 'ID of the task to update.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Assignee ID', + name: 'assignee_id', + type: 'string', + default: '', + description: 'ID of the user who will own the task.', + }, + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Description to set for the task.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name to set for the task.', + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 'High', + options: [ + { + name: 'High', + value: 'High', + }, + { + name: 'None', + value: 'None', + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'Open', + options: [ + { + name: 'Completed', + value: 'Completed', + }, + { + name: 'Open', + value: 'Open', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/UserDescription.ts b/packages/nodes-base/nodes/Copper/descriptions/UserDescription.ts new file mode 100644 index 0000000000..52c45db9f8 --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/UserDescription.ts @@ -0,0 +1,73 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const userOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'user', + ], + }, + }, + options: [ + { + name: 'Get All', + value: 'getAll', + }, + ], + default: 'getAll', + description: 'Operation to perform', + }, +] as INodeProperties[]; + +export const userFields = [ + // ---------------------------------------- + // user: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Return all results.', + displayOptions: { + show: { + resource: [ + 'user', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 5, + description: 'The number of results to return.', + typeOptions: { + minValue: 1, + maxValue: 1000, + }, + displayOptions: { + show: { + resource: [ + 'user', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Copper/descriptions/index.ts b/packages/nodes-base/nodes/Copper/descriptions/index.ts new file mode 100644 index 0000000000..13b61b5aaa --- /dev/null +++ b/packages/nodes-base/nodes/Copper/descriptions/index.ts @@ -0,0 +1,8 @@ +export * from './CompanyDescription'; +export * from './CustomerSourceDescription'; +export * from './LeadDescription'; +export * from './OpportunityDescription'; +export * from './PersonDescription'; +export * from './ProjectDescription'; +export * from './TaskDescription'; +export * from './UserDescription'; diff --git a/packages/nodes-base/nodes/Copper/utils/isoCountryCodes.ts b/packages/nodes-base/nodes/Copper/utils/isoCountryCodes.ts new file mode 100644 index 0000000000..dd5bce6f4c --- /dev/null +++ b/packages/nodes-base/nodes/Copper/utils/isoCountryCodes.ts @@ -0,0 +1,1000 @@ +// ISO 3166 alpha-2 country code + +export const isoCountryCodes = [ + { + name: 'Afghanistan', + alpha2: 'AF', + }, + { + name: 'Åland Islands', + alpha2: 'AX', + }, + { + name: 'Albania', + alpha2: 'AL', + }, + { + name: 'Algeria', + alpha2: 'DZ', + }, + { + name: 'American Samoa', + alpha2: 'AS', + }, + { + name: 'Andorra', + alpha2: 'AD', + }, + { + name: 'Angola', + alpha2: 'AO', + }, + { + name: 'Anguilla', + alpha2: 'AI', + }, + { + name: 'Antarctica', + alpha2: 'AQ', + }, + { + name: 'Antigua and Barbuda', + alpha2: 'AG', + }, + { + name: 'Argentina', + alpha2: 'AR', + }, + { + name: 'Armenia', + alpha2: 'AM', + }, + { + name: 'Aruba', + alpha2: 'AW', + }, + { + name: 'Australia', + alpha2: 'AU', + }, + { + name: 'Austria', + alpha2: 'AT', + }, + { + name: 'Azerbaijan', + alpha2: 'AZ', + }, + { + name: 'Bahamas (the)', + alpha2: 'BS', + }, + { + name: 'Bahrain', + alpha2: 'BH', + }, + { + name: 'Bangladesh', + alpha2: 'BD', + }, + { + name: 'Barbados', + alpha2: 'BB', + }, + { + name: 'Belarus', + alpha2: 'BY', + }, + { + name: 'Belgium', + alpha2: 'BE', + }, + { + name: 'Belize', + alpha2: 'BZ', + }, + { + name: 'Benin', + alpha2: 'BJ', + }, + { + name: 'Bermuda', + alpha2: 'BM', + }, + { + name: 'Bhutan', + alpha2: 'BT', + }, + { + name: 'Bolivia (Plurinational State of)', + alpha2: 'BO', + }, + { + name: 'Bonaire, Sint Eustatius and Saba', + alpha2: 'BQ', + }, + { + name: 'Bosnia and Herzegovina', + alpha2: 'BA', + }, + { + name: 'Botswana', + alpha2: 'BW', + }, + { + name: 'Bouvet Island', + alpha2: 'BV', + }, + { + name: 'Brazil', + alpha2: 'BR', + }, + { + name: 'British Indian Ocean Territory (the)', + alpha2: 'IO', + }, + { + name: 'Brunei Darussalam', + alpha2: 'BN', + }, + { + name: 'Bulgaria', + alpha2: 'BG', + }, + { + name: 'Burkina Faso', + alpha2: 'BF', + }, + { + name: 'Burundi', + alpha2: 'BI', + }, + { + name: 'Cabo Verde', + alpha2: 'CV', + }, + { + name: 'Cambodia', + alpha2: 'KH', + }, + { + name: 'Cameroon', + alpha2: 'CM', + }, + { + name: 'Canada', + alpha2: 'CA', + }, + { + name: 'Cayman Islands (the)', + alpha2: 'KY', + }, + { + name: 'Central African Republic (the)', + alpha2: 'CF', + }, + { + name: 'Chad', + alpha2: 'TD', + }, + { + name: 'Chile', + alpha2: 'CL', + }, + { + name: 'China', + alpha2: 'CN', + }, + { + name: 'Christmas Island', + alpha2: 'CX', + }, + { + name: 'Cocos (Keeling) Islands (the)', + alpha2: 'CC', + }, + { + name: 'Colombia', + alpha2: 'CO', + }, + { + name: 'Comoros (the)', + alpha2: 'KM', + }, + { + name: 'Congo (the Democratic Republic of the)', + alpha2: 'CD', + }, + { + name: 'Congo (the)', + alpha2: 'CG', + }, + { + name: 'Cook Islands (the)', + alpha2: 'CK', + }, + { + name: 'Costa Rica', + alpha2: 'CR', + }, + { + name: 'Côte d\'Ivoire', + alpha2: 'CI', + }, + { + name: 'Croatia', + alpha2: 'HR', + }, + { + name: 'Cuba', + alpha2: 'CU', + }, + { + name: 'Curaçao', + alpha2: 'CW', + }, + { + name: 'Cyprus', + alpha2: 'CY', + }, + { + name: 'Czechia', + alpha2: 'CZ', + }, + { + name: 'Denmark', + alpha2: 'DK', + }, + { + name: 'Djibouti', + alpha2: 'DJ', + }, + { + name: 'Dominica', + alpha2: 'DM', + }, + { + name: 'Dominican Republic (the)', + alpha2: 'DO', + }, + { + name: 'Ecuador', + alpha2: 'EC', + }, + { + name: 'Egypt', + alpha2: 'EG', + }, + { + name: 'El Salvador', + alpha2: 'SV', + }, + { + name: 'Equatorial Guinea', + alpha2: 'GQ', + }, + { + name: 'Eritrea', + alpha2: 'ER', + }, + { + name: 'Estonia', + alpha2: 'EE', + }, + { + name: 'Ethiopia', + alpha2: 'ET', + }, + { + name: 'Falkland Islands (the) [Malvinas]', + alpha2: 'FK', + }, + { + name: 'Faroe Islands (the)', + alpha2: 'FO', + }, + { + name: 'Fiji', + alpha2: 'FJ', + }, + { + name: 'Finland', + alpha2: 'FI', + }, + { + name: 'France', + alpha2: 'FR', + }, + { + name: 'French Guiana', + alpha2: 'GF', + }, + { + name: 'French Polynesia', + alpha2: 'PF', + }, + { + name: 'French Southern Territories (the)', + alpha2: 'TF', + }, + { + name: 'Gabon', + alpha2: 'GA', + }, + { + name: 'Gambia (the)', + alpha2: 'GM', + }, + { + name: 'Georgia', + alpha2: 'GE', + }, + { + name: 'Germany', + alpha2: 'DE', + }, + { + name: 'Ghana', + alpha2: 'GH', + }, + { + name: 'Gibraltar', + alpha2: 'GI', + }, + { + name: 'Greece', + alpha2: 'GR', + }, + { + name: 'Greenland', + alpha2: 'GL', + }, + { + name: 'Grenada', + alpha2: 'GD', + }, + { + name: 'Guadeloupe', + alpha2: 'GP', + }, + { + name: 'Guam', + alpha2: 'GU', + }, + { + name: 'Guatemala', + alpha2: 'GT', + }, + { + name: 'Guernsey', + alpha2: 'GG', + }, + { + name: 'Guinea', + alpha2: 'GN', + }, + { + name: 'Guinea-Bissau', + alpha2: 'GW', + }, + { + name: 'Guyana', + alpha2: 'GY', + }, + { + name: 'Haiti', + alpha2: 'HT', + }, + { + name: 'Heard Island and McDonald Islands', + alpha2: 'HM', + }, + { + name: 'Holy See (the)', + alpha2: 'VA', + }, + { + name: 'Honduras', + alpha2: 'HN', + }, + { + name: 'Hong Kong', + alpha2: 'HK', + }, + { + name: 'Hungary', + alpha2: 'HU', + }, + { + name: 'Iceland', + alpha2: 'IS', + }, + { + name: 'India', + alpha2: 'IN', + }, + { + name: 'Indonesia', + alpha2: 'ID', + }, + { + name: 'Iran (Islamic Republic of)', + alpha2: 'IR', + }, + { + name: 'Iraq', + alpha2: 'IQ', + }, + { + name: 'Ireland', + alpha2: 'IE', + }, + { + name: 'Isle of Man', + alpha2: 'IM', + }, + { + name: 'Israel', + alpha2: 'IL', + }, + { + name: 'Italy', + alpha2: 'IT', + }, + { + name: 'Jamaica', + alpha2: 'JM', + }, + { + name: 'Japan', + alpha2: 'JP', + }, + { + name: 'Jersey', + alpha2: 'JE', + }, + { + name: 'Jordan', + alpha2: 'JO', + }, + { + name: 'Kazakhstan', + alpha2: 'KZ', + }, + { + name: 'Kenya', + alpha2: 'KE', + }, + { + name: 'Kiribati', + alpha2: 'KI', + }, + { + name: 'Korea (the Democratic People\'s Republic of)', + alpha2: 'KP', + }, + { + name: 'Korea (the Republic of)', + alpha2: 'KR', + }, + { + name: 'Kuwait', + alpha2: 'KW', + }, + { + name: 'Kyrgyzstan', + alpha2: 'KG', + }, + { + name: 'Lao People\'s Democratic Republic (the)', + alpha2: 'LA', + }, + { + name: 'Latvia', + alpha2: 'LV', + }, + { + name: 'Lebanon', + alpha2: 'LB', + }, + { + name: 'Lesotho', + alpha2: 'LS', + }, + { + name: 'Liberia', + alpha2: 'LR', + }, + { + name: 'Libya', + alpha2: 'LY', + }, + { + name: 'Liechtenstein', + alpha2: 'LI', + }, + { + name: 'Lithuania', + alpha2: 'LT', + }, + { + name: 'Luxembourg', + alpha2: 'LU', + }, + { + name: 'Macao', + alpha2: 'MO', + }, + { + name: 'Macedonia (the former Yugoslav Republic of)', + alpha2: 'MK', + }, + { + name: 'Madagascar', + alpha2: 'MG', + }, + { + name: 'Malawi', + alpha2: 'MW', + }, + { + name: 'Malaysia', + alpha2: 'MY', + }, + { + name: 'Maldives', + alpha2: 'MV', + }, + { + name: 'Mali', + alpha2: 'ML', + }, + { + name: 'Malta', + alpha2: 'MT', + }, + { + name: 'Marshall Islands (the)', + alpha2: 'MH', + }, + { + name: 'Martinique', + alpha2: 'MQ', + }, + { + name: 'Mauritania', + alpha2: 'MR', + }, + { + name: 'Mauritius', + alpha2: 'MU', + }, + { + name: 'Mayotte', + alpha2: 'YT', + }, + { + name: 'Mexico', + alpha2: 'MX', + }, + { + name: 'Micronesia (Federated States of)', + alpha2: 'FM', + }, + { + name: 'Moldova (the Republic of)', + alpha2: 'MD', + }, + { + name: 'Monaco', + alpha2: 'MC', + }, + { + name: 'Mongolia', + alpha2: 'MN', + }, + { + name: 'Montenegro', + alpha2: 'ME', + }, + { + name: 'Montserrat', + alpha2: 'MS', + }, + { + name: 'Morocco', + alpha2: 'MA', + }, + { + name: 'Mozambique', + alpha2: 'MZ', + }, + { + name: 'Myanmar', + alpha2: 'MM', + }, + { + name: 'Namibia', + alpha2: 'NA', + }, + { + name: 'Nauru', + alpha2: 'NR', + }, + { + name: 'Nepal', + alpha2: 'NP', + }, + { + name: 'Netherlands (the)', + alpha2: 'NL', + }, + { + name: 'New Caledonia', + alpha2: 'NC', + }, + { + name: 'New Zealand', + alpha2: 'NZ', + }, + { + name: 'Nicaragua', + alpha2: 'NI', + }, + { + name: 'Niger (the)', + alpha2: 'NE', + }, + { + name: 'Nigeria', + alpha2: 'NG', + }, + { + name: 'Niue', + alpha2: 'NU', + }, + { + name: 'Norfolk Island', + alpha2: 'NF', + }, + { + name: 'Northern Mariana Islands (the)', + alpha2: 'MP', + }, + { + name: 'Norway', + alpha2: 'NO', + }, + { + name: 'Oman', + alpha2: 'OM', + }, + { + name: 'Pakistan', + alpha2: 'PK', + }, + { + name: 'Palau', + alpha2: 'PW', + }, + { + name: 'Palestine, State of', + alpha2: 'PS', + }, + { + name: 'Panama', + alpha2: 'PA', + }, + { + name: 'Papua New Guinea', + alpha2: 'PG', + }, + { + name: 'Paraguay', + alpha2: 'PY', + }, + { + name: 'Peru', + alpha2: 'PE', + }, + { + name: 'Philippines (the)', + alpha2: 'PH', + }, + { + name: 'Pitcairn', + alpha2: 'PN', + }, + { + name: 'Poland', + alpha2: 'PL', + }, + { + name: 'Portugal', + alpha2: 'PT', + }, + { + name: 'Puerto Rico', + alpha2: 'PR', + }, + { + name: 'Qatar', + alpha2: 'QA', + }, + { + name: 'Réunion', + alpha2: 'RE', + }, + { + name: 'Romania', + alpha2: 'RO', + }, + { + name: 'Russian Federation (the)', + alpha2: 'RU', + }, + { + name: 'Rwanda', + alpha2: 'RW', + }, + { + name: 'Saint Barthélemy', + alpha2: 'BL', + }, + { + name: 'Saint Helena, Ascension and Tristan da Cunha', + alpha2: 'SH', + }, + { + name: 'Saint Kitts and Nevis', + alpha2: 'KN', + }, + { + name: 'Saint Lucia', + alpha2: 'LC', + }, + { + name: 'Saint Martin (French part)', + alpha2: 'MF', + }, + { + name: 'Saint Pierre and Miquelon', + alpha2: 'PM', + }, + { + name: 'Saint Vincent and the Grenadines', + alpha2: 'VC', + }, + { + name: 'Samoa', + alpha2: 'WS', + }, + { + name: 'San Marino', + alpha2: 'SM', + }, + { + name: 'Sao Tome and Principe', + alpha2: 'ST', + }, + { + name: 'Saudi Arabia', + alpha2: 'SA', + }, + { + name: 'Senegal', + alpha2: 'SN', + }, + { + name: 'Serbia', + alpha2: 'RS', + }, + { + name: 'Seychelles', + alpha2: 'SC', + }, + { + name: 'Sierra Leone', + alpha2: 'SL', + }, + { + name: 'Singapore', + alpha2: 'SG', + }, + { + name: 'Sint Maarten (Dutch part)', + alpha2: 'SX', + }, + { + name: 'Slovakia', + alpha2: 'SK', + }, + { + name: 'Slovenia', + alpha2: 'SI', + }, + { + name: 'Solomon Islands', + alpha2: 'SB', + }, + { + name: 'Somalia', + alpha2: 'SO', + }, + { + name: 'South Africa', + alpha2: 'ZA', + }, + { + name: 'South Georgia and the South Sandwich Islands', + alpha2: 'GS', + }, + { + name: 'South Sudan', + alpha2: 'SS', + }, + { + name: 'Spain', + alpha2: 'ES', + }, + { + name: 'Sri Lanka', + alpha2: 'LK', + }, + { + name: 'Sudan (the)', + alpha2: 'SD', + }, + { + name: 'Suriname', + alpha2: 'SR', + }, + { + name: 'Svalbard and Jan Mayen', + alpha2: 'SJ', + }, + { + name: 'Swaziland', + alpha2: 'SZ', + }, + { + name: 'Sweden', + alpha2: 'SE', + }, + { + name: 'Switzerland', + alpha2: 'CH', + }, + { + name: 'Syrian Arab Republic', + alpha2: 'SY', + }, + { + name: 'Taiwan (Province of China)', + alpha2: 'TW', + }, + { + name: 'Tajikistan', + alpha2: 'TJ', + }, + { + name: 'Tanzania, United Republic of', + alpha2: 'TZ', + }, + { + name: 'Thailand', + alpha2: 'TH', + }, + { + name: 'Timor-Leste', + alpha2: 'TL', + }, + { + name: 'Togo', + alpha2: 'TG', + }, + { + name: 'Tokelau', + alpha2: 'TK', + }, + { + name: 'Tonga', + alpha2: 'TO', + }, + { + name: 'Trinidad and Tobago', + alpha2: 'TT', + }, + { + name: 'Tunisia', + alpha2: 'TN', + }, + { + name: 'Turkey', + alpha2: 'TR', + }, + { + name: 'Turkmenistan', + alpha2: 'TM', + }, + { + name: 'Turks and Caicos Islands (the)', + alpha2: 'TC', + }, + { + name: 'Tuvalu', + alpha2: 'TV', + }, + { + name: 'Uganda', + alpha2: 'UG', + }, + { + name: 'Ukraine', + alpha2: 'UA', + }, + { + name: 'United Arab Emirates (the)', + alpha2: 'AE', + }, + { + name: 'United Kingdom of Great Britain and Northern Ireland (the)', + alpha2: 'GB', + }, + { + name: 'United States Minor Outlying Islands (the)', + alpha2: 'UM', + }, + { + name: 'United States of America (the)', + alpha2: 'US', + }, + { + name: 'Uruguay', + alpha2: 'UY', + }, + { + name: 'Uzbekistan', + alpha2: 'UZ', + }, + { + name: 'Vanuatu', + alpha2: 'VU', + }, + { + name: 'Venezuela (Bolivarian Republic of)', + alpha2: 'VE', + }, + { + name: 'Viet Nam', + alpha2: 'VN', + }, + { + name: 'Virgin Islands (British)', + alpha2: 'VG', + }, + { + name: 'Virgin Islands (U.S.)', + alpha2: 'VI', + }, + { + name: 'Wallis and Futuna', + alpha2: 'WF', + }, + { + name: 'Western Sahara', + alpha2: 'EH', + }, + { + name: 'Yemen', + alpha2: 'YE', + }, + { + name: 'Zambia', + alpha2: 'ZM', + }, + { + name: 'Zimbabwe', + alpha2: 'ZW', + }, +]; diff --git a/packages/nodes-base/nodes/Copper/utils/sharedFields.ts b/packages/nodes-base/nodes/Copper/utils/sharedFields.ts new file mode 100644 index 0000000000..2e76bd24ba --- /dev/null +++ b/packages/nodes-base/nodes/Copper/utils/sharedFields.ts @@ -0,0 +1,140 @@ +// for companies, leads, persons +export const addressFixedCollection = { + displayName: 'Address', + name: 'address', + placeholder: 'Add Address Fields', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Address Fields', + name: 'addressFields', + values: [ + { + displayName: 'Street', + name: 'street', + type: 'string', + default: '', + }, + { + displayName: 'City', + name: 'city', + type: 'string', + default: '', + }, + { + displayName: 'State', + name: 'state', + type: 'string', + default: '', + }, + { + displayName: 'Postal Code', + name: 'postal_code', + type: 'string', + default: '', + }, + { + displayName: 'Country', + name: 'country', + type: 'string', + default: '', + description: 'ISO 3166 alpha-2 country code.', + }, + ], + }, + ], +}; + +// for companies, leads, persons +export const phoneNumbersFixedCollection = { + displayName: 'Phone Numbers', + name: 'phone_numbers', + placeholder: 'Add Phone Number', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + displayName: 'Phone Fields', + name: 'phoneFields', + values: [ + { + displayName: 'Number', + name: 'number', + type: 'string', + default: '', + }, + { + displayName: 'Category', + name: 'category', + type: 'string', + default: '', + }, + ], + }, + ], +}; + +// for persons, multiple emails +export const emailsFixedCollection = { + displayName: 'Emails', + name: 'emails', + placeholder: 'Add Email', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + displayName: 'Email Fields', + name: 'emailFields', + values: [ + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + }, + { + displayName: 'Category', + name: 'category', + type: 'string', + default: '', + }, + ], + }, + ], +}; + +// for leads, single email +export const emailFixedCollection = { + displayName: 'Email', + name: 'email', + placeholder: 'Add Email', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Email Fields', + name: 'emailFields', + values: [ + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + }, + { + displayName: 'Category', + name: 'category', + type: 'string', + default: '', + }, + ], + }, + ], +}; diff --git a/packages/nodes-base/nodes/Copper/utils/types.d.ts b/packages/nodes-base/nodes/Copper/utils/types.d.ts new file mode 100644 index 0000000000..0c71e916cd --- /dev/null +++ b/packages/nodes-base/nodes/Copper/utils/types.d.ts @@ -0,0 +1,23 @@ +export type EmailFixedCollection = { + email?: { + emailFields: Array<{ email: string, category: string }> + } +}; + +export type EmailsFixedCollection = { + emails?: { + emailFields: Array<{ email: string, category: string }> + } +}; + +export type PhoneNumbersFixedCollection = { + phone_numbers?: { + phoneFields: object, + } +}; + +export type AddressFixedCollection = { + address?: { + addressFields: object + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 556d7cfc1b..d3d39335f6 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -315,6 +315,7 @@ "dist/nodes/Contentful/Contentful.node.js", "dist/nodes/ConvertKit/ConvertKit.node.js", "dist/nodes/ConvertKit/ConvertKitTrigger.node.js", + "dist/nodes/Copper/Copper.node.js", "dist/nodes/Copper/CopperTrigger.node.js", "dist/nodes/Cortex/Cortex.node.js", "dist/nodes/CrateDb/CrateDb.node.js",