Add Freshworks node (#2017)

*  Create Freshworks node

*  Implement all getAll operations

*  Add tz to appointment:create and update

*  Fix repetition in email in contact:create

*  Add tz to salesActivity:create and update

*  Add tz to task:create and update

* 🔥 Remove required from due date

*  Add all-day setting to appointment

*  Add filters to all operations

*  Improvements

*  Minor improvements

*  Additional parameter display name changes

Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Iván Ovejero 2021-07-30 16:12:30 +02:00 committed by GitHub
parent b039de7226
commit a661dece4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 5004 additions and 0 deletions

View file

@ -0,0 +1,27 @@
import {
ICredentialType,
INodeProperties,
} from 'n8n-workflow';
export class FreshworksCrmApi implements ICredentialType {
name = 'freshworksCrmApi';
displayName = 'Freshworks CRM API';
documentationUrl = 'freshdesk';
properties: INodeProperties[] = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string',
default: '',
placeholder: 'BDsTn15vHezBlt_XGp3Tig',
},
{
displayName: 'Domain',
name: 'domain',
type: 'string',
default: '',
placeholder: 'n8n-org',
description: 'Domain in the Freshworks CRM org URL. For example, in <code>https://n8n-org.myfreshworks.com</code>, the domain is <code>n8n-org</code>.',
},
];
}

View file

@ -0,0 +1,996 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
adjustAccounts,
adjustAttendees,
freshworksCrmApiRequest,
getAllItemsViewId,
handleListing,
loadResource,
throwOnEmptyFilter,
throwOnEmptyUpdate,
} from './GenericFunctions';
import {
accountFields,
accountOperations,
appointmentFields,
appointmentOperations,
contactFields,
contactOperations,
dealFields,
dealOperations,
noteFields,
noteOperations,
salesActivityFields,
salesActivityOperations,
taskFields,
taskOperations,
} from './descriptions';
import {
FreshworksConfigResponse,
LoadedCurrency,
LoadedUser,
LoadOption,
} from './types';
import {
tz,
} from 'moment-timezone';
export class FreshworksCrm implements INodeType {
description: INodeTypeDescription = {
displayName: 'Freshworks CRM',
name: 'freshworksCrm',
icon: 'file:freshworksCrm.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the Freshworks CRM API',
defaults: {
name: 'Freshworks CRM',
color: '#ffa800',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'freshworksCrmApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Account',
value: 'account',
},
{
name: 'Appointment',
value: 'appointment',
},
{
name: 'Contact',
value: 'contact',
},
{
name: 'Deal',
value: 'deal',
},
{
name: 'Note',
value: 'note',
},
{
name: 'Sales Activity',
value: 'salesActivity',
},
{
name: 'Task',
value: 'task',
},
],
default: 'account',
},
...accountOperations,
...accountFields,
...appointmentOperations,
...appointmentFields,
...contactOperations,
...contactFields,
...dealOperations,
...dealFields,
...noteOperations,
...noteFields,
...salesActivityOperations,
...salesActivityFields,
...taskOperations,
...taskFields,
],
};
methods = {
loadOptions: {
async getAccounts(this: ILoadOptionsFunctions) {
const viewId = await getAllItemsViewId.call(this, { fromLoadOptions: true });
const responseData = await handleListing.call(this, 'GET', `/sales_accounts/view/${viewId}`);
return responseData.map(({ name, id }) => ({ name, value: id })) as LoadOption[];
},
async getAccountViews(this: ILoadOptionsFunctions) {
const responseData = await handleListing.call(this, 'GET', '/sales_accounts/filters');
return responseData.map(({ name, id }) => ({ name, value: id })) as LoadOption[];
},
async getBusinessTypes(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'business_types');
},
async getCampaigns(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'campaigns');
},
async getContactStatuses(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'contact_statuses');
},
async getContactViews(this: ILoadOptionsFunctions) {
const responseData = await handleListing.call(this, 'GET', '/contacts/filters');
return responseData.map(({ name, id }) => ({ name, value: id })) as LoadOption[];
},
async getCurrencies(this: ILoadOptionsFunctions) {
const response = await freshworksCrmApiRequest.call(
this, 'GET', '/selector/currencies',
) as FreshworksConfigResponse<LoadedCurrency>;
const key = Object.keys(response)[0];
return response[key].map(({ currency_code, id }) => ({ name: currency_code, value: id }));
},
async getDealPaymentStatuses(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_payment_statuses');
},
async getDealPipelines(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_pipelines');
},
async getDealProducts(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_products');
},
async getDealReasons(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_reasons');
},
async getDealStages(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_stages');
},
async getDealTypes(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'deal_types');
},
async getDealViews(this: ILoadOptionsFunctions) {
const responseData = await handleListing.call(this, 'GET', '/deals/filters');
return responseData.map(({ name, id }) => ({ name, value: id })) as LoadOption[];
},
async getIndustryTypes(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'industry_types');
},
async getLifecycleStages(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'lifecycle_stages');
},
async getOutcomes(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'sales_activity_outcomes');
},
async getSalesActivityTypes(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'sales_activity_types');
},
async getTerritories(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'territories');
},
async getUsers(this: ILoadOptionsFunctions) { // for attendees, owners, and creators
const response = await freshworksCrmApiRequest.call(
this, 'GET', `/selector/owners`,
) as FreshworksConfigResponse<LoadedUser>;
const key = Object.keys(response)[0];
return response[key].map(
({ display_name, id }) => ({ name: display_name, value: id }),
);
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
const defaultTimezone = this.getTimezone();
let responseData;
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'account') {
// **********************************************************************
// account
// **********************************************************************
// https://developers.freshworks.com/crm/api/#accounts
if (operation === 'create') {
// ----------------------------------------
// account: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_account
const body = {
name: this.getNodeParameter('name', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, additionalFields);
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/sales_accounts', body);
responseData = responseData.sales_account;
} else if (operation === 'delete') {
// ----------------------------------------
// account: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_account
const accountId = this.getNodeParameter('accountId', i);
const endpoint = `/sales_accounts/${accountId}`;
await freshworksCrmApiRequest.call(this, 'DELETE', endpoint);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// account: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_account
const accountId = this.getNodeParameter('accountId', i);
const endpoint = `/sales_accounts/${accountId}`;
responseData = await freshworksCrmApiRequest.call(this, 'GET', endpoint);
responseData = responseData.sales_account;
} else if (operation === 'getAll') {
// ----------------------------------------
// account: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_accounts
const view = this.getNodeParameter('view', i) as string;
responseData = await handleListing.call(this, 'GET', `/sales_accounts/view/${view}`);
} else if (operation === 'update') {
// ----------------------------------------
// account: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_account
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (Object.keys(updateFields).length) {
Object.assign(body, updateFields);
} else {
throwOnEmptyUpdate.call(this, resource);
}
const accountId = this.getNodeParameter('accountId', i);
const endpoint = `/sales_accounts/${accountId}`;
responseData = await freshworksCrmApiRequest.call(this, 'PUT', endpoint, body);
responseData = responseData.sales_account;
}
} else if (resource === 'appointment') {
// **********************************************************************
// appointment
// **********************************************************************
// https://developers.freshworks.com/crm/api/#appointments
if (operation === 'create') {
// ----------------------------------------
// appointment: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_appointment
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & {
time_zone: string;
is_allday: boolean;
};
const startDate = this.getNodeParameter('fromDate', i) as string;
const endDate = this.getNodeParameter('endDate', i) as string;
const attendees = this.getNodeParameter('attendees.attendee', i, []) as [{ type: string, contactId: string, userId: string }];
const timezone = additionalFields.time_zone ?? defaultTimezone;
let allDay = false;
if (additionalFields.is_allday) {
allDay = additionalFields.is_allday as boolean;
}
const start = tz(startDate, timezone);
const end = tz(endDate, timezone);
const body = {
title: this.getNodeParameter('title', i),
from_date: start.format(),
end_date: (allDay) ? start.format() : end.format(),
} as IDataObject;
Object.assign(body, additionalFields);
if (attendees.length) {
body['appointment_attendees_attributes'] = adjustAttendees(attendees);
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/appointments', body);
responseData = responseData.appointment;
} else if (operation === 'delete') {
// ----------------------------------------
// appointment: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_appointment
const appointmentId = this.getNodeParameter('appointmentId', i);
const endpoint = `/appointments/${appointmentId}`;
await freshworksCrmApiRequest.call(this, 'DELETE', endpoint);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// appointment: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_a_appointment
const appointmentId = this.getNodeParameter('appointmentId', i);
const endpoint = `/appointments/${appointmentId}`;
responseData = await freshworksCrmApiRequest.call(this, 'GET', endpoint);
responseData = responseData.appointment;
} else if (operation === 'getAll') {
// ----------------------------------------
// appointment: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_appointments
const { filter, include } = this.getNodeParameter('filters', i) as {
filter: string;
include: string[];
};
const qs: IDataObject = {};
if (filter) {
qs.filter = filter;
}
if (include) {
qs.include = include;
}
responseData = await handleListing.call(this, 'GET', '/appointments', {}, qs);
} else if (operation === 'update') {
// ----------------------------------------
// appointment: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_appointment
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject & {
from_date: string;
end_date: string;
time_zone: string;
};
const attendees = this.getNodeParameter('updateFields.attendees.attendee', i, []) as [{ type: string, contactId: string, userId: string }];
if (!Object.keys(updateFields).length) {
throwOnEmptyUpdate.call(this, resource);
}
const body = {} as IDataObject;
const { from_date, end_date, ...rest } = updateFields;
const timezone = rest.time_zone ?? defaultTimezone;
if (from_date) {
body.from_date = tz(from_date, timezone).format();
}
if (end_date) {
body.end_date = tz(end_date, timezone).format();
}
Object.assign(body, rest);
if (attendees.length) {
body['appointment_attendees_attributes'] = adjustAttendees(attendees);
delete body.attendees;
}
const appointmentId = this.getNodeParameter('appointmentId', i);
const endpoint = `/appointments/${appointmentId}`;
responseData = await freshworksCrmApiRequest.call(this, 'PUT', endpoint, body);
responseData = responseData.appointment;
}
} else if (resource === 'contact') {
// **********************************************************************
// contact
// **********************************************************************
// https://developers.freshworks.com/crm/api/#contacts
if (operation === 'create') {
// ----------------------------------------
// contact: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_contact
const body = {
first_name: this.getNodeParameter('firstName', i),
last_name: this.getNodeParameter('lastName', i),
emails: this.getNodeParameter('emails', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, adjustAccounts(additionalFields));
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/contacts', body);
responseData = responseData.contact;
} else if (operation === 'delete') {
// ----------------------------------------
// contact: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_contact
const contactId = this.getNodeParameter('contactId', i);
const endpoint = `/contacts/${contactId}`;
await freshworksCrmApiRequest.call(this, 'DELETE', endpoint);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// contact: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_a_contact
const contactId = this.getNodeParameter('contactId', i);
const endpoint = `/contacts/${contactId}`;
responseData = await freshworksCrmApiRequest.call(this, 'GET', endpoint);
responseData = responseData.contact;
} else if (operation === 'getAll') {
// ----------------------------------------
// contact: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_contacts
const view = this.getNodeParameter('view', i) as string;
responseData = await handleListing.call(this, 'GET', `/contacts/view/${view}`);
} else if (operation === 'update') {
// ----------------------------------------
// contact: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_contact
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (Object.keys(updateFields).length) {
Object.assign(body, adjustAccounts(updateFields));
} else {
throwOnEmptyUpdate.call(this, resource);
}
const contactId = this.getNodeParameter('contactId', i);
const endpoint = `/contacts/${contactId}`;
responseData = await freshworksCrmApiRequest.call(this, 'PUT', endpoint, body);
responseData = responseData.contact;
}
} else if (resource === 'deal') {
// **********************************************************************
// deal
// **********************************************************************
// https://developers.freshworks.com/crm/api/#deals
if (operation === 'create') {
// ----------------------------------------
// deal: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_deal
const body = {
name: this.getNodeParameter('name', i),
amount: this.getNodeParameter('amount', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, adjustAccounts(additionalFields));
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/deals', body);
responseData = responseData.deal;
} else if (operation === 'delete') {
// ----------------------------------------
// deal: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_deal
const dealId = this.getNodeParameter('dealId', i);
await freshworksCrmApiRequest.call(this, 'DELETE', `/deals/${dealId}`);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// deal: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_a_deal
const dealId = this.getNodeParameter('dealId', i);
responseData = await freshworksCrmApiRequest.call(this, 'GET', `/deals/${dealId}`);
responseData = responseData.deal;
} else if (operation === 'getAll') {
// ----------------------------------------
// deal: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_deals
const view = this.getNodeParameter('view', i) as string;
responseData = await handleListing.call(this, 'GET', `/deals/view/${view}`);
} else if (operation === 'update') {
// ----------------------------------------
// deal: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_deal
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (Object.keys(updateFields).length) {
Object.assign(body, adjustAccounts(updateFields));
} else {
throwOnEmptyUpdate.call(this, resource);
}
const dealId = this.getNodeParameter('dealId', i);
responseData = await freshworksCrmApiRequest.call(this, 'PUT', `/deals/${dealId}`, body);
responseData = responseData.deal;
}
} else if (resource === 'note') {
// **********************************************************************
// note
// **********************************************************************
// https://developers.freshworks.com/crm/api/#notes
if (operation === 'create') {
// ----------------------------------------
// note: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_note
const body = {
description: this.getNodeParameter('description', i),
targetable_id: this.getNodeParameter('targetable_id', i),
targetable_type: this.getNodeParameter('targetableType', i),
} as IDataObject;
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/notes', body);
responseData = responseData.note;
} else if (operation === 'delete') {
// ----------------------------------------
// note: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_note
const noteId = this.getNodeParameter('noteId', i);
await freshworksCrmApiRequest.call(this, 'DELETE', `/notes/${noteId}`);
responseData = { success: true };
} else if (operation === 'update') {
// ----------------------------------------
// note: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_note
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (Object.keys(updateFields).length) {
Object.assign(body, updateFields);
} else {
throwOnEmptyUpdate.call(this, resource);
}
const noteId = this.getNodeParameter('noteId', i);
responseData = await freshworksCrmApiRequest.call(this, 'PUT', `/notes/${noteId}`, body);
responseData = responseData.note;
}
} else if (resource === 'salesActivity') {
// **********************************************************************
// salesActivity
// **********************************************************************
// https://developers.freshworks.com/crm/api/#sales-activities
if (operation === 'create') {
// ----------------------------------------
// salesActivity: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_sales_activity
const startDate = this.getNodeParameter('from_date', i) as string;
const endDate = this.getNodeParameter('end_date', i) as string;
const body = {
sales_activity_type_id: this.getNodeParameter('sales_activity_type_id', i),
title: this.getNodeParameter('title', i),
owner_id: this.getNodeParameter('ownerId', i),
start_date: tz(startDate, defaultTimezone).format(),
end_date: tz(endDate, defaultTimezone).format(),
targetable_type: this.getNodeParameter('targetableType', i),
targetable_id: this.getNodeParameter('targetable_id', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, additionalFields);
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/sales_activities', { sales_activity: body });
responseData = responseData.sales_activity;
} else if (operation === 'delete') {
// ----------------------------------------
// salesActivity: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_sales_activity
const salesActivityId = this.getNodeParameter('salesActivityId', i);
const endpoint = `/sales_activities/${salesActivityId}`;
await freshworksCrmApiRequest.call(this, 'DELETE', endpoint);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// salesActivity: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_a_sales_activity
const salesActivityId = this.getNodeParameter('salesActivityId', i);
const endpoint = `/sales_activities/${salesActivityId}`;
responseData = await freshworksCrmApiRequest.call(this, 'GET', endpoint);
responseData = responseData.sales_activity;
} else if (operation === 'getAll') {
// ----------------------------------------
// salesActivity: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_sales_activities
responseData = await handleListing.call(this, 'GET', '/sales_activities');
} else if (operation === 'update') {
// ----------------------------------------
// salesActivity: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_sales_activity
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject & {
from_date: string;
end_date: string;
time_zone: string;
};
if (!Object.keys(updateFields).length) {
throwOnEmptyUpdate.call(this, resource);
}
const body = {} as IDataObject;
const { from_date, end_date, ...rest } = updateFields;
if (from_date) {
body.from_date = tz(from_date, defaultTimezone).format();
}
if (end_date) {
body.end_date = tz(end_date, defaultTimezone).format();
}
if (Object.keys(rest).length) {
Object.assign(body, rest);
}
const salesActivityId = this.getNodeParameter('salesActivityId', i);
const endpoint = `/sales_activities/${salesActivityId}`;
responseData = await freshworksCrmApiRequest.call(this, 'PUT', endpoint, body);
responseData = responseData.sales_activity;
}
} else if (resource === 'task') {
// **********************************************************************
// task
// **********************************************************************
// https://developers.freshworks.com/crm/api/#tasks
if (operation === 'create') {
// ----------------------------------------
// task: create
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#create_task
const dueDate = this.getNodeParameter('dueDate', i);
const body = {
title: this.getNodeParameter('title', i),
owner_id: this.getNodeParameter('ownerId', i),
due_date: tz(dueDate, defaultTimezone).format(),
targetable_type: this.getNodeParameter('targetableType', i),
targetable_id: this.getNodeParameter('targetable_id', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, additionalFields);
}
responseData = await freshworksCrmApiRequest.call(this, 'POST', '/tasks', body);
responseData = responseData.task;
} else if (operation === 'delete') {
// ----------------------------------------
// task: delete
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#delete_a_task
const taskId = this.getNodeParameter('taskId', i);
await freshworksCrmApiRequest.call(this, 'DELETE', `/tasks/${taskId}`);
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------------
// task: get
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#view_a_task
const taskId = this.getNodeParameter('taskId', i);
responseData = await freshworksCrmApiRequest.call(this, 'GET', `/tasks/${taskId}`);
responseData = responseData.task;
} else if (operation === 'getAll') {
// ----------------------------------------
// task: getAll
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#list_all_tasks
const { filter, include } = this.getNodeParameter('filters', i) as {
filter: string;
include: string;
};
const qs: IDataObject = {
filter: 'open',
};
if (filter) {
qs.filter = filter;
}
if (include) {
qs.include = include;
}
responseData = await handleListing.call(this, 'GET', '/tasks', {}, qs);
} else if (operation === 'update') {
// ----------------------------------------
// task: update
// ----------------------------------------
// https://developers.freshworks.com/crm/api/#update_a_task
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (!Object.keys(updateFields).length) {
throwOnEmptyUpdate.call(this, resource);
}
const { dueDate, ...rest } = updateFields;
if (dueDate) {
body.due_date = tz(dueDate, defaultTimezone).format();
}
if (Object.keys(rest).length) {
Object.assign(body, rest);
}
const taskId = this.getNodeParameter('taskId', i);
responseData = await freshworksCrmApiRequest.call(this, 'PUT', `/tasks/${taskId}`, body);
responseData = responseData.task;
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ json: { error: error.message } });
continue;
}
throw error;
}
Array.isArray(responseData)
? returnData.push(...responseData)
: returnData.push(responseData);
}
return [this.helpers.returnJsonArray(returnData)];
}
}

View file

@ -0,0 +1,215 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import {
OptionsWithUri,
} from 'request';
import {
FreshworksConfigResponse,
FreshworksCrmApiCredentials,
SalesAccounts,
ViewsResponse,
} from './types';
import {
omit,
} from 'lodash';
export async function freshworksCrmApiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: IDataObject = {},
qs: IDataObject = {},
) {
const { apiKey, domain } = this.getCredentials('freshworksCrmApi') as FreshworksCrmApiCredentials;
const options: OptionsWithUri = {
headers: {
Authorization: `Token token=${apiKey}`,
},
method,
body,
qs,
uri: `https://${domain}.myfreshworks.com/crm/sales/api${endpoint}`,
json: true,
};
if (!Object.keys(body).length) {
delete options.body;
}
if (!Object.keys(qs).length) {
delete options.qs;
}
try {
return await this.helpers.request!(options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
export async function getAllItemsViewId(
this: IExecuteFunctions | ILoadOptionsFunctions,
{ fromLoadOptions } = { fromLoadOptions: false },
) {
let resource = this.getNodeParameter('resource', 0) as string;
let keyword = 'All';
if (resource === 'account' || fromLoadOptions) {
resource = 'sales_account'; // adjust resource to endpoint
}
if (resource === 'deal') {
keyword = 'My Deals'; // no 'All Deals' available
}
const response = await freshworksCrmApiRequest.call(this, 'GET', `/${resource}s/filters`) as ViewsResponse;
const view = response.filters.find(v => v.name.includes(keyword));
if (!view) {
throw new NodeOperationError(this.getNode(), 'Failed to get all items view');
}
return view.id.toString();
}
export async function freshworksCrmApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: IDataObject = {},
qs: IDataObject = {},
) {
const returnData: IDataObject[] = [];
let response: any; // tslint:disable-line: no-any
qs.page = 1;
do {
response = await freshworksCrmApiRequest.call(this, method, endpoint, body, qs);
const key = Object.keys(response)[0];
returnData.push(...response[key]);
qs.page++;
} while (
response.meta.total_pages && qs.page <= response.meta.total_pages
);
return returnData;
}
export async function handleListing(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: IDataObject = {},
qs: IDataObject = {},
) {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (returnAll) {
return await freshworksCrmApiRequestAllItems.call(this, method, endpoint, body, qs);
}
const responseData = await freshworksCrmApiRequestAllItems.call(this, method, endpoint, body, qs);
const limit = this.getNodeParameter('limit', 0) as number;
if (limit) return responseData.slice(0, limit);
return responseData;
}
/**
* Load resources for options, except users.
*
* See: https://developers.freshworks.com/crm/api/#admin_configuration
*/
export async function loadResource(
this: ILoadOptionsFunctions,
resource: string,
) {
const response = await freshworksCrmApiRequest.call(
this, 'GET', `/selector/${resource}`,
) as FreshworksConfigResponse<LoadedResource>;
const key = Object.keys(response)[0];
return response[key].map(({ name, id }) => ({ name, value: id }));
}
export function adjustAttendees(attendees: [{ type: string, contactId: string, userId: string }]) {
return attendees.map((attendee) => {
if (attendee.type === 'contact') {
return {
attendee_type: 'Contact',
attendee_id: attendee.contactId.toString(),
};
} else if (attendee.type === 'user') {
return {
attendee_type: 'FdMultitenant::User',
attendee_id: attendee.userId.toString(),
};
}
});
}
// /**
// * Adjust attendee data from n8n UI to the format expected by Freshworks CRM API.
// */
// export function adjustAttendees(additionalFields: IDataObject & Attendees) {
// if (!additionalFields?.appointment_attendees_attributes) return additionalFields;
// return {
// ...omit(additionalFields, ['appointment_attendees_attributes']),
// appointment_attendees_attributes: additionalFields.appointment_attendees_attributes.map(attendeeId => {
// return { type: 'user', id: attendeeId };
// }),
// };
// }
/**
* Adjust account data from n8n UI to the format expected by Freshworks CRM API.
*/
export function adjustAccounts(additionalFields: IDataObject & SalesAccounts) {
if (!additionalFields?.sales_accounts) return additionalFields;
const adjusted = additionalFields.sales_accounts.map(accountId => {
return { id: accountId, is_primary: false };
});
adjusted[0].is_primary = true;
return {
...omit(additionalFields, ['sales_accounts']),
sales_accounts: adjusted,
};
}
export function throwOnEmptyUpdate(
this: IExecuteFunctions,
resource: string,
) {
throw new NodeOperationError(
this.getNode(),
`Please enter at least one field to update for the ${resource}.`,
);
}
export function throwOnEmptyFilter(
this: IExecuteFunctions,
) {
throw new NodeOperationError(
this.getNode(),
`Please select at least one filter.`,
);
}

View file

@ -0,0 +1,507 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const accountOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'account',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create an account',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete an account',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve an account',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all accounts',
},
{
name: 'Update',
value: 'update',
description: 'Update an account',
},
],
default: 'create',
},
] as INodeProperties[];
export const accountFields = [
// ----------------------------------------
// account: create
// ----------------------------------------
{
displayName: 'Name',
name: 'name',
description: 'Name of the account',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'string',
default: '',
description: 'Address of the account',
},
{
displayName: 'Annual Revenue',
name: 'annual_revenue',
type: 'number',
default: 0,
description: 'Annual revenue of the account',
},
{
displayName: 'Business Type ID',
name: 'business_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getBusinessTypes',
},
description: 'ID of the business that the account belongs to',
},
{
displayName: 'City',
name: 'city',
type: 'string',
default: '',
description: 'City that the account belongs to',
},
{
displayName: 'Country',
name: 'country',
type: 'string',
default: '',
description: 'Country that the account belongs to',
},
{
displayName: 'Facebook',
name: 'facebook',
type: 'string',
default: '',
description: 'Facebook username of the account',
},
{
displayName: 'Industry Type ID',
name: 'industry_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getIndustryTypes',
},
description: 'ID of the industry that the account belongs to',
},
{
displayName: 'LinkedIn',
name: 'linkedin',
type: 'string',
default: '',
description: 'LinkedIn account of the account',
},
{
displayName: 'Number of Employees',
name: 'number_of_employees',
type: 'number',
default: 0,
description: 'Number of employees in the account',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the account is assigned',
},
{
displayName: 'Parent Sales Account ID',
name: 'parent_sales_account_id',
type: 'string',
default: '',
description: 'Parent account ID of the account',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Phone number of the account',
},
{
displayName: 'State',
name: 'state',
type: 'string',
default: '',
description: 'State that the account belongs to',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the account belongs to',
},
{
displayName: 'Twitter',
name: 'twitter',
type: 'string',
default: '',
description: 'Twitter username of the account',
},
{
displayName: 'Website',
name: 'website',
type: 'string',
default: '',
description: 'Website of the account',
},
{
displayName: 'Zipcode',
name: 'zipcode',
type: 'string',
default: '',
description: 'Zipcode of the region that the account belongs to',
},
],
},
// ----------------------------------------
// account: delete
// ----------------------------------------
{
displayName: 'Account ID',
name: 'accountId',
description: 'ID of the account to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// account: get
// ----------------------------------------
{
displayName: 'Account ID',
name: 'accountId',
description: 'ID of the account to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// account: getAll
// ----------------------------------------
{
displayName: 'View',
name: 'view',
type: 'options',
required: true,
typeOptions: {
loadOptionsMethod: 'getAccountViews',
},
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'getAll',
],
},
},
default: '',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
// ----------------------------------------
// account: update
// ----------------------------------------
{
displayName: 'Account ID',
name: 'accountId',
description: 'ID of the account to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'account',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'string',
default: '',
description: 'Address of the account',
},
{
displayName: 'Annual Revenue',
name: 'annual_revenue',
type: 'number',
default: 0,
description: 'Annual revenue of the account',
},
{
displayName: 'Business Type ID',
name: 'business_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getBusinessTypes',
},
description: 'ID of the business that the account belongs to',
},
{
displayName: 'City',
name: 'city',
type: 'string',
default: '',
description: 'City that the account belongs to',
},
{
displayName: 'Country',
name: 'country',
type: 'string',
default: '',
description: 'Country that the account belongs to',
},
{
displayName: 'Facebook',
name: 'facebook',
type: 'string',
default: '',
description: 'Facebook username of the account',
},
{
displayName: 'Industry Type ID',
name: 'industry_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getIndustryTypes',
},
description: 'ID of the industry that the account belongs to',
},
{
displayName: 'LinkedIn',
name: 'linkedin',
type: 'string',
default: '',
description: 'LinkedIn account of the account',
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'Name of the account',
},
{
displayName: 'Number of Employees',
name: 'number_of_employees',
type: 'number',
default: 0,
description: 'Number of employees in the account',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the account is assigned',
},
{
displayName: 'Parent Sales Account ID',
name: 'parent_sales_account_id',
type: 'string',
default: '',
description: 'Parent account ID of the account',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Phone number of the account',
},
{
displayName: 'State',
name: 'state',
type: 'string',
default: '',
description: 'State that the account belongs to',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the account belongs to',
},
{
displayName: 'Twitter',
name: 'twitter',
type: 'string',
default: '',
description: 'Twitter username of the account',
},
{
displayName: 'Website',
name: 'website',
type: 'string',
default: '',
description: 'Website of the account',
},
{
displayName: 'Zipcode',
name: 'zipcode',
type: 'string',
default: '',
description: 'Zipcode of the region that the account belongs to',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,636 @@
import {
tz,
} from 'moment-timezone';
import {
INodeProperties,
} from 'n8n-workflow';
export const appointmentOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'appointment',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create an appointment',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete an appointment',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve an appointment',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all appointments',
},
{
name: 'Update',
value: 'update',
description: 'Update an appointment',
},
],
default: 'create',
},
] as INodeProperties[];
export const appointmentFields = [
// ----------------------------------------
// appointment: create
// ----------------------------------------
{
displayName: 'Title',
name: 'title',
description: 'Title of the appointment',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Start Date',
name: 'fromDate',
description: 'Timestamp that denotes the start of appointment. Start date if this is an all-day appointment.',
type: 'dateTime',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'create',
],
},
},
},
{
displayName: 'End Date',
name: 'endDate',
description: 'Timestamp that denotes the end of appointment. End date if this is an all-day appointment.',
type: 'dateTime',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Attendees',
name: 'attendees',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'create',
],
},
},
placeholder: 'Add Attendee',
default: {},
options: [
{
name: 'attendee',
displayName: 'Attendee',
values: [
{
displayName: 'Type',
name: 'type',
type: 'options',
options: [
{
name: 'Contact',
value: 'contact',
},
{
name: 'User',
value: 'user',
},
],
default: 'contact',
},
{
displayName: 'User ID',
name: 'userId',
type: 'options',
displayOptions: {
show: {
type: [
'user',
],
},
},
typeOptions: {
loadOptionsMethod: 'getUsers',
},
default: '',
},
{
displayName: 'Contact ID',
name: 'contactId',
displayOptions: {
show: {
type: [
'contact',
],
},
},
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Creator ID',
name: 'creater_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the appointment',
},
{
displayName: 'Is All-Day',
name: 'is_allday',
type: 'boolean',
default: false,
description: 'Whether it is an all-day appointment or not',
},
{
displayName: 'Latitude',
name: 'latitude',
type: 'string',
default: '',
description: 'Latitude of the location when you check in for an appointment',
},
{
displayName: 'Location',
name: 'location',
type: 'string',
default: '',
description: 'Location of the appointment',
},
{
displayName: 'Longitude',
name: 'longitude',
type: 'string',
default: '',
description: 'Longitude of the location when you check in for an appointment',
},
{
displayName: 'Outcome ID',
name: 'outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of outcome of Appointment sales activity type',
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
type: 'string',
default: '',
description: 'ID of contact/account against whom appointment is created',
},
{
displayName: 'Targetable Type',
name: 'targetable_type',
type: 'options',
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'SalesAccount',
value: 'SalesAccount',
},
],
},
{
displayName: 'Time Zone',
name: 'time_zone',
type: 'options',
default: '',
description: 'Timezone that the appointment is scheduled in',
options: tz.names().map(tz => ({ name: tz, value: tz })),
},
],
},
// ----------------------------------------
// appointment: delete
// ----------------------------------------
{
displayName: 'Appointment ID',
name: 'appointmentId',
description: 'ID of the appointment to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// appointment: get
// ----------------------------------------
{
displayName: 'Appointment ID',
name: 'appointmentId',
description: 'ID of the appointment to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// appointment: getAll
// ----------------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
default: '',
placeholder: 'Add Filter',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'getAll',
],
},
},
options: [
{
displayName: 'Include',
name: 'include',
type: 'options',
default: 'creater',
options: [
{
name: 'Appointment Attendees',
value: 'appointment_attendees',
},
{
name: 'Creator',
value: 'creater',
},
{
name: 'Targetable',
value: 'targetable',
},
],
},
{
displayName: 'Time',
name: 'filter',
type: 'options',
default: 'upcoming',
options: [
{
name: 'Past',
value: 'past',
},
{
name: 'Upcoming',
value: 'upcoming',
},
],
},
],
},
// ----------------------------------------
// appointment: update
// ----------------------------------------
{
displayName: 'Appointment ID',
name: 'appointmentId',
description: 'ID of the appointment to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'appointment',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Attendees',
name: 'attendees',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
placeholder: 'Add Attendee',
default: {},
options: [
{
name: 'attendee',
displayName: 'Attendee',
values: [
{
displayName: 'Type',
name: 'type',
type: 'options',
options: [
{
name: 'Contact',
value: 'contact',
},
{
name: 'User',
value: 'user',
},
],
default: 'contact',
},
{
displayName: 'User ID',
name: 'userId',
type: 'options',
displayOptions: {
show: {
type: [
'user',
],
},
},
typeOptions: {
loadOptionsMethod: 'getUsers',
},
default: '',
},
{
displayName: 'Contact ID',
name: 'contactId',
displayOptions: {
show: {
type: [
'contact',
],
},
},
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Creator ID',
name: 'creater_id',
type: 'options',
default: [],
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the appointment',
},
{
displayName: 'End Date',
name: 'endDate',
description: 'Timestamp that denotes the end of appointment. End date if this is an all-day appointment.',
type: 'dateTime',
default: '',
},
{
displayName: 'Is All-Day',
name: 'is_allday',
type: 'boolean',
default: false,
description: 'Whether it is an all-day appointment or not',
},
{
displayName: 'Latitude',
name: 'latitude',
type: 'string',
default: '',
description: 'Latitude of the location when you check in for an appointment',
},
{
displayName: 'Location',
name: 'location',
type: 'string',
default: '',
description: 'Location of the appointment',
},
{
displayName: 'Longitude',
name: 'longitude',
type: 'string',
default: '',
description: 'Longitude of the location when you check in for an appointment',
},
{
displayName: 'Outcome ID',
name: 'outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of outcome of Appointment sales activity type',
},
{
displayName: 'Start Date',
name: 'fromDate',
description: 'Timestamp that denotes the start of appointment. Start date if this is an all-day appointment.',
type: 'dateTime',
default: '',
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
type: 'string',
default: '',
description: 'ID of contact/account against whom appointment is created',
},
{
displayName: 'Targetable Type',
name: 'targetable_type',
type: 'options',
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'SalesAccount',
value: 'SalesAccount',
},
],
},
{
displayName: 'Time Zone',
name: 'time_zone',
type: 'options',
default: '',
description: 'Timezone that the appointment is scheduled in',
options: tz.names().map(tz => ({ name: tz, value: tz })),
},
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Title of the appointment',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,668 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const contactOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'contact',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a contact',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a contact',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a contact',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all contacts',
},
{
name: 'Update',
value: 'update',
description: 'Update a contact',
},
],
default: 'create',
},
] as INodeProperties[];
export const contactFields = [
// ----------------------------------------
// contact: create
// ----------------------------------------
{
displayName: 'First Name',
name: 'firstName',
description: 'First name of the contact',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Last Name',
name: 'lastName',
description: 'Last name of the contact',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Email Address',
name: 'emails',
type: 'string',
default: '',
description: 'Email addresses of the contact',
required: true,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'string',
default: '',
description: 'Address of the contact',
},
{
displayName: 'Campaign ID',
name: 'campaign_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description: 'ID of the campaign that led your contact to your webapp',
},
{
displayName: 'City',
name: 'city',
type: 'string',
default: '',
description: 'City that the contact belongs to',
},
{
displayName: 'Contact Status ID',
name: 'contact_status_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getContactStatuses',
},
description: 'ID of the contact status that the contact belongs to',
},
{
displayName: 'Country',
name: 'country',
type: 'string',
default: '',
description: 'Country that the contact belongs to',
},
{
displayName: 'External ID',
name: 'external_id',
type: 'string',
default: '',
description: 'External ID of the contact',
},
{
displayName: 'Facebook',
name: 'facebook',
type: 'string',
default: '',
description: 'Facebook username of the contact',
},
{
displayName: 'Job Title',
name: 'job_title',
type: 'string',
default: '',
description: 'Designation of the contact in the account they belong to',
},
{
displayName: 'Keywords',
name: 'keyword',
type: 'string',
default: '',
description: 'Keywords that the contact used to reach your website/web app',
},
{
displayName: 'Lead Source ID',
name: 'lead_source_id',
type: 'string', // not obtainable from API
default: '',
description: 'ID of the source where contact came from',
},
{
displayName: 'Lifecycle Stage ID',
name: 'lifecycle_stage_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getLifecycleStages',
},
description: 'ID of the lifecycle stage that the contact belongs to',
},
{
displayName: 'LinkedIn',
name: 'linkedin',
type: 'string',
default: '',
description: 'LinkedIn account of the contact',
},
{
displayName: 'Medium',
name: 'medium',
type: 'string',
default: '',
description: 'Medium that led your contact to your website/webapp',
},
{
displayName: 'Mobile Number',
name: 'mobile_number',
type: 'string',
default: '',
description: 'Mobile phone number of the contact',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the contact is assigned',
},
{
displayName: 'Sales Accounts',
name: 'sales_accounts',
type: 'multiOptions',
default: [],
typeOptions: {
loadOptionsMethod: 'getAccounts',
},
description: 'Accounts which contact belongs to',
},
{
displayName: 'State',
name: 'state',
type: 'string',
default: '',
description: 'State that the contact belongs to',
},
{
displayName: 'Subscription Status',
name: 'subscription_status',
type: 'string', // not obtainable from API
default: '',
description: 'Status of subscription that the contact is in',
},
{
displayName: 'Subscription Types',
name: 'subscription_types',
type: 'string', // not obtainable from API
default: '',
description: 'Type of subscription that the contact is in',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the contact belongs to',
},
{
displayName: 'Time Zone',
name: 'time_zone',
type: 'string',
default: '',
description: 'Timezone that the contact belongs to',
},
{
displayName: 'Twitter',
name: 'twitter',
type: 'string',
default: '',
description: 'Twitter username of the contact',
},
{
displayName: 'Work Number',
name: 'work_number',
type: 'string',
default: '',
description: 'Work phone number of the contact',
},
{
displayName: 'Zipcode',
name: 'zipcode',
type: 'string',
default: '',
description: 'Zipcode of the region that the contact belongs to',
},
],
},
// ----------------------------------------
// contact: delete
// ----------------------------------------
{
displayName: 'Contact ID',
name: 'contactId',
description: 'ID of the contact to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// contact: get
// ----------------------------------------
{
displayName: 'Contact ID',
name: 'contactId',
description: 'ID of the contact to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// contact: getAll
// ----------------------------------------
{
displayName: 'View',
name: 'view',
type: 'options',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
},
},
typeOptions: {
loadOptionsMethod: 'getContactViews',
},
default: '',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
// ----------------------------------------
// contact: update
// ----------------------------------------
{
displayName: 'Contact ID',
name: 'contactId',
description: 'ID of the contact to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'string',
default: '',
description: 'Address of the contact',
},
{
displayName: 'Campaign ID',
name: 'campaign_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description: 'ID of the campaign that led your contact to your webapp',
},
{
displayName: 'City',
name: 'city',
type: 'string',
default: '',
description: 'City that the contact belongs to',
},
{
displayName: 'Contact Status ID',
name: 'contact_status_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getContactStatuses',
},
description: 'ID of the contact status that the contact belongs to',
},
{
displayName: 'Country',
name: 'country',
type: 'string',
default: '',
description: 'Country that the contact belongs to',
},
{
displayName: 'External ID',
name: 'external_id',
type: 'string',
default: '',
description: 'External ID of the contact',
},
{
displayName: 'Facebook',
name: 'facebook',
type: 'string',
default: '',
description: 'Facebook username of the contact',
},
{
displayName: 'First Name',
name: 'first_name',
type: 'string',
default: '',
description: 'First name of the contact',
},
{
displayName: 'Job Title',
name: 'job_title',
type: 'string',
default: '',
description: 'Designation of the contact in the account they belong to',
},
{
displayName: 'Keywords',
name: 'keyword',
type: 'string',
default: '',
description: 'Keywords that the contact used to reach your website/web app',
},
{
displayName: 'Last Name',
name: 'last_name',
type: 'string',
default: '',
description: 'Last name of the contact',
},
{
displayName: 'Lead Source ID',
name: 'lead_source_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getLeadSources',
},
description: 'ID of the source where contact came from',
},
{
displayName: 'Lifecycle Stage ID',
name: 'lifecycle_stage_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getLifecycleStages',
},
description: 'ID of the lifecycle stage that the contact belongs to',
},
{
displayName: 'LinkedIn',
name: 'linkedin',
type: 'string',
default: '',
description: 'LinkedIn account of the contact',
},
{
displayName: 'Medium',
name: 'medium',
type: 'string',
default: '',
description: 'Medium that led your contact to your website/webapp',
},
{
displayName: 'Mobile Number',
name: 'mobile_number',
type: 'string',
default: '',
description: 'Mobile phone number of the contact',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the contact is assigned',
},
{
displayName: 'Sales Accounts',
name: 'sales_accounts',
type: 'multiOptions',
default: [],
typeOptions: {
loadOptionsMethod: 'getAccounts',
},
description: 'Accounts which contact belongs to',
},
{
displayName: 'State',
name: 'state',
type: 'string',
default: '',
description: 'State that the contact belongs to',
},
{
displayName: 'Subscription Status',
name: 'subscription_status',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getSubscriptionStatuses',
},
description: 'Status of subscription that the contact is in',
},
{
displayName: 'Subscription Types',
name: 'subscription_types',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getSubscriptionTypes',
},
description: 'Type of subscription that the contact is in',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the contact belongs to',
},
{
displayName: 'Time Zone',
name: 'time_zone',
type: 'string',
default: '',
description: 'Timezone that the contact belongs to',
},
{
displayName: 'Twitter',
name: 'twitter',
type: 'string',
default: '',
description: 'Twitter username of the contact',
},
{
displayName: 'Work Number',
name: 'work_number',
type: 'string',
default: '',
description: 'Work phone number of the contact',
},
{
displayName: 'Zipcode',
name: 'zipcode',
type: 'string',
default: '',
description: 'Zipcode of the region that the contact belongs to',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,545 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const dealOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'deal',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a deal',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a deal',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a deal',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all deals',
},
{
name: 'Update',
value: 'update',
description: 'Update a deal',
},
],
default: 'create',
},
] as INodeProperties[];
export const dealFields = [
// ----------------------------------------
// deal: create
// ----------------------------------------
{
displayName: 'Amount',
name: 'amount',
description: 'Value of the deal',
type: 'number',
required: true,
default: 0,
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Name',
name: 'name',
description: 'Name of the deal',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Base Currency Amount',
name: 'base_currency_amount',
type: 'number',
default: 0,
description: 'Value of the deal in base currency',
},
{
displayName: 'Campaign ID',
name: 'campaign_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description: 'ID of the campaign that landed this deal',
},
{
displayName: 'Currency ID',
name: 'currency_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
description: 'ID of the currency that the deal belongs to',
},
{
displayName: 'Deal Payment Status ID',
name: 'deal_payment_status_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealPaymentStatuses',
},
description: 'ID of the mode of payment for the deal',
},
{
displayName: 'Deal Pipeline ID',
name: 'deal_pipeline_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealPipelines',
},
description: 'ID of the deal pipeline that it belongs to',
},
{
displayName: 'Deal Product ID',
name: 'deal_product_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealProducts',
},
description: 'ID of the product that the deal belongs to (in a multi-product company)',
},
{
displayName: 'Deal Reason ID',
name: 'deal_reason_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealReasons',
},
description: 'ID of the reason for losing the deal. Can only be set if the deal is in \'Lost\' stage.',
},
{
displayName: 'Deal Stage ID',
name: 'deal_stage_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealStages',
},
description: 'ID of the deal stage that the deal belongs to',
},
{
displayName: 'Deal Type ID',
name: 'deal_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealTypes',
},
description: 'ID of the deal type that the deal belongs to',
},
{
displayName: 'Lead Source ID',
name: 'lead_source_id',
type: 'string', // not obtainable from API
default: '',
description: 'ID of the source where deal came from',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the deal is assigned',
},
{
displayName: 'Probability',
name: 'probability',
type: 'number',
default: 0,
typeOptions: {
minValue: 0,
maxValue: 100,
},
description: 'Probability of winning the deal as a number between 0 and 100',
},
{
displayName: 'Sales Account ID',
name: 'sales_account_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getAccounts',
},
description: 'ID of the account that the deal belongs to',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the deal belongs to',
},
],
},
// ----------------------------------------
// deal: delete
// ----------------------------------------
{
displayName: 'Deal ID',
name: 'dealId',
description: 'ID of the deal to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// deal: get
// ----------------------------------------
{
displayName: 'Deal ID',
name: 'dealId',
description: 'ID of the deal to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// deal: getAll
// ----------------------------------------
{
displayName: 'View',
name: 'view',
type: 'options',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'getAll',
],
},
},
typeOptions: {
loadOptionsMethod: 'getDealViews',
},
default: '',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
// ----------------------------------------
// deal: update
// ----------------------------------------
{
displayName: 'Deal ID',
name: 'dealId',
description: 'ID of the deal to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'deal',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: 0,
typeOptions: {
minValue: 0,
},
description: 'Value of the deal',
},
{
displayName: 'Base Currency Amount',
name: 'base_currency_amount',
type: 'number',
default: 0,
typeOptions: {
minValue: 0,
},
description: 'Value of the deal in base currency',
},
{
displayName: 'Campaign ID',
name: 'campaign_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description: 'ID of the campaign that landed this deal',
},
{
displayName: 'Currency ID',
name: 'currency_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
description: 'ID of the currency that the deal belongs to',
},
{
displayName: 'Deal Payment Status ID',
name: 'deal_payment_status_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealPaymentStatuses',
},
description: 'ID of the mode of payment for the deal',
},
{
displayName: 'Deal Pipeline ID',
name: 'deal_pipeline_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealPipelines',
},
description: 'ID of the deal pipeline that it belongs to',
},
{
displayName: 'Deal Product ID',
name: 'deal_product_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealProducts',
},
description: 'ID of the product that the deal belongs to (in a multi-product company)',
},
{
displayName: 'Deal Reason ID',
name: 'deal_reason_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealReasons',
},
description: 'ID of the reason for losing the deal. Can only be set if the deal is in \'Lost\' stage.',
},
{
displayName: 'Deal Stage ID',
name: 'deal_stage_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealStages',
},
description: 'ID of the deal stage that the deal belongs to',
},
{
displayName: 'Deal Type ID',
name: 'deal_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getDealTypes',
},
description: 'ID of the deal type that the deal belongs to',
},
{
displayName: 'Lead Source ID',
name: 'lead_source_id',
type: 'string', // not obtainable from API
default: '',
description: 'ID of the source where deal came from',
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'Name of the deal',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the deal is assigned',
},
{
displayName: 'Probability',
name: 'probability',
type: 'number',
default: 0,
typeOptions: {
minValue: 0,
maxValue: 100,
},
description: 'Probability of winning the deal as a number between 0 and 100',
},
{
displayName: 'Sales Account ID',
name: 'sales_account_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getAccounts',
},
description: 'ID of the account that the deal belongs to',
},
{
displayName: 'Territory ID',
name: 'territory_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getTerritories',
},
description: 'ID of the territory that the deal belongs to',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,214 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const noteOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'note',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a note',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a note',
},
{
name: 'Update',
value: 'update',
description: 'Update a note',
},
],
default: 'create',
},
] as INodeProperties[];
export const noteFields = [
// ----------------------------------------
// note: create
// ----------------------------------------
{
displayName: 'Content',
name: 'description',
description: 'Content of the note',
type: 'string',
required: true,
typeOptions: {
rows: 5,
},
default: '',
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Target Type',
name: 'targetableType',
description: 'Type of the entity for which the note is created',
type: 'options',
required: true,
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'Sales Account',
value: 'SalesAccount',
},
],
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Target ID',
name: 'targetable_id',
description: 'ID of the entity for which note is created. The type of entity is selected in "Target Type".',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'create',
],
},
},
},
// ----------------------------------------
// note: delete
// ----------------------------------------
{
displayName: 'Note ID',
name: 'noteId',
description: 'ID of the note to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// note: update
// ----------------------------------------
{
displayName: 'Note ID',
name: 'noteId',
description: 'ID of the note to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'note',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Content',
name: 'description',
type: 'string',
typeOptions: {
rows: 5,
},
default: '',
description: 'Content of the note',
},
{
displayName: 'Target ID',
name: 'targetable_id',
type: 'string',
default: '',
description: 'ID of the entity for which the note is updated',
},
{
displayName: 'Target Type',
name: 'targetable_type',
type: 'options',
default: 'Contact',
description: 'Type of the entity for which the note is updated',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'Sales Account',
value: 'SalesAccount',
},
],
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,508 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const salesActivityOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'salesActivity',
],
},
},
options: [
// {
// name: 'Create',
// value: 'create',
// description: 'Create a sales activity',
// },
// {
// name: 'Delete',
// value: 'delete',
// description: 'Delete a sales activity',
// },
{
name: 'Get',
value: 'get',
description: 'Retrieve a sales activity',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all sales activities',
},
// {
// name: 'Update',
// value: 'update',
// description: 'Update a sales activity',
// },
],
default: 'get',
},
] as INodeProperties[];
export const salesActivityFields = [
// ----------------------------------------
// salesActivity: create
// ----------------------------------------
{
displayName: 'Sales Activity Type ID',
name: 'sales_activity_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getSalesActivityTypes',
},
description: 'ID of a sales activity type for which the sales activity is created',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Title',
name: 'title',
description: 'Title of the sales activity to create',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Owner ID',
name: 'ownerId',
description: 'ID of the user who owns the sales activity',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
required: true,
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Start Date',
name: 'from_date',
description: 'Timestamp that denotes the end of sales activity',
type: 'dateTime',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'End Date',
name: 'end_date',
description: 'Timestamp that denotes the end of sales activity',
type: 'dateTime',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Targetable Type',
name: 'targetableType',
description: 'Type of the entity for which the sales activity is created',
type: 'options',
required: true,
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'Sales Account',
value: 'SalesAccount',
},
],
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
description: 'ID of the entity for which the sales activity is created. The type of entity is selected in "Targetable Type".',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Creator ID',
name: 'creater_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the sales activity',
},
{
displayName: 'Latitude',
name: 'latitude',
type: 'string',
default: '',
description: 'Latitude of the location when you check in on a sales activity',
},
{
displayName: 'Location',
name: 'location',
type: 'string',
default: '',
description: 'Location of the sales activity',
},
{
displayName: 'Longitude',
name: 'longitude',
type: 'string',
default: '',
description: 'Longitude of the location when you check in for a sales activity',
},
{
displayName: 'Notes',
name: 'notes',
type: 'string',
default: '',
description: 'Description about the sales activity',
},
{
displayName: 'Sales Activity Outcome ID',
name: 'sales_activity_outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of a sales activity\'s outcome',
},
],
},
// ----------------------------------------
// salesActivity: delete
// ----------------------------------------
{
displayName: 'Sales Activity ID',
name: 'salesActivityId',
description: 'ID of the salesActivity to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------------
// salesActivity: get
// ----------------------------------------
{
displayName: 'Sales Activity ID',
name: 'salesActivityId',
description: 'ID of the salesActivity to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'get',
],
},
},
},
// ----------------------------------------
// salesActivity: getAll
// ----------------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
// ----------------------------------------
// salesActivity: update
// ----------------------------------------
{
displayName: 'Sales Activity ID',
name: 'salesActivityId',
description: 'ID of the salesActivity to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'salesActivity',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Creator ID',
name: 'creater_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the sales activity',
},
{
displayName: 'Start Date',
name: 'end_date',
description: 'Timestamp that denotes the start of the sales activity',
type: 'dateTime',
},
{
displayName: 'Latitude',
name: 'latitude',
type: 'string',
default: '',
description: 'Latitude of the location when you check in on a sales activity',
},
{
displayName: 'Location',
name: 'location',
type: 'string',
default: '',
description: 'Location of the sales activity',
},
{
displayName: 'Longitude',
name: 'longitude',
type: 'string',
default: '',
description: 'Longitude of the location when you check in for a sales activity',
},
{
displayName: 'Notes',
name: 'notes',
type: 'string',
default: '',
description: 'Description about the sales activity',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who owns the sales activity',
},
{
displayName: 'Sales Activity Outcome ID',
name: 'sales_activity_outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of a sales activity\'s outcome',
},
{
displayName: 'Sales Activity Type ID',
name: 'sales_activity_type_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getSalesActivityTypes',
},
description: 'ID of a sales activity type for which the sales activity is updated',
},
{
displayName: 'Start Date',
name: 'from_date',
description: 'Timestamp that denotes the start of the sales activity',
type: 'dateTime',
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
type: 'string',
default: '',
description: 'ID of the entity for which the sales activity is updated. The type of entity is selected in "Targetable Type".',
},
{
displayName: 'Targetable Type',
name: 'targetable_type',
type: 'options',
default: 'Contact',
description: 'Type of the entity for which the sales activity is updated',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'SalesAccount',
value: 'SalesAccount',
},
],
},
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Title of the sales activity to update',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,480 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const taskOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'task',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a task',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a task',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a task',
},
{
name: 'Get All',
value: 'getAll',
description: 'Retrieve all tasks',
},
{
name: 'Update',
value: 'update',
description: 'Update a task',
},
],
default: 'create',
},
] as INodeProperties[];
export const taskFields = [
// ----------------------------------------
// task: create
// ----------------------------------------
{
displayName: 'Title',
name: 'title',
description: 'Title of the task',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Due Date',
name: 'dueDate',
description: 'Timestamp that denotes when the task is due to be completed',
type: 'dateTime',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Owner ID',
name: 'ownerId',
description: 'ID of the user to whom the task is assigned',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
required: true,
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Targetable Type',
name: 'targetableType',
description: 'Type of the entity for which the task is updated',
type: 'options',
required: true,
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'SalesAccount',
value: 'SalesAccount',
},
],
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
description: 'ID of the entity for which the task is created. The type of entity is selected in "Targetable Type".',
type: 'string',
default: '',
required: true,
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: 'Creator ID',
name: 'creater_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the task',
},
{
displayName: 'Outcome ID',
name: 'outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of the outcome of the task',
},
{
displayName: 'Task Type ID',
name: 'task_type_id',
type: 'string', // not obtainable from API
default: '',
description: 'ID of the type of task',
},
],
},
// ----------------------------------------
// 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: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
default: false,
placeholder: 'Add Filter',
displayOptions: {
show: {
resource: [
'task',
],
operation: [
'getAll',
],
},
},
options: [
{
displayName: 'Include',
name: 'include',
type: 'options',
default: 'owner',
options: [
{
name: 'Owner',
value: 'owner',
},
{
name: 'Targetable',
value: 'targetable',
},
{
name: 'Users',
value: 'users',
},
],
},
{
displayName: 'Status',
name: 'filter',
type: 'options',
default: 'open',
options: [
{
name: 'Completed',
value: 'completed',
},
{
name: 'Due Today',
value: 'due_today',
},
{
name: 'Due Tomorrow',
value: 'due_tomorrow',
},
{
name: 'Open',
value: 'open',
},
{
name: 'Overdue',
value: 'overdue',
},
],
},
],
},
// ----------------------------------------
// 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: 'Creator ID',
name: 'creater_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user who created the sales activity',
},
{
displayName: 'Due Date',
name: 'dueDate',
description: 'Timestamp that denotes when the task is due to be completed',
type: 'dateTime',
default: '',
},
{
displayName: 'Outcome ID',
name: 'outcome_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getOutcomes',
},
description: 'ID of the outcome of the task',
},
{
displayName: 'Owner ID',
name: 'owner_id',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getUsers',
},
description: 'ID of the user to whom the task is assigned',
},
{
displayName: 'Targetable ID',
name: 'targetable_id',
type: 'string',
default: '',
description: 'ID of the entity for which the task is updated. The type of entity is selected in "Targetable Type".',
},
{
displayName: 'Targetable Type',
name: 'targetable_type',
description: 'Type of the entity for which the task is updated',
type: 'options',
default: 'Contact',
options: [
{
name: 'Contact',
value: 'Contact',
},
{
name: 'Deal',
value: 'Deal',
},
{
name: 'SalesAccount',
value: 'SalesAccount',
},
],
},
{
displayName: 'Task Type ID',
name: 'task_type_id',
type: 'string', // not obtainable from API
default: '',
description: 'ID of the type of task',
},
{
displayName: 'Title',
name: 'title',
type: 'string',
default: '',
description: 'Title of the task',
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,7 @@
export * from './AccountDescription';
export * from './AppointmentDescription';
export * from './ContactDescription';
export * from './DealDescription';
export * from './NoteDescription';
export * from './SalesActivityDescription';
export * from './TaskDescription';

View file

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="layer"
viewBox="0 0 102.6 102.6"
xml:space="preserve"
sodipodi:docname="freshworksCrm.svg"
width="102.6"
height="102.6"
inkscape:version="1.1 (c4e8f9e, 2021-05-24)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview156"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.7642045"
inkscape:cx="166.36393"
inkscape:cy="122.15137"
inkscape:window-width="1312"
inkscape:window-height="847"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer" /><defs
id="defs173" />
<style
type="text/css"
id="style108">
.st0{fill:#4D4D4D;}
.st1{fill:#9B65C3;}
.st2{fill:#BE63C5;}
.st3{fill:#BF63C6;}
.st4{fill:#3278B1;}
.st5{fill:#3278B2;}
.st6{fill:#45A4EC;}
.st7{fill:#19BB7D;}
.st8{fill:#08C7FB;}
.st9{fill:#59F2F6;}
.st10{fill:#FFA700;}
.st11{fill:#DA3757;}
.st12{fill:#D33C4E;}
.st13{fill:#EE5A24;}
.st14{fill:#8BDF55;}
.st15{fill:#25C16F;}
.st16{fill:#FFBB00;}
.st17{fill:#FFA800;}
</style>
<g
id="g168"
transform="translate(-21.6,-279.3)">
<path
class="st1"
d="m 22.2,338.2 c 1.7,11.1 6.9,21.1 14.4,28.6 l 17.5,-17.5 c 0,-17.7 9.2,-34.9 25.6,-44.4 z"
id="path130" />
<path
class="st1"
d="m 54.1,349.3 c -8.7,0 -17.5,-2.2 -25.6,-6.9 -2.2,-1.3 -4.3,-2.7 -6.3,-4.3 1.7,11.1 6.9,21.1 14.4,28.6 z"
id="path132" />
<path
class="st2"
d="m 54.1,349.3 v 0 l -17.5,17.5 c 7.6,7.6 17.5,12.8 28.6,14.4 L 98.4,323.7 C 89,340.1 71.8,349.3 54.1,349.3"
id="path134" />
<path
class="st3"
d="m 61,375 c -4.7,-8.1 -6.9,-16.9 -6.9,-25.6 l -17.5,17.5 c 7.6,7.6 17.5,12.8 28.6,14.4 -1.5,-2 -2.9,-4.1 -4.2,-6.3"
id="path136" />
<path
class="st4"
d="M 119.3,282.1 79.8,305 c -16.4,9.5 -35.9,8.8 -51.2,0 -4.4,7.5 -6.9,16.3 -6.9,25.6 0,2.6 0.2,5.1 0.6,7.6 2,1.6 4.1,3 6.3,4.3 8.1,4.7 16.9,6.9 25.6,6.9 l 66.2,-66.2 c -0.4,-0.4 -0.7,-0.8 -1.1,-1.1"
id="path138" />
<path
class="st5"
d="m 28.5,342.5 c 8.1,4.7 16.9,6.9 25.6,6.9 0,-17.7 9.2,-34.9 25.6,-44.4 l -57.6,33.2 c 2.1,1.5 4.2,3 6.4,4.3"
id="path140" />
<path
class="st6"
d="m 28.5,305 c -4.4,7.5 -6.9,16.3 -6.9,25.6 0,2.6 0.2,5.1 0.6,7.6 L 79.8,305 c -16.5,9.4 -36,8.8 -51.3,0"
id="path142" />
<path
class="st7"
d="m 120.4,283.1 c -0.3,-0.3 -0.7,-0.7 -1.1,-1 -0.5,-0.4 -1,-0.8 -1.6,-1.1 -1.9,-1.1 -4.1,-1.7 -6.4,-1.7 H 72.9 c -19,0 -35.5,10.3 -44.4,25.6 15.3,8.8 34.8,9.5 51.2,0 -16.4,9.5 -25.6,26.7 -25.6,44.4 17.7,0 34.9,-9.2 44.4,-25.6 l 22.8,-39.5 c -0.3,-0.4 -0.6,-0.8 -0.9,-1.1"
id="path144" />
<path
class="st8"
d="m 79.8,305 39.5,-22.8 c -0.5,-0.4 -1,-0.8 -1.6,-1.1 L 28.5,305 c 15.3,8.8 34.8,9.4 51.3,0"
id="path146" />
<path
class="st9"
d="M 111.3,279.3 H 72.9 c -19,0 -35.5,10.3 -44.4,25.6 L 117.7,281 c -1.9,-1 -4,-1.7 -6.4,-1.7"
id="path148" />
<path
class="st10"
d="M 54.1,349.3"
id="path150" />
<path
class="st11"
d="m 98.5,323.7 22.8,-39.5 c -0.3,-0.4 -0.6,-0.7 -1,-1.1 l -66.2,66.2 c 0,8.7 2.2,17.5 6.9,25.6 1.3,2.2 2.7,4.3 4.3,6.3 2.5,0.4 5,0.6 7.6,0.6 9.3,0 18.1,-2.5 25.6,-6.9 -8.8,-15.3 -9.5,-34.8 0,-51.2"
id="path152" />
<path
class="st12"
d="m 54.1,349.3 v 0 c 0,8.7 2.2,17.5 6.9,25.6 1.3,2.2 2.7,4.3 4.3,6.3 L 98.5,323.7 C 89,340.1 71.8,349.3 54.1,349.3"
id="path154" />
<path
class="st13"
d="m 98.5,323.7 -33.2,57.6 c 2.5,0.4 5,0.6 7.6,0.6 9.3,0 18.1,-2.5 25.6,-6.9 -8.8,-15.4 -9.5,-34.9 0,-51.3"
id="path156" />
<path
class="st14"
d="m 122.4,285.8 c -0.3,-0.6 -0.7,-1.1 -1.1,-1.6 -0.3,-0.4 -0.6,-0.7 -1,-1.1 -0.3,-0.3 -0.7,-0.7 -1.1,-1 L 79.8,305 c -16.4,9.5 -25.6,26.7 -25.6,44.4 17.7,0 34.9,-9.2 44.4,-25.6 -9.5,16.4 -8.8,35.9 0,51.2 15.3,-8.9 25.6,-25.4 25.6,-44.4 v -38.4 c -0.1,-2.4 -0.7,-4.6 -1.8,-6.4"
id="path158" />
<path
class="st15"
d="M 119.3,282.1 79.8,305 c -16.4,9.5 -25.6,26.7 -25.6,44.4 l 66.2,-66.2 c -0.4,-0.4 -0.7,-0.8 -1.1,-1.1"
id="path160" />
<path
class="st14"
d="m 54.1,349.3 c 17.7,0 34.9,-9.2 44.4,-25.6 l 22.8,-39.5 c -0.3,-0.4 -0.6,-0.7 -1,-1.1 z"
id="path162" />
<path
class="st16"
d="m 121.3,284.2 -22.8,39.5 c -9.5,16.4 -8.8,35.9 0,51.2 l 23.9,-89.2 c -0.3,-0.5 -0.7,-1 -1.1,-1.5"
id="path164" />
<path
class="st17"
d="m 98.5,375 c 15.3,-8.9 25.6,-25.4 25.6,-44.4 v -38.4 c 0,-2.3 -0.6,-4.5 -1.7,-6.4 z"
id="path166" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -0,0 +1,43 @@
export type FreshworksCrmApiCredentials = {
apiKey: string;
domain: string;
}
export type FreshworksConfigResponse<T> = {
[key: string]: T[];
};
export type LoadOption = {
name: string;
value: string;
};
export type LoadedCurrency = {
currency_code: string;
id: string;
};
export type LoadedUser = {
id: string;
display_name: string;
};
export type SalesAccounts = {
sales_accounts?: number[];
};
export type ViewsResponse = {
filters: View[];
meta: object;
}
export type View = {
id: number;
name: string;
model_class_name: string;
user_id: number;
is_default: boolean;
updated_at: string;
user_name: string;
current_user_permissions: string[];
};

View file

@ -7,6 +7,11 @@ type LoadedResource = {
name: string;
};
type LoadOption = {
value: string;
name: string;
};
type LoadedUser = {
id: string;
full_name_display: string;

View file

@ -85,6 +85,7 @@
"dist/credentials/FacebookGraphApi.credentials.js",
"dist/credentials/FacebookGraphAppApi.credentials.js",
"dist/credentials/FreshdeskApi.credentials.js",
"dist/credentials/FreshworksCrmApi.credentials.js",
"dist/credentials/FileMaker.credentials.js",
"dist/credentials/FlowApi.credentials.js",
"dist/credentials/Ftp.credentials.js",
@ -375,6 +376,7 @@
"dist/nodes/FileMaker/FileMaker.node.js",
"dist/nodes/Ftp.node.js",
"dist/nodes/Freshdesk/Freshdesk.node.js",
"dist/nodes/FreshworksCrm/FreshworksCrm.node.js",
"dist/nodes/Flow/Flow.node.js",
"dist/nodes/Flow/FlowTrigger.node.js",
"dist/nodes/Function.node.js",