From be609208aae7526df1bbcf9b3ce463116fa97afa Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Mon, 13 Dec 2021 20:09:10 -0500 Subject: [PATCH 01/12] feat: added Onfleet nodes Added Onfleet nodes for working with different endpoints like: organizations, administrators, workers, hubs, teams, destinations, recipients, containers and webhooks. --- .../credentials/OnfleetApi.credentials.ts | 18 + .../nodes/Onfleet/GenericFunctions.ts | 56 + .../nodes/Onfleet/Onfleet.node.json | 32 + .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 1218 +++++++++++++++++ packages/nodes-base/nodes/Onfleet/Onfleet.png | Bin 0 -> 1327 bytes .../nodes-base/nodes/Onfleet/Onfleet@2x.png | Bin 0 -> 2913 bytes .../nodes/Onfleet/OnfleetTrigger.node.json | 27 + .../nodes/Onfleet/OnfleetTrigger.node.ts | 197 +++ .../nodes/Onfleet/WebhookMapping.ts | 84 ++ .../descriptions/AdministratorDescription.ts | 167 +++ .../descriptions/ContainerDescription.ts | 162 +++ .../descriptions/DestinationDescription.ts | 389 ++++++ .../Onfleet/descriptions/HubDescription.ts | 123 ++ .../descriptions/OnfleetWebhookDescription.ts | 17 + .../descriptions/OrganizationDescription.ts | 53 + .../descriptions/RecipientDescription.ts | 332 +++++ .../Onfleet/descriptions/TaskDescription.ts | 431 ++++++ .../Onfleet/descriptions/TeamDescription.ts | 185 +++ .../descriptions/WebhookDescription.ts | 153 +++ .../Onfleet/descriptions/WorkerDescription.ts | 570 ++++++++ .../nodes-base/nodes/Onfleet/interfaces.ts | 157 +++ packages/nodes-base/package.json | 3 + 22 files changed, 4374 insertions(+) create mode 100644 packages/nodes-base/credentials/OnfleetApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Onfleet/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.node.json create mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.node.ts create mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.png create mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet@2x.png create mode 100644 packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json create mode 100644 packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts create mode 100644 packages/nodes-base/nodes/Onfleet/WebhookMapping.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts create mode 100644 packages/nodes-base/nodes/Onfleet/interfaces.ts diff --git a/packages/nodes-base/credentials/OnfleetApi.credentials.ts b/packages/nodes-base/credentials/OnfleetApi.credentials.ts new file mode 100644 index 0000000000000..69e5ae3b72b00 --- /dev/null +++ b/packages/nodes-base/credentials/OnfleetApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class OnfleetApi implements ICredentialType { + name = 'onfleetApi'; + displayName = 'Onfleet API'; + documentationUrl = 'onfleet'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts new file mode 100644 index 0000000000000..5e8da96ed19af --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts @@ -0,0 +1,56 @@ +import { + IDataObject, + JsonObject, + NodeApiError +} from 'n8n-workflow'; +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { + OptionsWithUri, +} from 'request'; + +export async function onfleetApiRequest( + this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, + method: string, + apikey: string, + resource: string, + body: any = {}, // tslint:disable-line:no-any + qs?: any, // tslint:disable-line:no-any + uri?: string, + headers: IDataObject = {}, + option: IDataObject = {}): Promise { // tslint:disable-line:no-any + const options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Basic ${apikey}`, + 'User-Agent': 'n8n-onfleet', + }, + method, + body, + qs, + uri: uri || `https://onfleet.com/api/v2/${resource}`, + json: true, + }; + try { + //@ts-ignore + return await this.helpers.request(options); + } catch (error) { + const apiError = error as IDataObject; + const { message: messageError } = apiError.error as IDataObject; + if (messageError) { + const { message = '', cause = '' } = messageError as IDataObject; + if (message && cause) { + apiError.message = `${message}: ${cause}`; + } else { + apiError.message = message; + } + throw new NodeApiError(this.getNode(), apiError as JsonObject); + } + throw new NodeApiError(this.getNode(), apiError as JsonObject); + } +} diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.json b/packages/nodes-base/nodes/Onfleet/Onfleet.node.json new file mode 100644 index 0000000000000..b88e2cda5be7c --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.json @@ -0,0 +1,32 @@ +{ + "node": "n8n-nodes-base.onfleet", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": [ + "Development" + ], + "resources": { + "credentialDocumentation": [ + { + "url": "https://docs.n8n.io/credentials/github" + } + ], + "primaryDocumentation": [ + { + "url": "https://docs.n8n.io/nodes/n8n-nodes-base.github/" + } + ], + "generic": [ + { + "label": "Automatically pulling and visualizing data with n8n", + "icon": "📈", + "url": "https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/" + }, + { + "label": "5 workflow automations for Mattermost that we love at n8n", + "icon": "🤖", + "url": "https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/" + } + ] + } +} diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts new file mode 100644 index 0000000000000..0ec8ee6b049e6 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -0,0 +1,1218 @@ +import { + ICredentialDataDecryptedObject, + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; +import { + OnfleetAdmins, + OnfleetCloneTask, + OnfleetCloneTaskOptions, + OnfleetDestination, + OnfleetHubs, + OnfleetListTaskFilters, + OnfleetRecipient, + OnfleetTask, + OnfleetTaskComplete, + OnfleetTaskUpdate, + OnfleetTeams, + OnfleetWebhook, + OnfleetWorker, + OnfleetWorkerFilter, + OnfleetWorkerSchedule +} from './interfaces'; +import { taskFields, taskOperations } from './descriptions/TaskDescription'; + +import { + IExecuteFunctions, +} from 'n8n-core'; +import { destinationFields, destinationOperations } from './descriptions/DestinationDescription'; +import { + onfleetApiRequest, +} from './GenericFunctions'; +import { recipientFields, recipientOperations } from './descriptions/RecipientDescription'; +import { organizationFields, organizationOperations } from './descriptions/OrganizationDescription'; +import { adminFields, adminOperations } from './descriptions/AdministratorDescription'; +import { hubFields, hubOperations } from './descriptions/HubDescription'; +import { workerFields, workerOperations } from './descriptions/WorkerDescription'; +import { webhookFields, webhookOperations } from './descriptions/WebhookDescription'; +import { containerFields, containerOperations } from './descriptions/ContainerDescription'; +import { teamFields, teamOperations } from './descriptions/TeamDescription'; + +export class Onfleet implements INodeType { + description: INodeTypeDescription = { + displayName: 'Onfleet', + name: 'onfleet', + icon: 'file:Onfleet.png', + group: ['input'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Onfleet API', + defaults: { + name: 'Onfleet', + color: '#AA81F3', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'onfleetApi', + required: true, + }, + ], + properties: [ + // List of option resources + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Admins', + value: 'admins', + }, + { + name: 'Containers', + value: 'containers', + }, + { + name: 'Destinations', + value: 'destinations', + }, + { + name: 'Organization', + value: 'organizations', + }, + { + name: 'Recipients', + value: 'recipients', + }, + { + name: 'Tasks', + value: 'tasks', + }, + { + name: 'Teams', + value: 'teams', + }, + { + name: 'Workers', + value: 'workers', + }, + { + name: 'Webhooks', + value: 'webhooks', + }, + { + name: 'Hubs', + value: 'hubs', + }, + ], + default: 'tasks', + description: 'The resource to perform operations on.', + }, + // Operations + ...adminOperations, + ...recipientOperations, + ...taskOperations, + ...destinationOperations, + ...organizationOperations, + ...hubOperations, + ...workerOperations, + ...webhookOperations, + ...containerOperations, + ...teamOperations, + // Display Fields + ...adminFields, + ...destinationFields, + ...recipientFields, + ...taskFields, + ...organizationFields, + ...hubFields, + ...workerFields, + ...webhookFields, + ...containerFields, + ...teamFields, + ], + }; + + /** + * Gets the properties of a destination according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current destination opration + * @returns {OnfleetDestination} Destination information + */ + static getDestinationFields(this: IExecuteFunctions, item: number, operation: string) { + if (['create', 'createBatch', 'update'].includes(operation)) { + /* -------------------------------------------------------------------------- */ + /* Get fields for create, createBatch and update task */ + /* -------------------------------------------------------------------------- */ + const unparsed = this.getNodeParameter('unparsed', item) as boolean; + const addDestinationFields = this.getNodeParameter('additionalDestinationFields', item) as IDataObject; + let destination: OnfleetDestination; + if (unparsed) { + destination = { + address: { + unparsed: this.getNodeParameter('address', item) as string, + }, + }; + } else { + destination = { + address: { + number: this.getNodeParameter('addressNumber', item) as string, + street: this.getNodeParameter('addressStreet', item) as string, + city: this.getNodeParameter('addressCity', item) as string, + country: this.getNodeParameter('addressCountry', item) as string, + }, + }; + } + + // Adding destination extra fields + if (addDestinationFields.addressName) { + destination.address.name = addDestinationFields.addressName as string; + } + if (addDestinationFields.addressApartment) { + destination.address.apartment = addDestinationFields.addressApartment as string; + } + if (addDestinationFields.addressState) { + destination.address.state = addDestinationFields.addressState as string; + } + if (addDestinationFields.addressPostalCode) { + destination.address.postalCode = addDestinationFields.addressPostalCode as string; + } + if (addDestinationFields.addressNotes) { + destination.notes = addDestinationFields.addressNotes as string; + } + + return destination; + } + return null; + } + + /** + * Gets the properties of a administrator according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current administrator opration + * @returns {OnfleetAdmins} Administrator information + */ + static getAdminFields(this: IExecuteFunctions, item: number, operation: string): OnfleetAdmins | null { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Get fields for create admin */ + /* -------------------------------------------------------------------------- */ + const name = this.getNodeParameter('name', item) as string; + const email = this.getNodeParameter('email', item) as string; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + + const adminData: OnfleetAdmins = { name, email }; + // Adding additional fields + Object.assign(adminData, additionalFields); + + return adminData; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields for update admin */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const adminData: OnfleetAdmins = {}; + // Adding additional fields + Object.assign(adminData, additionalFields); + return adminData; + } + return null; + } + + /** + * Gets the properties of a hub according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current hub opration + * @returns {OnfleetHub} Hub information + */ + static getHubFields(this: IExecuteFunctions, item: number, operation: string): OnfleetHubs | null { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Get fields for create hub */ + /* -------------------------------------------------------------------------- */ + const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + const name = this.getNodeParameter('name', item) as string; + const { teams } = this.getNodeParameter('additionalFields', item) as IDataObject; + + const hubData: OnfleetHubs = { name, ...destination }; + // Adding additional fields + if (teams) { + Object.assign(hubData, { teams: JSON.parse(teams as string) }); + } + + return hubData; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields for update hub */ + /* -------------------------------------------------------------------------- */ + const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + const hubData: OnfleetHubs = { ...destination }; + + // Adding additional fields + const {teams, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; + if (teams) { + Object.assign(hubData, { teams: JSON.parse(teams as string) }); + } + Object.assign(hubData, additionalFields); + return hubData; + } + return null; + } + + /** + * Gets the properties of a worker according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current worker opration + * @returns {OnfleetWorker|OnfleetWorkerFilter|OnfleetWorkerSchedule} Worker information + */ + static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | null { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Get fields for create worker */ + /* -------------------------------------------------------------------------- */ + const name = this.getNodeParameter('name', item) as string; + const phone = this.getNodeParameter('phone', item) as string; + const teams = JSON.parse(this.getNodeParameter('teams', item) as string) as string[]; + const vehicle = this.getNodeParameter('vehicle', item) as boolean; + const workerData: OnfleetWorker = { name, phone, teams }; + + // Addding vehicule fields + if (vehicle) { + const type = this.getNodeParameter('type', item) as string; + const additionalVehicleFields = this.getNodeParameter('additionalVehicleFields', item) as IDataObject; + Object.assign(workerData, { vehicle: { type, ...additionalVehicleFields} }); + } + + // Adding additional fields + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + Object.assign(workerData, additionalFields); + + return workerData; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields for update worker */ + /* -------------------------------------------------------------------------- */ + const vehicle = this.getNodeParameter('vehicle', item) as boolean; + const workerData: OnfleetWorker = {}; + + // Addding vehicule fields + if (vehicle) { + const type = this.getNodeParameter('type', item) as string; + const additionalVehicleFields = this.getNodeParameter('additionalVehicleFields', item) as IDataObject; + Object.assign(workerData, { vehicle: { type, ...additionalVehicleFields} }); + } + + // Adding additional fields + const {teams, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; + Object.assign(workerData, additionalFields); + if (teams) { + workerData.teams = JSON.parse(teams as string); + } + + return workerData; + } else if (['getAll', 'get'].includes(operation)) { + /* -------------------------------------------------------------------------- */ + /* Get fields for get and getAll workers */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const workerFilter: OnfleetWorkerFilter = {}; + if (additionalFields.states) { + additionalFields.states = (additionalFields.states as number[]).join(','); + } + Object.assign(workerFilter, additionalFields); + return workerFilter; + } else if (operation === 'setSchedule') { + /* -------------------------------------------------------------------------- */ + /* Get fields for setSchedule to worker */ + /* -------------------------------------------------------------------------- */ + const scheduleDate = new Date(this.getNodeParameter('date', item) as Date); + const timezone = this.getNodeParameter('timezone', item) as string; + const start = new Date(this.getNodeParameter('start', item) as Date); + const end = new Date(this.getNodeParameter('end', item) as Date); + const datestring = scheduleDate.getFullYear() + + '-' + (scheduleDate.getMonth() + 1).toString().padStart(2, '0') + + '-' + scheduleDate.getDate().toString().padStart(2, '0'); + const workerSchedule: OnfleetWorkerSchedule = { + entries: [ + { + date: datestring, + timezone, + shifts: [[ + start.getTime(), end.getTime(), + ]], + }, + ], + }; + return workerSchedule; + } + return null; + } + + /** + * Gets the properties of a webhooks according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current webhooks opration + * @returns {OnfleetWebhook} Webhooks information + */ + static getWebhookFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWebhook | null { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Get fields for create webhook */ + /* -------------------------------------------------------------------------- */ + const url = this.getNodeParameter('url', item) as string; + const name = this.getNodeParameter('name', item) as string; + const trigger = this.getNodeParameter('trigger', item) as number; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + + const webhookData: OnfleetWebhook = { url, name, trigger }; + // Adding additional fields + Object.assign(webhookData, additionalFields); + + return webhookData; + } + return null; + } + + /** + * Gets the properties of a recipient according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current recipient opration + * @returns {OnfleetRecipient} Recipient information + */ + static getRecipientFields(this: IExecuteFunctions, item: number, operation: string) { + if (['create', 'createBatch'].includes(operation)) { + /* -------------------------------------------------------------------------- */ + /* Get fields to create recipient */ + /* -------------------------------------------------------------------------- */ + const addRecipientFields = this.getNodeParameter('additionalRecipientFields', item) as IDataObject; + const recipient: OnfleetRecipient = { + name: this.getNodeParameter('recipientName', item) as string, + phone: this.getNodeParameter('recipientPhone', item) as string, + }; + + // Adding recipient extra fields + if (addRecipientFields.recipientNotes) { + recipient.notes = addRecipientFields.recipientNotes as string; + } + if (addRecipientFields.skipSMSNotifications) { + recipient.skipSMSNotifications = addRecipientFields.skipSMSNotifications as boolean; + } + if (addRecipientFields.skipPhoneNumberValidation) { + recipient.skipPhoneNumberValidation = addRecipientFields.skipPhoneNumberValidation as boolean; + } + + return recipient; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields to update recipient */ + /* -------------------------------------------------------------------------- */ + const { + recipientName: name = '', recipientPhone: phone = '', ...additionalFields + } = this.getNodeParameter('additionalFields', item) as IDataObject; + + const recipientData: OnfleetRecipient = {}; + + // Adding additional fields + if (name) { + recipientData.name = name as string; + } + if (phone) { + recipientData.phone = phone as string; + } + Object.assign(recipientData, additionalFields); + return recipientData; + } + } + + /** + * Gets the properties of a task according to the operation chose + * @param this Current node execution function + * @param items Current execution data + * @param operation Current task operation + * @returns {OnfleetListTaskFilters | OnfleetTask } Task information + */ + static getTaskFields(this: IExecuteFunctions, item: number, operation: string): + OnfleetListTaskFilters | OnfleetTask | OnfleetCloneTask | OnfleetTaskComplete | OnfleetTaskUpdate | null { + if (['create', 'createBatch'].includes(operation)) { + /* -------------------------------------------------------------------------- */ + /* Get fields to create and createBatch tasks */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + + // Adding recipients information + const hasRecipient = this.getNodeParameter('recipient', item) as boolean; + const recipients: OnfleetRecipient[] = []; + if (hasRecipient) { + const recipient = Onfleet.getRecipientFields.call(this, item, operation) as OnfleetRecipient; + recipients.push(recipient); + } + + const taskData: OnfleetTask = { destination, recipients }; + const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields; + if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime(); + if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime(); + + Object.assign(taskData, extraFields); + return taskData; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields to update task */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const taskData: OnfleetTaskUpdate = {}; + const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields; + if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime(); + if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime(); + Object.assign(taskData, extraFields); + return taskData; + } else if (operation === 'clone') { + /* -------------------------------------------------------------------------- */ + /* Get fields to clone task */ + /* -------------------------------------------------------------------------- */ + const optionFields = this.getNodeParameter('options', item) as IDataObject; + + const options: OnfleetCloneTaskOptions = {}; + if (optionFields.includeMetadata) options.includeMetadata = optionFields.includeMetadata as boolean; + if (optionFields.includeBarcodes) options.includeBarcodes = optionFields.includeBarcodes as boolean; + if (optionFields.includeDependencies) options.includeDependencies = optionFields.includeDependencies as boolean; + if (optionFields.overrides) options.overrides = optionFields.overrides as object; + return { options } as OnfleetCloneTask; + } else if (operation === 'list') { + /* -------------------------------------------------------------------------- */ + /* Get fields to list tasks */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const listTaskData: OnfleetListTaskFilters = { + from: new Date(this.getNodeParameter('from', 0) as Date).getTime(), + }; + + // Adding extra fields to search tasks + if (additionalFields.to) { + listTaskData.to = new Date(additionalFields.to as Date).getTime(); + } + if (additionalFields.state) { + listTaskData.state = (additionalFields.state as number[]).join(','); + } + if (additionalFields.lastId) { + listTaskData.lastId = additionalFields.lastId as string; + } + + return listTaskData; + } else if (operation === 'complete') { + /* -------------------------------------------------------------------------- */ + /* Get fields to complete a task */ + /* -------------------------------------------------------------------------- */ + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const success = this.getNodeParameter('success', item) as boolean; + const taskData: OnfleetTaskComplete = { completionDetails: { success } }; + if (additionalFields.notes) taskData.completionDetails.notes = additionalFields.notes as string; + return taskData; + } + return null; + } + + /** + * Gets the properties of a team according to the operation chose + * @param this Current node execution function + * @param item Current execution data + * @param operation Current team opration + * @returns {OnfleetTeams} Team information + */ + static getTeamFields(this: IExecuteFunctions, item: number, operation: string): OnfleetTeams | null { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Get fields to create a team */ + /* -------------------------------------------------------------------------- */ + const name = this.getNodeParameter('name', item) as string; + const workers = this.getNodeParameter('workers', item) as string; + const managers = this.getNodeParameter('managers', item) as string; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + + const teamData: OnfleetTeams = { name, workers: JSON.parse(workers), managers: JSON.parse(managers) }; + // Adding additional fields + Object.assign(teamData, additionalFields); + + return teamData; + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Get fields to update a team */ + /* -------------------------------------------------------------------------- */ + const teamData: OnfleetTeams = {}; + // Adding additional fields + const {workers, managers, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; + if (workers) { + Object.assign(teamData, { workers: JSON.parse(workers as string) }); + } + if (managers) { + Object.assign(teamData, { managers: JSON.parse(managers as string) }); + } + Object.assign(teamData, additionalFields); + return teamData; + } + return null; + } + + /** + * Execute the task operations + * @param this Execute function + * @param resource Resource to be executed (Task) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Task information + */ + static async executeTaskOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + if (operation === 'createBatch') { + /* -------------------------------------------------------------------------- */ + /* Add tasks by batch */ + /* -------------------------------------------------------------------------- */ + const path = `${resource}/batch`; + const tasksData = { tasks: items.map((_item, index) => Onfleet.getTaskFields.call(this, index, operation)) }; + const { tasks: tasksCreated } = await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, tasksData); + return tasksCreated; + } + + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add new task */ + /* -------------------------------------------------------------------------- */ + const taskData = Onfleet.getTaskFields.call(this, index, operation); + if (!taskData) { continue ;} + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, taskData)); + } else if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get a dingle task */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const shortId = this.getNodeParameter('shortId', index) as boolean; + const path = `${resource}${(shortId ? '/shortId' : '')}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } else if (operation === 'clone') { + /* -------------------------------------------------------------------------- */ + /* Clone a task */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const taskData = Onfleet.getTaskFields.call(this, index, operation); + if (!taskData) { continue; } + const path = `${resource}/${id}/clone`; + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, taskData)); + } else if (operation === 'delete') { + /* -------------------------------------------------------------------------- */ + /* Delete a single task */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } else if (operation === 'list') { + /* -------------------------------------------------------------------------- */ + /* List tasks */ + /* -------------------------------------------------------------------------- */ + const taskData = Onfleet.getTaskFields.call(this, 0, operation) as IDataObject; + if (!taskData) return []; + + const path = `${resource}/all`; + const { tasks = [] } = await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, taskData); + responseData.push(...tasks); + } else if (operation === 'complete') { + /* -------------------------------------------------------------------------- */ + /* Force to complete a task */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const taskData = Onfleet.getTaskFields.call(this, index, operation); + if (!taskData) { continue; } + const path = `${resource}/${id}/complete`; + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, taskData)); + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update a task */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', 0) as string; + const path = `${resource}/${id}`; + const taskData = Onfleet.getTaskFields.call(this, index, operation); + if (!taskData) { continue; } + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, taskData)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + return responseData; + } + + /** + * Execute the destination operations + * @param this Execute function + * @param resource Resource to be executed (Destination) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Destination information + */ + static async executeDestinationOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Create destiantion */ + /* -------------------------------------------------------------------------- */ + const destinationData = Onfleet.getDestinationFields.call(this, index, operation); + if (!destinationData) { continue; } + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, destinationData)); + } else if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get single destination */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the organization operations + * @param this Execute function + * @param resource Resource to be executed (Organization) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Organization information + */ + static async executeOrganizationOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get organization details */ + /* -------------------------------------------------------------------------- */ + const path = 'organization'; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } else if (operation === 'getDelegatee') { + /* -------------------------------------------------------------------------- */ + /* Get organization delegatee */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the recipient operations + * @param this Execute function + * @param resource Resource to be executed (Recipient) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Recipient information + */ + static async executeRecipientOperations(this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add a new recipient */ + /* -------------------------------------------------------------------------- */ + const recipientData = Onfleet.getRecipientFields.call(this, index, operation); + if (!recipientData) { continue; } + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, recipientData)); + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update a recipient */ + /* -------------------------------------------------------------------------- */ + const recipientData = Onfleet.getRecipientFields.call(this, index, operation); + if (!recipientData) { continue; } + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, recipientData)); + } else if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get recipient information */ + /* -------------------------------------------------------------------------- */ + const lookupBy = this.getNodeParameter('getBy', index) as string; + const lookupByValue = this.getNodeParameter(lookupBy, index) as string; + const path = `${resource}${lookupBy === 'id' ? '' : ('/' + lookupBy)}/${lookupByValue}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the administrator operations + * @param this Execute function + * @param resource Resource to be executed (Administrator) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Administrator information + */ + static async executeAdministratorOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get adiministrators */ + /* -------------------------------------------------------------------------- */ + responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); + } else if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add new admin */ + /* -------------------------------------------------------------------------- */ + const adminData = Onfleet.getAdminFields.call(this, index, operation); + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, adminData)); + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update admin */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const adminData = Onfleet.getAdminFields.call(this, index, operation); + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, adminData)); + } else if (operation === 'delete') { + /* -------------------------------------------------------------------------- */ + /* Delete admin */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the hub operations + * @param this Execute function + * @param resource Resource to be executed (Hub) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Hub information + */ + static async executeHubOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'getAll') { + /* -------------------------------------------------------------------------- */ + /* Get all hubs */ + /* -------------------------------------------------------------------------- */ + responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); + } else if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add new hub */ + /* -------------------------------------------------------------------------- */ + const hubData = Onfleet.getHubFields.call(this, index, operation); + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, hubData)); + } + if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update a hub */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const hubData = Onfleet.getHubFields.call(this, index, operation); + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, hubData)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the worker operations + * @param this Execute function + * @param resource Resource to be executed (Worker) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Workers information + */ + static async executeWorkerOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'getAll') { + /* -------------------------------------------------------------------------- */ + /* Get all workers */ + /* -------------------------------------------------------------------------- */ + const workerFilters = Onfleet.getWorkerFields.call(this, 0, operation) as OnfleetWorkerFilter; + + responseData.push(... await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource, {}, workerFilters)); + } else if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get a worker */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const workerFilters = Onfleet.getWorkerFields.call(this, index, operation) as OnfleetWorkerFilter; + const analytics = this.getNodeParameter('analytics', index) as boolean; + + const path = `${resource}/${id}`; + workerFilters.analytics = analytics ? 'true' : 'false'; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, workerFilters)); + } else if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add new worker */ + /* -------------------------------------------------------------------------- */ + const workerData = Onfleet.getWorkerFields.call(this, index, operation); + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, workerData)); + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update worker */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const workerData = Onfleet.getWorkerFields.call(this, index, operation); + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, workerData)); + } else if (operation === 'delete') { + /* -------------------------------------------------------------------------- */ + /* Delete worker */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } else if (operation === 'getSchedule') { + /* -------------------------------------------------------------------------- */ + /* Get worker schedule */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}/schedule`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } else if (operation === 'getAllLocation') { + /* -------------------------------------------------------------------------- */ + /* Get worker location */ + /* -------------------------------------------------------------------------- */ + const longitude = this.getNodeParameter('longitude', index) as string; + const latitude = this.getNodeParameter('latitude', index) as number; + const additionalFields = this.getNodeParameter('additionalFields', index) as IDataObject; + const path = `${resource}/location`; + const { workers } = await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, { longitude, latitude }); + responseData.push(...workers); + } else if (operation === 'setSchedule') { + /* -------------------------------------------------------------------------- */ + /* Set a worker schedule */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const workerSchedule = Onfleet.getWorkerFields.call(this, index, operation) as OnfleetWorkerSchedule; + const path = `${resource}/${id}/schedule`; + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, workerSchedule)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the webhook operations + * @param this Execute function + * @param resource Resource to be executed (Webhook) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Webhook information + */ + static async executeWebhookOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'getAll') { + /* -------------------------------------------------------------------------- */ + /* Get all webhooks */ + /* -------------------------------------------------------------------------- */ + responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); + } else if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add a new webhook */ + /* -------------------------------------------------------------------------- */ + const webhookData = Onfleet.getWebhookFields.call(this, index, operation); + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, webhookData)); + } else if (operation === 'delete') { + /* -------------------------------------------------------------------------- */ + /* Delete a webhook */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the containers operations + * @param this Execute function + * @param resource Resource to be executed (Container) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Contianer information + */ + static async executeContainerOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get container by id and type */ + /* -------------------------------------------------------------------------- */ + const containerId = this.getNodeParameter('containerId', index) as string; + const containerType = this.getNodeParameter('containerType', index) as string; + const path = `${resource}/${containerType}/${containerId}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } else if (['add', 'update'].includes(operation)) { + /* -------------------------------------------------------------------------- */ + /* Add or update tasks to container */ + /* -------------------------------------------------------------------------- */ + const containerId = this.getNodeParameter('containerId', index) as string; + const containerType = this.getNodeParameter('containerType', index) as string; + + const tasks = JSON.parse(this.getNodeParameter('tasks', index) as string) as Array; + if (operation === 'add') { + const type = this.getNodeParameter('type', index) as number; + if (type === 1) { + const tasksIndex = this.getNodeParameter('index', index) as number; + tasks.unshift(tasksIndex); + } else { + tasks.unshift(type); + } + } + const path = `${resource}/${containerType}/${containerId}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { tasks })); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + /** + * Execute the team operations + * @param this Execute function + * @param resource Resource to be executed (Team) + * @param operation Operation to be executed + * @param items Number of items to process by the node + * @param encodedApiKey API KEY for the current organization + * @returns Team information + */ + static async executeTeamOperations( + this: IExecuteFunctions, + resource: string, + operation: string, + items: INodeExecutionData[], + encodedApiKey: string, + ): Promise { + const responseData = []; + for (const key of Object.keys(items)) { + const index = Number(key); + try { + if (operation === 'getAll') { + /* -------------------------------------------------------------------------- */ + /* Get all teams */ + /* -------------------------------------------------------------------------- */ + responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); + } else if (operation === 'get') { + /* -------------------------------------------------------------------------- */ + /* Get a single team */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); + } else if (operation === 'create') { + /* -------------------------------------------------------------------------- */ + /* Add a new team */ + /* -------------------------------------------------------------------------- */ + const teamData = Onfleet.getTeamFields.call(this, index, operation); + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, teamData)); + } else if (operation === 'update') { + /* -------------------------------------------------------------------------- */ + /* Update a team */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const teamData = Onfleet.getTeamFields.call(this, index, operation); + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, teamData)); + } else if (operation === 'delete') { + /* -------------------------------------------------------------------------- */ + /* Delete a team */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const path = `${resource}/${id}`; + responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } + } catch (error) { + if (this.continueOnFail()) { + responseData.push({ error: (error as IDataObject).toString() }); + } + continue; + } + } + + return responseData; + } + + async execute(this: IExecuteFunctions): Promise { + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + const items = this.getInputData(); + //Get credentials the user provided for this node + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + const operations: { [ key:string ]: Function} = { + tasks: Onfleet.executeTaskOperations, + destinations: Onfleet.executeDestinationOperations, + organizations: Onfleet.executeOrganizationOperations, + admins: Onfleet.executeAdministratorOperations, + recipients: Onfleet.executeRecipientOperations, + hubs: Onfleet.executeHubOperations, + workers: Onfleet.executeWorkerOperations, + webhooks: Onfleet.executeWebhookOperations, + containers: Onfleet.executeContainerOperations, + teams: Onfleet.executeTeamOperations, + }; + + const responseData = await operations[resource].call(this, resource, operation, items, encodedApiKey); + // Map data to n8n data + return [this.helpers.returnJsonArray(responseData)]; + } + +} diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.png b/packages/nodes-base/nodes/Onfleet/Onfleet.png new file mode 100644 index 0000000000000000000000000000000000000000..2bfbacd3e151d90aefaa36f5d6ebef0e30cc7d29 GIT binary patch literal 1327 zcma)+eLT|%9LIkiCXFS|)0Eayj)hv?E89edFl-!C5hV|qnj*VArHvd&b3_UF7TL-qB)n*k(M2 z9@y$(BM#8%CeO#eseH#>8CVmnypIuz5iWKCOU-E>@9j^aiCa0N&=O5|+HDIJ?;*T1 zNj)bNRa9WQBTv&B`ZF9=Fy-Y|PPRYvF7!HW(v{|D9`R6#A62MrL~WTe9C0+ifo|gZ z9G|aA6I2=zMUiX8xm|rtz=*$N$Yc1dy-Vd(sOq0HBU=fOZn(JFt;wbmT~y8EW&uMI8pr4cC4B{E*$P^&&i$WY(cJP7%RJf z2|o~r+VCl}dijl|6!yr*PF|x0?+Wx(d&ZF%ynPHY)GJ%mrXRiweM%*_Wu?#G^V6Yj zza>P2(>wm6586?23Y1%7ZLP=2kiyzQilHq6Q=`W$A#r+!lVm1Em=;N-nIT}SyYls$GEvZ)=KS_zHiUauXpzQD#m zXYr;l`m;#ylL)?5x76GQwmo6c^1(X;swr!7=ClFtXzOdfbattk=?q~IL6f@cfAdV;k>(#sLi_1st4a#Tji?|hv!jUt35Kw)-f5C_=t+1!ql~r)= b|3&MtMo}V9nw4d>`K)lq2~G_TLDYW$%42XD literal 0 HcmV?d00001 diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet@2x.png b/packages/nodes-base/nodes/Onfleet/Onfleet@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..95311be0abc3cefbb24c8158fb9fa22b877c07b5 GIT binary patch literal 2913 zcmeHJ)n5~i7T<_5V3Z;Vl3sPh1}GuYAxe&rNex8|YP5_V2nf=ps4!YW&`E8yl!7=J zDlnRnKe}U5s22V^(08*zK3;@Qs0GR$-P9b;-0Dv(M2w*&A;NMyv z!+*K~d5r(ne~sX2>Y#@B82H7IwF?gyxg^m(`?fz37j$p!JY@TSuqpA zD|k$eCpD;Z99cFV>N#QTe^MMA6m%fDF`ewmum8=OgDLTqF_W~b7C+x9P;8gFOy?k0YKM*ApE8hssIlsb7P+(m=U#kfmVs8{f_&I|Vi1nFW%&qD@^bExQ5@XyXw^Cj#h<5X)ujjI9q zW_hXkLd`VSxMB|lu7zTTrh{K{q0`$}*{Yd`B(o%cLVD@5*$iLp7^4ihAw9%;`BYgc zk6ARCZms*d)(_;;mjw3H6e`y8%80RLiG)G#8U5OSIBYArS!3Ua+8N1_b3fMk@ql2} z`^aS@*F~^pMZxquMzvA5&P$@f&pQQ!{g-*oY+;y*#g)bPh`8*pwl9J-gr#j)P&q{- z3sd^xP;Xp8EH5eJJ*7sRmg(5GN{Z~Kg-qj-?b*#V8gI7hH5!a%$W4^1ucNV`|2N;e z#jHS;qmoOBT&hq#^^piCU|nU#2uvwg+DyrWH#YrYdqbe|o?#kUINR{YMRDX4eVe!@d`SkLi&Axlb#s9PmtflPhTY4ctS2SXw4@- zScnr34U9~HNXDM2{rF;3yi+%#D3I3s*9**O4wu%xVx5VF&@sd zycoEhIY{l0Em~N5E9AZpV^AtM>sh*6kH2ngr*XEi@sV}tsOE!@&)(^XoE3NeV zsI z+xM@b%n@S2FFnGP6z%i;Pu{@jJ&y@{^Bcl#qB(jA4@x*px2{m3TjwVInyVwU7p9&a zP>gGnDhLq+mxk0elw;0RMu%;YHm6nA*18TtAIlkiI)2npN3k8W)bvc4UHqQst2!7M z_QH`Jw_NSoLLkyOCin0blrBf~wBhGB`<2+>-M3EmBKz!(%u1QBvT)0}ilDJS`29t5;qq|drC2YPp zgLVpp$;&@fT3eWQBT#a@XgVi|%HF5oLuQTkYsoQ1m#jpg!bL5yg4Z2pIWfO5797?q zy=5US@-{w|UL;e^u1UNEmkcK>=h2hmHy4qMEfnHR2;cz}U3er$1t4HPY*A{}_br)d zS**5ARcdwDZ~5%(c{ba4N_Q&+_AFKwu$E{@savi4Q2`iHUK@|_Q%Bj_bFNct8iq-B?oJI-+IKWspo}z^8gmj5=4f+KP*Om=Tlq><;^$y{A~m;{HV3&Y z3Z?NseaT<$T)&b5lmQ2BT(a9NUQOfz^ECi5dIQ_3wHZ#|-3l_G=SJ(eW-CFThF9#l zTfFU}%GJznm}3ut@xv$a!L<5s*TjcLzR$Nxl)CYXpP)+&L0#hE@3gr-Wpw_I~D-fYzrsU)9c%Z6z9 zbm#>qs5}L08GCSgVz__g*UYWhxG$HuiDaEaAszaiR*%i&bpzKlqFJu(aL#9#Tii(` z3wQq{RNLT{w234;0&M1t-Qkz|fVAyd`gysY`;7xN$f=3pFsC)im^SUhStKFT$)Vk51B<9J^c)^?F(&k=S?MmlMkFy5lwW3e`< z8V#f?;oK6Sc1O)tSCNTx4!BgMC~n(*xtcWCV=okT?3i?Lg8NWkQ=Ha**B9`j>K;zI zV;dr3EbY{k@$~ig;E(SRK2oNiPWq{{aq9rx{8D1;C}aQ(e5-!d>?3^b@z4^29?AYg z9cE--C8ci~DtQmqt9RnWS>*D9eXU9{z#2VF3{^yw#uFDN*PXz(-(W570HVW_H7>w2 znu5e(V-uAvMQdxG%?o`?jFP7PXz@J8w&TK=^IMCsMEmx@>Vc}A`WMv7kyaAewRV+x zyL3qz>GUk$_uU9qk;9>a#b{!TAHIyAcRXFd&;;(uU@RO_$oeX!S%|wKT|&NgTcKxN zMBF7Zc+XitO?-&4q9>pnICK4+gWS&sWi7iu@Cf`a;cM{l)9#2oIe!e~STQXHy!cPS z9*3#kH~V}G50uc>%$z*U#;cx~*g$z24sYW&o=OZa5;7xHUCz@I>(zTL0OFOrCBZ7g zv-_o#;Hs2A3mTSex)s;T^X%pB?=dFNL$l6h@`PgKd@`i9hnqelS6nNZl^ofrkZum3 nK;)1ZW(Q=V3+3Mb6AC?StjUy%tmokO_q{dHL)^scI7Iv#I9Xnj literal 0 HcmV?d00001 diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json new file mode 100644 index 0000000000000..72b3c06048894 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json @@ -0,0 +1,27 @@ +{ + "node": "n8n-nodes-base.onfleetTrigger", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": [ + "Development" + ], + "resources": { + "credentialDocumentation": [ + { + "url": "https://docs.n8n.io/credentials/onfleet" + } + ], + "primaryDocumentation": [ + { + "url": "https://docs.n8n.io/nodes/n8n-nodes-base.onfleetTrigger/" + } + ], + "generic": [ + { + "label": "5 workflow automations for Mattermost that we love at n8n", + "icon": "🤖", + "url": "https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/" + } + ] + } +} diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts new file mode 100644 index 0000000000000..6fabf1cf108b6 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -0,0 +1,197 @@ +import { + ICredentialDataDecryptedObject, + IDataObject, + INodeType, + INodeTypeDescription, + IWebhookResponseData, + NodeApiError, + NodeOperationError, +} from 'n8n-workflow'; +import { + IHookFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { eventDisplay } from './descriptions/OnfleetWebhookDescription'; +import { + onfleetApiRequest, +} from './GenericFunctions'; +import { webhookMapping } from './WebhookMapping'; + +export class OnfleetTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Onfleet Trigger', + name: 'onfleetTrigger', + icon: 'file:Onfleet.png', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["events"]}}', + description: 'Starts the workflow when Onfleet events occur.', + defaults: { + name: 'Onfleet Trigger', + color: '#AA81F3', + }, + inputs: [], + outputs: ['main'], + credentials: [ + { + name: 'onfleetApi', + required: true, + }, + ], + webhooks: [ + { + name: 'default', + httpMethod: 'POST', + responseMode: 'onReceived', + path: 'webhook', + }, + { + name: 'validate', + httpMethod: 'GET', + responseMode: 'onReceived', + path: 'webhook', + }, + ], + properties: [ + eventDisplay, + ], + }; + + // @ts-ignore (because of request) + webhookMethods = { + default: { + async checkExists(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node') as IDataObject; + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const event = this.getNodeParameter('event', 0) as string; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + if (!webhookData[event] || typeof webhookData[event] !== 'string') { + // No webhook id is set so no webhook can exist + return false; + } + + // Webhook got created before so check if it still exists + const endpoint = `/webhooks/${webhookData[event]}`; + + try { + await onfleetApiRequest.call(this, 'GET', encodedApiKey, endpoint); + } catch (error) { + const { httpCode = '' } = error as { httpCode: string }; + if (httpCode === '404') { + // Webhook does not exist + delete webhookData[event]; + return false; + } + + // Some error occured + throw error; + } + + // If it did not error then the webhook exists + return true; + }, + async create(this: IHookFunctions): Promise { + const webhookUrl = this.getNodeWebhookUrl('default') as string; + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const webhookData = this.getWorkflowStaticData('node'); + const event = this.getNodeParameter('event', 0) as string; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + if (webhookUrl.includes('//localhost')) { + throw new NodeOperationError(this.getNode(), 'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!'); + } + + const path = `/webhooks`; + const body = { + name : `[N8N] ${webhookMapping[event].name}`, + url : webhookUrl, + trigger : webhookMapping[event].key, + }; + + try { + onfleetApiRequest.call(this, 'POST', encodedApiKey, path, body) + .then(responseData => { + if (responseData.id === undefined) { + // Required data is missing so was not successful + throw new NodeApiError(this.getNode(), responseData, { message: 'Onfleet webhook creation response did not contain the expected data.' }); + } + + webhookData[event] = responseData.id as string; + return Promise.resolve(true); + }); + } catch (error) { + const { httpCode = '' } = error as { httpCode: string }; + if (httpCode === '422') { + // Webhook exi`sts already + + // Get the data of the already registered webhook + onfleetApiRequest.call(this, 'GET', encodedApiKey, path) + .then((responseData: IDataObject[]) => { + const webhook = responseData.find(webhook => webhook.url === webhookUrl); + webhookData[event] = webhook!.id; + return Promise.resolve(true); + }); + throw new NodeOperationError(this.getNode(), 'A webhook with the identical URL probably exists already. Please delete it manually on Onfleet!'); + } + + throw error; + } + return true; + }, + async delete(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const event = this.getNodeParameter('event', 0) as string; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + if (webhookData[event] !== undefined) { + const endpoint = `/webhooks/${webhookData[event]}`; + + try { + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, endpoint); + } catch (error) { + return false; + } + + // Remove from the static workflow data so that it is clear + // that no webhooks are registred anymore + delete webhookData[event]; + } + + return true; + }, + }, + }; + + /** + * Triggered function when a Onfleet webhook is executed + * @param this Webhook functions + * @returns {Promise} Response data + */ + async webhook(this: IWebhookFunctions): Promise { + const req = this.getRequestObject(); + if (req.method === 'GET') { + /* -------------------------------------------------------------------------- */ + /* Validation request */ + /* -------------------------------------------------------------------------- */ + const res = this.getResponseObject(); + res.status(200).send(req.query.check); + return { noWebhookResponse: true }; + } + + const bodyData = this.getBodyData(); + const returnData: IDataObject[] = [{ + body: bodyData, + headers: this.getHeaderData(), + query: this.getQueryData(), + }]; + + return { + workflowData: [ + this.helpers.returnJsonArray(returnData), + ], + }; + } +} diff --git a/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts b/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts new file mode 100644 index 0000000000000..84a60333ab1bb --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts @@ -0,0 +1,84 @@ +import { OnfleetWebhooksMapping } from './interfaces'; + +export const webhookMapping: OnfleetWebhooksMapping = { + taskStarted: { + name: 'Task Started', + value: 'taskStarted', + key: 0, + }, + taskEta: { + name: 'Task Eta', + value: 'taskEta', + key: 1, + }, + taskArrival: { + name: 'Task Arrival', + value: 'taskArrival', + key: 2, + }, + taskCompleted: { + name: 'Task Completed', + value: 'taskCompleted', + key: 3, + }, + taskFailed: { + name: 'Task Failed', + value: 'taskFailed', + key: 4, + }, + workerDuty: { + name: 'Worker Duty', + value: 'workerDuty', + key: 5, + }, + taskCreated: { + name: 'Task Created', + value: 'taskCreated', + key: 6, + }, + taskUpdated: { + name: 'Task Updated', + value: 'taskUpdated', + key: 7, + }, + taskDeleted: { + name: 'Task Deleted', + value: 'taskDeleted', + key: 8, + }, + taskAssigned: { + name: 'Task Assigned', + value: 'taskAssigned', + key: 9, + }, + taskUnassigned: { + name: 'Task Unassigned', + value: 'taskUnassigned', + key: 10, + }, + taskDelayed: { + name: 'Task Delayed', + value: 'taskDelayed', + key: 12, + }, + taskCloned: { + name: 'Task Cloned', + value: 'taskCloned', + key: 13, + }, + smsRecipientResponseMissed: { + name: 'Sms Recipient Response Missed', + value: 'smsRecipientResponseMissed', + key: 14, + }, + workerCreated: { + name: 'Worker Created', + value: 'workerCreated', + key: 15, + }, + workerDeleted: { + name: 'Worker Deleted', + value: 'workerDeleted', + key: 16, + }, +}; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts new file mode 100644 index 0000000000000..3ba5431d7797a --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -0,0 +1,167 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const adminOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'admins', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet admin.', + }, + { + name: 'Remove', + value: 'delete', + description: 'Remove an Onfleet admin.', + }, + { + name: 'List', + value: 'get', + description: 'List all Onfleet admins.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet admin.', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +const adminNameField = { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'The administrator\'s complete name.', +} as INodeProperties; + +const adminEmailField = { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + description: 'The administrator\'s email address.', +} as INodeProperties; + +const adminPhoneField = { + displayName: 'Phone', + name: 'phone', + type: 'string', + default: '', + description: 'The administrator\'s phone number.', +} as INodeProperties; + +const adminReadOnlyField = { + displayName: 'Read only', + name: 'isReadOnly', + type: 'boolean', + default: false, + description: 'Whether this administrator can perform write operations.', +} as INodeProperties; + +export const adminFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'admins', + ], + }, + hide: { + operation: [ + 'create', 'get', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + displayOptions: { + show: { + resource: [ + 'admins', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + ...adminNameField, + }, + { + displayOptions: { + show: { + resource: [ + 'admins', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + ...adminEmailField, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'admins', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + adminPhoneField, + adminReadOnlyField, + ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'admins', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + adminNameField, + adminPhoneField, + adminReadOnlyField, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts new file mode 100644 index 0000000000000..70cccc592820f --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -0,0 +1,162 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const containerOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'containers', + ], + }, + }, + options: [ + { + name: 'Insert tasks', + value: 'add', + description: 'Insert tasks at index.', + }, + { + name: 'Update tasks', + value: 'update', + description: 'Fully replace a container\'s tasks.', + }, + { + name: 'Get container', + value: 'get', + description: 'Get container information.', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +const containerTypeField = { + displayName: 'Container', + name: 'containerType', + type: 'options', + options: [ + { name: 'Organizations', value: 'organizations' }, + { name: 'Teams', value: 'teams' }, + { name: 'Workers', value: 'workers' }, + ], + default: '', + description: 'Container type.', +} as INodeProperties; + +const containerIdField = { + displayName: 'ID', + name: 'containerId', + type: 'string', + default: '', + description: 'The object ID according to the container chosen.', +} as INodeProperties; + +const insertTypeField = { + displayName: 'Insert type', + name: 'type', + type: 'options', + options: [ + { name: 'Append', value: -1 }, + { name: 'Prepend', value: 0 }, + { name: 'At specific index', value: 1 }, + ], + default: '', + description: 'The index given indicates the position where the tasks are going to be inserted.', +} as INodeProperties; + +const indexField = { + displayName: 'Index', + name: 'index', + type: 'number', + default: '', + description: 'The index given indicates the position where the tasks are going to be inserted.', +} as INodeProperties; + +const tasksField = { + displayName: 'Tasks (JSON)', + name: 'tasks', + type: 'json', + default: '[]', + description: 'Array witht the task\'s ID that are going to be used in JSON format.', +} as INodeProperties; + +export const containerFields = [ + { + ...containerTypeField, + displayOptions: { + show: { + resource: [ + 'containers', + ], + operation: [ + 'get', 'add', 'update', + ], + }, + }, + required: true, + }, + { + ...containerIdField, + displayOptions: { + show: { + resource: [ + 'containers', + ], + operation: [ + 'get', 'add', 'update', + ], + }, + }, + required: true, + }, + { + ...insertTypeField, + displayOptions: { + show: { + resource: [ + 'containers', + ], + operation: [ + 'add', + ], + }, + }, + required: true, + }, + { + ...indexField, + displayOptions: { + show: { + resource: [ + 'containers', + ], + operation: [ + 'add', + ], + type: [ + 1, + ], + }, + }, + required: true, + }, + { + ...tasksField, + displayOptions: { + show: { + resource: [ + 'containers', + ], + operation: [ + 'add', 'update', + ], + }, + }, + required: true, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts new file mode 100644 index 0000000000000..2687052e36c0c --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -0,0 +1,389 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const destinationOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'destinations', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new destination.', + }, + { + name: 'Get', + value: 'get', + description: 'Get a specific destination.', + }, + + ], + default: 'get', + }, +] as INodeProperties[]; + +const unparsedField = { + displayName: 'Unparsed adress', + name: 'unparsed', + type: 'boolean', + description: 'Whether the address is specified in a single.', + default: false, +} as INodeProperties; + +const unparsedAddressField = { + displayName: 'Destination address', + name: 'address', + type: 'string', + description: 'The destination’s street address details.', + default: null, +} as INodeProperties; + +const unparsedAddressNumberField = { + displayName: 'Number', + name: 'addressNumber', + type: 'string', + description: 'The number component of this address, it may also contain letters.', + default: '', +} as INodeProperties; + +const unparsedAddressStreetField = { + displayName: 'Street', + name: 'addressStreet', + type: 'string', + description: 'The name of the street.', + default: '', +} as INodeProperties; + +const unparsedAddressCityField = { + displayName: 'City', + name: 'addressCity', + type: 'string', + description: 'The name of the municipality.', + default: '', +} as INodeProperties; + +const unparsedAddressCountryField = { + displayName: 'Country', + name: 'addressCountry', + type: 'string', + description: 'The name of the country.', + default: '', +} as INodeProperties; + +const addressNameField = { + displayName: 'Address name', + name: 'addressName', + type: 'string', + default: '', + description: 'A name associated with this address.', +} as INodeProperties; + +const addressApartmentField = { + displayName: 'Apartment', + name: 'addressApartment', + type: 'string', + default: '', + description: 'The suite or apartment number, or any additional relevant information.', +} as INodeProperties; + +const addressNoteField = { + displayName: 'Address notes', + name: 'addressNotes', + type: 'string', + default: '', + description: 'Notes about the destination.', +} as INodeProperties; + +const addressPostalCodeField = { + displayName: 'Postal code', + name: 'addressPostalCode', + type: 'string', + default: '', + description: 'The postal or zip code.', +} as INodeProperties; + +export const destinationFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'destinations', + ], + }, + hide: { + operation: [ + 'create', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + ...unparsedField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + }, + }, + required: true, + }, + { + ...unparsedAddressField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ true ], + }, + }, + required: true, + }, + { + ...unparsedAddressNumberField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressStreetField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCityField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCountryField, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + displayName: 'Additional destination fields', + name: 'additionalDestinationFields', + type: 'collection', + placeholder: 'Add destination fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ true ], + }, + }, + options: [ addressNameField, addressApartmentField, addressNoteField ], + }, + { + displayName: 'Additional destination fields', + name: 'additionalDestinationFields', + type: 'collection', + placeholder: 'Add destination fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', 'hubs', 'destinations', + ], + operation: [ + 'create', 'createBatch', + ], + unparsed: [ false, null ], + }, + }, + options: [ addressNameField, addressApartmentField, addressNoteField, addressPostalCodeField ], + }, + { + ...unparsedField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + }, + }, + required: true, + }, + { + ...unparsedAddressField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ true ], + }, + }, + required: true, + }, + { + ...unparsedAddressNumberField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressStreetField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCityField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCountryField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ false ], + }, + }, + required: true, + }, + { + displayName: 'Additional destination fields', + name: 'additionalDestinationFields', + type: 'collection', + placeholder: 'Add destination fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ true ], + }, + }, + options: [ addressNameField, addressApartmentField, addressNoteField ], + }, + { + displayName: 'Additional destination fields', + name: 'additionalDestinationFields', + type: 'collection', + placeholder: 'Add destination fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + unparsed: [ false, null ], + }, + }, + options: [ addressNameField, addressApartmentField, addressNoteField, addressPostalCodeField ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts new file mode 100644 index 0000000000000..e5b055382531b --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -0,0 +1,123 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const hubOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'hubs', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet hub.', + }, + { + name: 'List hubs', + value: 'getAll', + description: 'List Onfleet hubs.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet hub.', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +const nameField = { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'A name to identify the hub.', +} as INodeProperties; + +const teamsField = { + displayName: 'Teams (JSON)', + name: 'teams', + type: 'json', + default: '[]', + description: 'This is the team ID(s) that this Hub will be assigned to.', +} as INodeProperties; + +export const hubFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + ...nameField, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'create', + ], + }, + }, + options: [ teamsField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'hubs', + ], + operation: [ + 'update', + ], + }, + }, + options: [ nameField, teamsField ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts new file mode 100644 index 0000000000000..93217e5ae2b07 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts @@ -0,0 +1,17 @@ +import { + INodeProperties +} from 'n8n-workflow'; +import { webhookMapping } from '../WebhookMapping'; + +export const eventDisplay: INodeProperties = { + displayName: 'Event', + name: 'event', + type: 'options', + options: Object.keys(webhookMapping).map((webhook) => { + const {name, value} = webhookMapping[webhook]; + return {name, value}; + }), + required: true, + default: [], + description: 'The event to listen to.', +}; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts new file mode 100644 index 0000000000000..5eb02db77081d --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -0,0 +1,53 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const organizationOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'organizations', + ], + }, + }, + options: [ + { + name: 'Get details', + value: 'get', + description: 'Retrieve your own organization\'s details.', + }, + { + name: 'Get delegatee details', + value: 'getDelegatee', + description: 'Retrieve the details of an organization with which you are connected.', + }, + + ], + default: 'get', + }, +] as INodeProperties[]; + +export const organizationFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'organizations', + ], + operation: [ + 'getDelegatee', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the delegatees for lookup.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts new file mode 100644 index 0000000000000..7746864d1d139 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -0,0 +1,332 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const recipientOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet recipient.', + }, + { + name: 'Get', + value: 'get', + description: 'Get a specific Onfleet recipient.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet recipient.', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +const additionalRecipientFields = [ + { + displayName: 'Recipient notes', + name: 'recipientNotes', + type: 'string', + default: '', + description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific.', + }, + { + displayName: 'Skip recipient SMS notifications', + name: 'recipientSkipSMSNotifications', + type: 'boolean', + default: false, + description: 'Whether this recipient has requested to not receive SMS notifications.', + }, + { + displayName: 'Skip recipient phone number validation', + name: 'recipientSkipPhoneNumberValidation', + type: 'boolean', + default: false, + description: 'Whether to skip validation of this recipient\'s phone number.', + }, +]; + +const recipientName = { + displayName: 'Recipient name', + name: 'recipientName', + type: 'string', + description: 'The recipient\'s complete name.', +} as INodeProperties; + +const recipientPhone = { + displayName: 'Recipient phone', + name: 'recipientPhone', + type: 'string', + description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting.', +} as INodeProperties; + +const additionalRecipientFieldsUpdate = [ + recipientName, + recipientPhone, + { + displayName: 'Recipient notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific.', + }, + { + displayName: 'Skip recipient SMS notifications', + name: 'skipSMSNotifications', + type: 'boolean', + default: false, + description: 'Whether this recipient has requested to not receive SMS notifications.', + }, + { + displayName: 'Skip recipient phone number validation', + name: 'skipPhoneNumberValidation', + type: 'boolean', + default: false, + description: 'Whether to skip validation of this recipient\'s phone number.', + }, +]; + +export const recipientFields = [ + { + displayName: 'Get by', + name: 'getBy', + type: 'options', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'get', + ], + }, + }, + options: [ + { name: 'ID', value: 'id' }, + { name: 'Phone', value: 'phone' }, + { name: 'Name', value: 'name' }, + ], + description: 'Field which is used for looking up.', + required: true, + default: 'id', + }, + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ 'get' ], + getBy: [ 'id' ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ 'update' ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'get', + ], + getBy: [ + 'name', + ], + }, + }, + default: '', + required: true, + description: 'The Name for lookup.', + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'get', + ], + getBy: [ + 'phone', + ], + }, + }, + default: '', + required: true, + description: 'The Phone for lookup.', + }, + { + displayName: 'Recipient', + name: 'recipient', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'create', 'createBatch', + ], + }, + }, + description: 'Whether the task has a recipient associated.', + required: true, + default: true, + }, + { + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'create', 'createBatch', + ], + recipient: [ true, ], + }, + }, + ...recipientName, + required: true, + }, + { + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'create', + ], + }, + }, + ...recipientName, + required: true, + }, + { + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'create', 'createBatch', + ], + recipient: [ true, ], + }, + }, + ...recipientPhone, + required: true, + }, + { + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'create', + ], + }, + }, + ...recipientPhone, + required: true, + }, + { + displayName: 'Additional recipient fields', + name: 'additionalRecipientFields', + type: 'collection', + placeholder: 'Add recipient fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'create', + ], + }, + }, + options: additionalRecipientFields, + }, + { + displayName: 'Additional recipient fields', + name: 'additionalRecipientFields', + type: 'collection', + placeholder: 'Add recipient fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'create', 'createBatch', + ], + recipient: [ true, ], + }, + }, + options: additionalRecipientFields, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'recipients', + ], + operation: [ + 'update', + ], + }, + }, + options: additionalRecipientFieldsUpdate, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts new file mode 100644 index 0000000000000..6ce401bf5262e --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -0,0 +1,431 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const taskOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet task.', + }, + { + name: 'Add multiple tasks', + value: 'createBatch', + description: 'Add new Onfleet tasks.', + }, + { + name: 'Clone', + value: 'clone', + description: 'Clone an Onfleet task.', + }, + { + name: 'Complete', + value: 'complete', + description: 'Force-complete a started Onfleet task.', + }, + { + name: 'Remove', + value: 'delete', + description: 'Remove an Onfleet task.', + }, + { + name: 'List', + value: 'list', + description: 'List Onfleet tasks.', + }, + { + name: 'Get', + value: 'get', + description: 'Get a specific Onfleet task.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet task.', + }, + + ], + default: 'get', + }, +] as INodeProperties[]; + +export const taskFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + }, + hide: { + operation: [ + 'create', 'createBatch', 'list', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + displayName: 'Short ID', + name: 'shortId', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'get', + ], + }, + }, + required: true, + description: 'Whether the short ID is used for lookup.', + }, + { + displayName: 'From', + name: 'from', + type: 'dateTime', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'list', + ], + }, + }, + description: 'The starting time of the range. Tasks created or completed at or after this time will be included.', + required: true, + default: null, + }, + { + displayName: 'Success', + name: 'success', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'complete', + ], + }, + }, + description: 'Whether the task\'s completion was successful.', + required: true, + default: true, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'list', + ], + }, + }, + options: [ + { + displayName: 'To', + name: 'to', + type: 'dateTime', + default: null, + description: 'The ending time of the range. Defaults to current time if not specified.', + }, + { + displayName: 'State', + name: 'state', + type: 'multiOptions', + options: [ + { value: 0, name: 'Unassigned' }, + { value: 1, name: 'Assigned' }, + { value: 2, name: 'Active' }, + { value: 3, name: 'Completed' }, + ], + default: null, + description: 'The state of the tasks.', + }, + { + displayName: 'LastId', + name: 'lastId', + type: 'string', + default: null, + description: 'The last Id to walk the paginated response.', + }, + ], + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add options', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'clone', + ], + }, + }, + options: [ + { + displayName: 'Include Metadata', + name: 'includeMetadata', + type: 'boolean', + default: null, + }, + { + displayName: 'Include Barcodes', + name: 'includeBarcodes', + type: 'boolean', + default: null, + }, + { + displayName: 'Include Dependencies', + name: 'includeDependencies', + type: 'boolean', + default: null, + }, + { + displayName: 'Overrides', + name: 'overrides', + type: 'json', + default: null, + }, + ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Merchant ID', + name: 'merchant', + type: 'string', + default: '', + description: 'The ID of the organization that will be displayed to the recipient of the task.', + }, + { + displayName: 'Executor ID', + name: 'executor', + type: 'string', + default: '', + description: 'The ID of the organization that will be responsible for fulfilling the task.', + }, + { + displayName: 'CompleteAfter', + name: 'completeAfter', + type: 'dateTime', + default: null, + description: 'The earliest time the task should be completed.', + }, + { + displayName: 'CompleteBefore', + name: 'completeBefore', + type: 'dateTime', + default: null, + description: 'The latest time the task should be completed.', + }, + { + displayName: 'PickupTask', + name: 'pickupTask', + type: 'boolean', + default: false, + description: 'Whether the task is a pickup task.', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes for the task.', + }, + { + displayName: 'Quantity', + name: 'quantity', + type: 'number', + default: 0, + description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', + }, + { + displayName: 'Service Time', + name: 'serviceTime', + type: 'number', + default: 0, + description: 'The number of minutes to be spent by the worker on arrival at this task\s destination, for route optimization purposes.', + }, + ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'complete', + ], + }, + }, + options: [ + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes for the task.', + }, + ], + }, + { + displayName: 'Additional task fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'tasks', + ], + operation: [ + 'create', 'createBatch', + ], + }, + }, + options: [ + { + displayName: 'Merchant ID', + name: 'merchant', + type: 'string', + default: '', + description: 'The ID of the organization that will be displayed to the recipient of the task.', + }, + { + displayName: 'Executor ID', + name: 'executor', + type: 'string', + default: '', + description: 'The ID of the organization that will be responsible for fulfilling the task.', + }, + { + displayName: 'CompleteAfter', + name: 'completeAfter', + type: 'dateTime', + default: null, + description: 'The earliest time the task should be completed.', + }, + { + displayName: 'CompleteBefore', + name: 'completeBefore', + type: 'dateTime', + default: null, + description: 'The latest time the task should be completed.', + }, + { + displayName: 'PickupTask', + name: 'pickupTask', + type: 'boolean', + default: false, + description: 'Whether the task is a pickup task.', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes for the task.', + }, + { + displayName: 'Quantity', + name: 'quantity', + type: 'number', + default: 0, + description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', + }, + { + displayName: 'Service Time', + name: 'serviceTime', + type: 'number', + default: 0, + description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes.', + }, + { + displayName: 'Recipient Name Override', + name: 'recipientNameOverride', + type: 'string', + default: '', + description: 'Override the recipient name for this task only.', + }, + { + displayName: 'Recipient Notes Override', + name: 'recipientNotes', + type: 'string', + default: '', + description: 'Override the recipient notes for this task only.', + }, + { + displayName: 'Recipient Skip SMS Notifications Override', + name: 'recipientSkipSMSNotifications', + type: 'boolean', + default: '', + description: 'Override the recipient notification settings for this task only.', + }, + { + displayName: 'Use Merchant For Proxy Override', + name: 'useMerchantForProxy', + type: 'boolean', + default: '', + description: 'Override the organization ID to use the merchant orgID when set to true for this task only.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts new file mode 100644 index 0000000000000..4b19fd5f9fbab --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -0,0 +1,185 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const teamOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'teams', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet team.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet team.', + }, + { + name: 'Remove', + value: 'delete', + description: 'Remove an Onfleet team.', + }, + { + name: 'Get', + value: 'get', + description: 'Get a specific Onfleet team.', + }, + { + name: 'List', + value: 'getAll', + description: 'List all Onfleet teams.', + }, + ], + default: 'getAll', + }, +] as INodeProperties[]; + +const nameField = { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'A unique name for the team.', +} as INodeProperties; + +const workersField = { + displayName: 'Workers (JSON)', + name: 'workers', + type: 'json', + default: '[]', + description: 'An array of worker IDs.', +} as INodeProperties; + +const managersField = { + displayName: 'Managers (JSON)', + name: 'managers', + type: 'json', + default: '[]', + description: 'An array of managing administrators IDs.', +} as INodeProperties; + +const hubField = { + displayName: 'Hub', + name: 'hub', + type: 'string', + default: '', + description: 'The ID of the team\'s hub.', +} as INodeProperties; + +const enableSelfAssignmentField = { + displayName: 'Self assignment', + name: 'enableSelfAssignment', + type: 'boolean', + default: false, + description: 'This toggles Team Self-Assignment that allows Drivers to Self Assign Tasks that are in the Team unassigned container.', +} as INodeProperties; + +export const teamFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'get', 'update', 'delete', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + ...nameField, + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...workersField, + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...managersField, + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'create', + ], + }, + }, + options: [ hubField, enableSelfAssignmentField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'teams', + ], + operation: [ + 'update', + ], + }, + }, + options: [ nameField, workersField, managersField, hubField, enableSelfAssignmentField ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts new file mode 100644 index 0000000000000..7c8bb39518d1f --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -0,0 +1,153 @@ +import { + INodeProperties +} from 'n8n-workflow'; +import { webhookMapping } from '../WebhookMapping'; + +export const webhookOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Add new Onfleet webhook.', + }, + { + name: 'Remove', + value: 'delete', + description: 'Remove an Onfleet webhook.', + }, + { + name: 'List', + value: 'getAll', + description: 'List all Onfleet webhooks.', + }, + ], + default: 'getAll', + }, +] as INodeProperties[]; + +const urlField = { + displayName: 'Url', + name: 'url', + type: 'string', + default: '', + description: 'The URL that Onfleet should issue a request against as soon as the trigger condition is met. It must be HTTPS and have a valid certificate.', +} as INodeProperties; + +const nameField = { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'A name for the webhook for identification.', +} as INodeProperties; + +const triggerField = { + displayName: 'Trigger', + name: 'trigger', + type: 'options', + options: Object.keys(webhookMapping).map((name, value) => { + return { name, value }; + }), + default: '', + description: 'The number corresponding to the trigger condition on which the webhook should fire.', +} as INodeProperties; + +const thresholdField = { + displayName: 'Threshold', + name: 'threshold', + type: 'number', + default: '', + description: 'For trigger Task Eta, the time threshold in seconds; for trigger Task Arrival, the distance threshold in meters.', +} as INodeProperties; + +export const webhookFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + operation: [ + 'delete', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + ...urlField, + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...nameField, + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...triggerField, + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'webhooks', + ], + operation: [ + 'create', + ], + }, + }, + options: [ thresholdField ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts new file mode 100644 index 0000000000000..defbf61f60c44 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -0,0 +1,570 @@ +import { + INodeProperties +} from 'n8n-workflow'; + +export const workerOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'workers', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'create', + description: 'Create new Onfleet worker.', + }, + { + name: 'Remove', + value: 'delete', + description: 'Remove an Onfleet worker.', + }, + { + name: 'List', + value: 'getAll', + description: 'List all Onfleet workers.', + }, + { + name: 'List workers by location', + value: 'getAllLocation', + description: 'List all Onfleet workers who are currently within a centain target area.', + }, + { + name: 'Get', + value: 'get', + description: 'Get a specific Onfleet worker.', + }, + { + name: 'Get Schedule', + value: 'getSchedule', + description: 'Get a specific Onfleet worker schedule.', + }, + { + name: 'Set worker\'s schedule', + value: 'setSchedule', + description: 'Set the worker\'s schedule.', + }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet worker.', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +const nameField = { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'The worker’s complete name.', +} as INodeProperties; + +const phoneField = { + displayName: 'Phone', + name: 'phone', + type: 'string', + default: '', + description: 'A valid phone number as per the worker’s organization’s country.', +} as INodeProperties; + +const capacityField = { + displayName: 'Capacity', + name: 'capacity', + type: 'number', + default: 0, + description: 'The maximum number of units this worker can carry, for route optimization purposes.', +} as INodeProperties; + +const displayNameField = { + displayName: 'Display name', + name: 'displayName', + type: 'string', + default: '', + description: 'This value is used in place of the worker\'s actual name within sms notifications, delivery tracking pages, and across organization boundaries.', +} as INodeProperties; + +// Vehicles fields +const vehicleField = { + displayName: 'Vehicle', + name: 'vehicle', + type: 'boolean', + default: false, + description: 'Whether the worker has vehicle or not.', +} as INodeProperties; + +const vehicleTypeField = { + displayName: 'Type', + name: 'type', + type: 'options', + options: [ + { + name: 'Car', + value: 'CAR', + }, + { + name: 'Motorcycle', + value: 'MOTORCYCLE', + }, + { + name: 'Bicycle', + value: 'BICYCLE', + }, + { + name: 'Truck', + value: 'TRUCK', + }, + ], + default: 'CAR', + description: 'Whether the worker has vehicle or not.', +} as INodeProperties; + +const vehicleDescriptionField = { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'The vehicle\'s make, model, year, or any other relevant identifying details.', +} as INodeProperties; + +const vehicleLicensePlateField = { + displayName: 'License plate', + name: 'licensePlate', + type: 'string', + default: '', + description: 'The vehicle\'s license plate number.', +} as INodeProperties; + +const vehicleColorField = { + displayName: 'Color', + name: 'color', + type: 'string', + default: '', + description: 'The vehicle\'s color.', +} as INodeProperties; + +const teamsField = { + displayName: 'Teams (JSON)', + name: 'teams', + type: 'json', + default: '[]', + description: 'One or more team IDs of which the worker is a member.', +} as INodeProperties; + +const teamsFilterField = { + displayName: 'Teams', + name: 'teams', + type: 'string', + default: '', + description: 'A comma-separated list of the team IDs that workers must be part of.', +} as INodeProperties; + +const statesFilterField = { + displayName: 'States', + name: 'states', + type: 'multiOptions', + options: [ + { name: 'Off-duty', value: 0 }, + { name: 'Idle (on-duty, no active task)', value: 1 }, + { name: 'Active (on-duty, active task)', value: 2 }, + ], + default: '', + description: 'List of worker states.', +} as INodeProperties; + +const phonesFilterField = { + displayName: 'Phones', + name: 'phones', + type: 'string', + default: '', + description: 'A comma-separated list of workers\' phone numbers.', +} as INodeProperties; + +const filterField = { + displayName: 'List of fields to return', + name: 'filter', + type: 'string', + default: '', + description: 'A comma-separated list of fields to return, if all are not desired. For example, name, location.', +} as INodeProperties; + +const longitudFilterField = { + displayName: 'Longitude', + name: 'longitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The longitude component of the coordinate pair.', +} as INodeProperties; + +const latitudFilterField = { + displayName: 'Latitude', + name: 'latitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The latitude component of the coordinate pair.', +} as INodeProperties; + +const radiousFilterField = { + displayName: 'Radious', + name: 'radius', + type: 'number', + typeOptions: { + maxValue: 10000, + minValue: 0, + }, + default: 1000, + description: 'The length in meters of the radius of the spherical area in which to look for workers. Defaults to 1000 if missing. Maximum value is 10000.', +} as INodeProperties; + +const scheduleDateField = { + displayName: 'Date', + name: 'date', + type: 'dateTime', + default: Date.now(), + description: 'Schedule\'s date.', +} as INodeProperties; + +const scheduleTimezoneField = { + displayName: 'Timezone', + name: 'timezone', + type: 'string', + default: '', + description: 'A valid timezone.', +} as INodeProperties; + +const scheduleStartField = { + displayName: 'Start', + name: 'start', + type: 'dateTime', + default: Date.now(), + description: 'Start time.', +} as INodeProperties; + +const scheduleEndField = { + displayName: 'End', + name: 'end', + type: 'dateTime', + default: Date.now(), + description: 'End time.', +} as INodeProperties; + +export const workerFields = [ + { + displayName: 'ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'get', 'getSchedule', 'setSchedule', 'update', 'delete', + ], + }, + }, + default: '', + required: true, + description: 'The ID of the object for lookup.', + }, + { + displayName: 'Analytics', + name: 'analytics', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'get', + ], + }, + }, + default: true, + required: true, + description: 'A more detailed response.', + }, + { + ...nameField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...phoneField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...vehicleField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', 'update', + ], + }, + }, + required: true, + }, + { + ...vehicleTypeField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', 'update', + ], + vehicle: [ + true, + ], + }, + }, + required: true, + }, + { + ...teamsField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + ...longitudFilterField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'getAllLocation', + ], + }, + }, + required: true, + }, + { + ...latitudFilterField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'getAllLocation', + ], + }, + }, + required: true, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'getAllLocation', + ], + }, + }, + options: [ radiousFilterField ], + }, + { + displayName: 'Additional vehicle fields', + name: 'additionalVehicleFields', + type: 'collection', + placeholder: 'Add vehicle fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', 'update', + ], + vehicle: [ + true, + ], + }, + }, + options: [ vehicleDescriptionField, vehicleLicensePlateField, vehicleColorField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'create', + ], + }, + }, + options: [ capacityField, displayNameField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'update', + ], + }, + }, + options: [ nameField, capacityField, displayNameField, teamsField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ filterField, teamsFilterField, statesFilterField, phonesFilterField ], + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'get', + ], + }, + }, + options: [ filterField ], + }, + { + ...scheduleDateField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'setSchedule', + ], + }, + }, + required: true, + }, + { + ...scheduleTimezoneField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'setSchedule', + ], + }, + }, + required: true, + }, + { + ...scheduleStartField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'setSchedule', + ], + }, + }, + required: true, + }, + { + ...scheduleEndField, + displayOptions: { + show: { + resource: [ + 'workers', + ], + operation: [ + 'setSchedule', + ], + }, + }, + required: true, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/interfaces.ts b/packages/nodes-base/nodes/Onfleet/interfaces.ts new file mode 100644 index 0000000000000..226c1d8637761 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/interfaces.ts @@ -0,0 +1,157 @@ +export interface OnfleetRecipient { + name?: string; + phone?: string; + notes?: string; + skipSMSNotifications?: boolean; + skipPhoneNumberValidation?: boolean; +} + +export interface OnfleetDestinationAddress { + name?: string; + number?: string; + street?: string; + apartment?: string; + city?: string; + state?: string; + postalCode?: string; + country?: string; + unparsed?: string; +} + +export interface OnfleetDestinationOptions { + language?: string; +} + +export interface OnfleetDestination { + address: OnfleetDestinationAddress; + location?: [number, number]; + notes?: string; + options?: OnfleetDestinationOptions; +} + +export interface OnfleetTask { + merchant?: string; + executor?: string; + destination: OnfleetDestination; + recipients: OnfleetRecipient[]; + completeAfter?: number; + completeBefore?: number; + pickupTask?: boolean; + notes?: string; + quantity?: number; + serviceTime?: number; +} + +export interface OnfleetTaskUpdate { + merchant?: string; + executor?: string; + completeAfter?: number; + completeBefore?: number; + pickupTask?: boolean; + notes?: string; + quantity?: number; + serviceTime?: number; +} + +export interface OnfleetListTaskFilters { + from: number; + to?: number; + lastId?: string; + state?: string; + worker?: string; + completeBeforeBefore?: number; + completeAfterAfter?: number; + dependencies?: string; +} + +export interface OnfleetCloneTaskOptions { + includeMetadata?: boolean; + includeBarcodes?: boolean; + includeDependencies?: boolean; + overrides?: object; +} + +export interface OnfleetCloneTask { + options?: OnfleetCloneTaskOptions; +} + +export interface OnfleetTaskCompletionDetails { + success: boolean; + notes?: string; +} + +export interface OnfleetTaskComplete { + completionDetails: OnfleetTaskCompletionDetails; +} + +export interface OnfleetAdmins { + name?: string; + email?: string; + phone?: string; + isReadOnly?: boolean; +} + +export interface OnfleetHubs extends OnfleetDestination{ + name?: string; + teams?: string[]; +} + +export interface OnfleetVehicle { + type?: string; + description?: string; + licensePlate?: string; + color?: string; +} + +export interface OnfleetWorker { + name?: string; + phone?: string; + vehicle?: OnfleetVehicle; + teams?: string[]; + capacity?: number; + displayName?: string; +} + +export interface OnfleetWorkerFilter { + [key: string]: string | undefined; + filter?: string; + teams?: string; + states?: string; + phones?: string; + analytics?: string; +} + +export interface OnfleetWorkerScheduleEntry { + date?: string; + timezone?: string; + shifts?: [[number, number]]; +} + +export interface OnfleetWebhook { + url?: string; + name?: string; + trigger?: number; + threshold?: number; +} + +export interface OnfleetTeams { + name?: string; + workers?: string[]; + managers?: string[]; + hub?: string; + enableSelfAssignment?: boolean; +} + +export interface OnfleetWorkerSchedule { + entries: OnfleetWorkerScheduleEntry[]; +} + +export interface OnfleetWebhookMapping { + key: number; + name: string; + value: string; +} + +export interface OnfleetWebhooksMapping { + [key: string]: OnfleetWebhookMapping; +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 27092cca26f6f..27bcb481cdb26 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -204,6 +204,7 @@ "dist/credentials/OAuth1Api.credentials.js", "dist/credentials/OAuth2Api.credentials.js", "dist/credentials/OneSimpleApi.credentials.js", + "dist/credentials/OnfleetApi.credentials.js", "dist/credentials/OpenWeatherMapApi.credentials.js", "dist/credentials/OrbitApi.credentials.js", "dist/credentials/OuraApi.credentials.js", @@ -525,6 +526,8 @@ "dist/nodes/NextCloud/NextCloud.node.js", "dist/nodes/NocoDB/NocoDB.node.js", "dist/nodes/NoOp/NoOp.node.js", + "dist/nodes/Onfleet/Onfleet.node.js", + "dist/nodes/Onfleet/OnfleetTrigger.node.js", "dist/nodes/Notion/Notion.node.js", "dist/nodes/Notion/NotionTrigger.node.js", "dist/nodes/OneSimpleApi/OneSimpleApi.node.js", From 6d111c58b2b7762757b956aadfb7437779dd06bb Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Mon, 20 Dec 2021 10:53:19 -0500 Subject: [PATCH 02/12] style: fixed typos, arrays uniformity, unnecesary files --- .../nodes/Onfleet/Onfleet.node.json | 32 -- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 43 ++- .../nodes/Onfleet/OnfleetTrigger.node.json | 27 -- .../nodes/Onfleet/OnfleetTrigger.node.ts | 12 +- .../nodes/Onfleet/WebhookMapping.ts | 5 + .../descriptions/AdministratorDescription.ts | 53 +-- .../descriptions/ContainerDescription.ts | 98 +++--- .../descriptions/DestinationDescription.ts | 172 +++++----- .../Onfleet/descriptions/HubDescription.ts | 47 +-- .../descriptions/OrganizationDescription.ts | 12 +- .../descriptions/RecipientDescription.ts | 145 ++++----- .../Onfleet/descriptions/TaskDescription.ts | 303 ++++++++---------- .../Onfleet/descriptions/TeamDescription.ts | 75 ++--- .../descriptions/WebhookDescription.ts | 48 +-- .../Onfleet/descriptions/WorkerDescription.ts | 229 ++++++------- 15 files changed, 540 insertions(+), 761 deletions(-) delete mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.node.json delete mode 100644 packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.json b/packages/nodes-base/nodes/Onfleet/Onfleet.node.json deleted file mode 100644 index b88e2cda5be7c..0000000000000 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "node": "n8n-nodes-base.onfleet", - "nodeVersion": "1.0", - "codexVersion": "1.0", - "categories": [ - "Development" - ], - "resources": { - "credentialDocumentation": [ - { - "url": "https://docs.n8n.io/credentials/github" - } - ], - "primaryDocumentation": [ - { - "url": "https://docs.n8n.io/nodes/n8n-nodes-base.github/" - } - ], - "generic": [ - { - "label": "Automatically pulling and visualizing data with n8n", - "icon": "📈", - "url": "https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/" - }, - { - "label": "5 workflow automations for Mattermost that we love at n8n", - "icon": "🤖", - "url": "https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/" - } - ] - } -} diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index 0ec8ee6b049e6..e573dd8d2e054 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -24,13 +24,9 @@ import { } from './interfaces'; import { taskFields, taskOperations } from './descriptions/TaskDescription'; -import { - IExecuteFunctions, -} from 'n8n-core'; +import { IExecuteFunctions } from 'n8n-core'; import { destinationFields, destinationOperations } from './descriptions/DestinationDescription'; -import { - onfleetApiRequest, -} from './GenericFunctions'; +import { onfleetApiRequest } from './GenericFunctions'; import { recipientFields, recipientOperations } from './descriptions/RecipientDescription'; import { organizationFields, organizationOperations } from './descriptions/OrganizationDescription'; import { adminFields, adminOperations } from './descriptions/AdministratorDescription'; @@ -45,7 +41,7 @@ export class Onfleet implements INodeType { displayName: 'Onfleet', name: 'onfleet', icon: 'file:Onfleet.png', - group: ['input'], + group: [ 'input' ], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Onfleet API', @@ -53,8 +49,8 @@ export class Onfleet implements INodeType { name: 'Onfleet', color: '#AA81F3', }, - inputs: ['main'], - outputs: ['main'], + inputs: [ 'main' ], + outputs: [ 'main' ], credentials: [ { name: 'onfleetApi', @@ -488,7 +484,7 @@ export class Onfleet implements INodeType { if (optionFields.includeDependencies) options.includeDependencies = optionFields.includeDependencies as boolean; if (optionFields.overrides) options.overrides = optionFields.overrides as object; return { options } as OnfleetCloneTask; - } else if (operation === 'list') { + } else if (operation === 'getAll') { /* -------------------------------------------------------------------------- */ /* Get fields to list tasks */ /* -------------------------------------------------------------------------- */ @@ -595,14 +591,14 @@ export class Onfleet implements INodeType { try { if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add new task */ + /* Add a new task */ /* -------------------------------------------------------------------------- */ const taskData = Onfleet.getTaskFields.call(this, index, operation); if (!taskData) { continue ;} responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, taskData)); } else if (operation === 'get') { /* -------------------------------------------------------------------------- */ - /* Get a dingle task */ + /* Get a single task */ /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const shortId = this.getNodeParameter('shortId', index) as boolean; @@ -624,9 +620,9 @@ export class Onfleet implements INodeType { const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); - } else if (operation === 'list') { + } else if (operation === 'getAll') { /* -------------------------------------------------------------------------- */ - /* List tasks */ + /* Get all tasks */ /* -------------------------------------------------------------------------- */ const taskData = Onfleet.getTaskFields.call(this, 0, operation) as IDataObject; if (!taskData) return []; @@ -636,7 +632,7 @@ export class Onfleet implements INodeType { responseData.push(...tasks); } else if (operation === 'complete') { /* -------------------------------------------------------------------------- */ - /* Force to complete a task */ + /* Force complete a task */ /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const taskData = Onfleet.getTaskFields.call(this, index, operation); @@ -829,14 +825,14 @@ export class Onfleet implements INodeType { for (const key of Object.keys(items)) { const index = Number(key); try { - if (operation === 'get') { + if (operation === 'getAll') { /* -------------------------------------------------------------------------- */ - /* Get adiministrators */ + /* Get administrators */ /* -------------------------------------------------------------------------- */ responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add new admin */ + /* Add a new admin */ /* -------------------------------------------------------------------------- */ const adminData = Onfleet.getAdminFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, adminData)); @@ -894,7 +890,7 @@ export class Onfleet implements INodeType { responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add new hub */ + /* Add a new hub */ /* -------------------------------------------------------------------------- */ const hubData = Onfleet.getHubFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, hubData)); @@ -959,7 +955,7 @@ export class Onfleet implements INodeType { responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, workerFilters)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add new worker */ + /* Add a new worker */ /* -------------------------------------------------------------------------- */ const workerData = Onfleet.getWorkerFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, workerData)); @@ -985,7 +981,7 @@ export class Onfleet implements INodeType { const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}/schedule`; responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); - } else if (operation === 'getAllLocation') { + } else if (operation === 'getAllByLocation') { /* -------------------------------------------------------------------------- */ /* Get worker location */ /* -------------------------------------------------------------------------- */ @@ -1099,6 +1095,7 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const containerId = this.getNodeParameter('containerId', index) as string; const containerType = this.getNodeParameter('containerType', index) as string; + const considerDependencies = this.getNodeParameter('considerDependencies', index) as boolean; const tasks = JSON.parse(this.getNodeParameter('tasks', index) as string) as Array; if (operation === 'add') { @@ -1111,7 +1108,9 @@ export class Onfleet implements INodeType { } } const path = `${resource}/${containerType}/${containerId}`; - responseData.push(await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { tasks })); + responseData.push( + await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { tasks, considerDependencies }), + ); } } catch (error) { if (this.continueOnFail()) { diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json deleted file mode 100644 index 72b3c06048894..0000000000000 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "node": "n8n-nodes-base.onfleetTrigger", - "nodeVersion": "1.0", - "codexVersion": "1.0", - "categories": [ - "Development" - ], - "resources": { - "credentialDocumentation": [ - { - "url": "https://docs.n8n.io/credentials/onfleet" - } - ], - "primaryDocumentation": [ - { - "url": "https://docs.n8n.io/nodes/n8n-nodes-base.onfleetTrigger/" - } - ], - "generic": [ - { - "label": "5 workflow automations for Mattermost that we love at n8n", - "icon": "🤖", - "url": "https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/" - } - ] - } -} diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 6fabf1cf108b6..efa9b80879aa0 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -13,9 +13,7 @@ import { } from 'n8n-core'; import { eventDisplay } from './descriptions/OnfleetWebhookDescription'; -import { - onfleetApiRequest, -} from './GenericFunctions'; +import { onfleetApiRequest } from './GenericFunctions'; import { webhookMapping } from './WebhookMapping'; export class OnfleetTrigger implements INodeType { @@ -23,7 +21,7 @@ export class OnfleetTrigger implements INodeType { displayName: 'Onfleet Trigger', name: 'onfleetTrigger', icon: 'file:Onfleet.png', - group: ['trigger'], + group: [ 'trigger' ], version: 1, subtitle: '={{$parameter["events"]}}', description: 'Starts the workflow when Onfleet events occur.', @@ -32,7 +30,7 @@ export class OnfleetTrigger implements INodeType { color: '#AA81F3', }, inputs: [], - outputs: ['main'], + outputs: [ 'main' ], credentials: [ { name: 'onfleetApi', @@ -124,7 +122,7 @@ export class OnfleetTrigger implements INodeType { } catch (error) { const { httpCode = '' } = error as { httpCode: string }; if (httpCode === '422') { - // Webhook exi`sts already + // Webhook exists already // Get the data of the already registered webhook onfleetApiRequest.call(this, 'GET', encodedApiKey, path) @@ -133,7 +131,7 @@ export class OnfleetTrigger implements INodeType { webhookData[event] = webhook!.id; return Promise.resolve(true); }); - throw new NodeOperationError(this.getNode(), 'A webhook with the identical URL probably exists already. Please delete it manually on Onfleet!'); + throw new NodeOperationError(this.getNode(), 'A webhook with the identical URL probably exists already. Please delete it manually in Onfleet!'); } throw error; diff --git a/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts b/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts index 84a60333ab1bb..85eec4d016cfa 100644 --- a/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts +++ b/packages/nodes-base/nodes/Onfleet/WebhookMapping.ts @@ -81,4 +81,9 @@ export const webhookMapping: OnfleetWebhooksMapping = { value: 'workerDeleted', key: 16, }, + SMSRecipientOptOut: { + name: 'SMS Recipient Opt Out', + value: 'SMSRecipientOptOut', + key: 17, + }, }; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts index 3ba5431d7797a..c79660da910a6 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -9,16 +9,14 @@ export const adminOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'admins', - ], + resource: [ 'admins' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new Onfleet admin.', + description: 'Add a new Onfleet admin.', }, { name: 'Remove', @@ -27,7 +25,7 @@ export const adminOperations = [ }, { name: 'List', - value: 'get', + value: 'getAll', description: 'List all Onfleet admins.', }, { @@ -36,7 +34,7 @@ export const adminOperations = [ description: 'Update an Onfleet admin.', }, ], - default: 'get', + default: 'getAll', }, ] as INodeProperties[]; @@ -45,7 +43,7 @@ const adminNameField = { name: 'name', type: 'string', default: '', - description: 'The administrator\'s complete name.', + description: 'The administrator\'s name.', } as INodeProperties; const adminEmailField = { @@ -79,29 +77,24 @@ export const adminFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'admins', - ], + resource: [ 'admins' ], }, hide: { operation: [ - 'create', 'get', + 'create', + 'getAll', ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the admin object for lookup.', }, { displayOptions: { show: { - resource: [ - 'admins', - ], - operation: [ - 'create', - ], + resource: [ 'admins' ], + operation: [ 'create' ], }, }, required: true, @@ -110,12 +103,8 @@ export const adminFields = [ { displayOptions: { show: { - resource: [ - 'admins', - ], - operation: [ - 'create', - ], + resource: [ 'admins' ], + operation: [ 'create' ], }, }, required: true, @@ -129,12 +118,8 @@ export const adminFields = [ default: {}, displayOptions: { show: { - resource: [ - 'admins', - ], - operation: [ - 'create', - ], + resource: [ 'admins' ], + operation: [ 'create' ], }, }, options: [ @@ -150,12 +135,8 @@ export const adminFields = [ default: {}, displayOptions: { show: { - resource: [ - 'admins', - ], - operation: [ - 'update', - ], + resource: [ 'admins' ], + operation: [ 'update' ], }, }, options: [ diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts index 70cccc592820f..43821c0d324a1 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -9,16 +9,14 @@ export const containerOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'containers', - ], + resource: [ 'containers' ], }, }, options: [ { - name: 'Insert tasks', + name: 'Insert tasks (or append)', value: 'add', - description: 'Insert tasks at index.', + description: 'Insert tasks at index (or append).', }, { name: 'Update tasks', @@ -40,9 +38,18 @@ const containerTypeField = { name: 'containerType', type: 'options', options: [ - { name: 'Organizations', value: 'organizations' }, - { name: 'Teams', value: 'teams' }, - { name: 'Workers', value: 'workers' }, + { + name: 'Organizations', + value: 'organizations', + }, + { + name: 'Teams', + value: 'teams', + }, + { + name: 'Workers', + value: 'workers', + }, ], default: '', description: 'Container type.', @@ -61,9 +68,18 @@ const insertTypeField = { name: 'type', type: 'options', options: [ - { name: 'Append', value: -1 }, - { name: 'Prepend', value: 0 }, - { name: 'At specific index', value: 1 }, + { + name: 'Append', + value: -1, + }, + { + name: 'Prepend', + value: 0, + }, + { + name: 'At specific index', + value: 1, + }, ], default: '', description: 'The index given indicates the position where the tasks are going to be inserted.', @@ -85,16 +101,24 @@ const tasksField = { description: 'Array witht the task\'s ID that are going to be used in JSON format.', } as INodeProperties; +const considerDependenciesField = { + displayName: 'Consider dependencies', + name: 'considerDependencies', + type: 'boolean', + default: false, + description: 'Whether to include the target task\'s dependency family (parent and child tasks) in the resulting assignment operation.', +} as INodeProperties; + export const containerFields = [ { ...containerTypeField, displayOptions: { show: { - resource: [ - 'containers', - ], + resource: [ 'containers' ], operation: [ - 'get', 'add', 'update', + 'get', + 'add', + 'update', ], }, }, @@ -104,11 +128,11 @@ export const containerFields = [ ...containerIdField, displayOptions: { show: { - resource: [ - 'containers', - ], + resource: [ 'containers' ], operation: [ - 'get', 'add', 'update', + 'get', + 'add', + 'update', ], }, }, @@ -118,12 +142,8 @@ export const containerFields = [ ...insertTypeField, displayOptions: { show: { - resource: [ - 'containers', - ], - operation: [ - 'add', - ], + resource: [ 'containers' ], + operation: [ 'add' ], }, }, required: true, @@ -132,28 +152,34 @@ export const containerFields = [ ...indexField, displayOptions: { show: { - resource: [ - 'containers', - ], + resource: [ 'containers' ], + operation: [ 'add' ], + type: [ 1 ], + }, + }, + required: true, + }, + { + ...tasksField, + displayOptions: { + show: { + resource: [ 'containers' ], operation: [ 'add', - ], - type: [ - 1, + 'update', ], }, }, required: true, }, { - ...tasksField, + ...considerDependenciesField, displayOptions: { show: { - resource: [ - 'containers', - ], + resource: [ 'containers' ], operation: [ - 'add', 'update', + 'add', + 'update', ], }, }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 2687052e36c0c..079f7c39610f7 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -9,16 +9,14 @@ export const destinationOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'destinations', - ], + resource: [ 'destinations' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new destination.', + description: 'Add a new destination.', }, { name: 'Get', @@ -43,7 +41,7 @@ const unparsedAddressField = { displayName: 'Destination address', name: 'address', type: 'string', - description: 'The destination’s street address details.', + description: 'The destination\'s street address details.', default: null, } as INodeProperties; @@ -118,29 +116,28 @@ export const destinationFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'destinations', - ], + resource: [ 'destinations' ], }, hide: { - operation: [ - 'create', - ], + operation: [ 'create' ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the destination object for lookup.', }, { ...unparsedField, displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], }, }, @@ -151,10 +148,13 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ true ], }, @@ -166,10 +166,13 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ false ], }, @@ -181,10 +184,13 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ false ], }, @@ -196,10 +202,13 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ false ], }, @@ -211,10 +220,13 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ false ], }, @@ -230,15 +242,22 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], unparsed: [ true ], }, }, - options: [ addressNameField, addressApartmentField, addressNoteField ], + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + ], }, { displayName: 'Additional destination fields', @@ -249,26 +268,33 @@ export const destinationFields = [ displayOptions: { show: { resource: [ - 'tasks', 'hubs', 'destinations', + 'tasks', + 'hubs', + 'destinations', ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', + ], + unparsed: [ + false, + null, ], - unparsed: [ false, null ], }, }, - options: [ addressNameField, addressApartmentField, addressNoteField, addressPostalCodeField ], + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + addressPostalCodeField, + ], }, { ...unparsedField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], }, }, required: true, @@ -277,12 +303,8 @@ export const destinationFields = [ ...unparsedAddressField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ true ], }, }, @@ -292,12 +314,8 @@ export const destinationFields = [ ...unparsedAddressNumberField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ false ], }, }, @@ -307,12 +325,8 @@ export const destinationFields = [ ...unparsedAddressStreetField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ false ], }, }, @@ -322,12 +336,8 @@ export const destinationFields = [ ...unparsedAddressCityField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ false ], }, }, @@ -337,12 +347,8 @@ export const destinationFields = [ ...unparsedAddressCountryField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ false ], }, }, @@ -356,16 +362,16 @@ export const destinationFields = [ default: {}, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], unparsed: [ true ], }, }, - options: [ addressNameField, addressApartmentField, addressNoteField ], + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + ], }, { displayName: 'Additional destination fields', @@ -375,15 +381,19 @@ export const destinationFields = [ default: {}, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', + resource: [ 'hubs' ], + operation: [ 'update' ], + unparsed: [ + false, + null, ], - unparsed: [ false, null ], }, }, - options: [ addressNameField, addressApartmentField, addressNoteField, addressPostalCodeField ], + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + addressPostalCodeField, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index e5b055382531b..634decafb51bd 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -9,16 +9,14 @@ export const hubOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'hubs', - ], + resource: [ 'hubs' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new Onfleet hub.', + description: 'Add a new Onfleet hub.', }, { name: 'List hubs', @@ -58,28 +56,20 @@ export const hubFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the hub object for lookup.', }, { ...nameField, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'create', - ], + resource: [ 'hubs' ], + operation: [ 'create' ], }, }, required: true, @@ -92,12 +82,8 @@ export const hubFields = [ default: {}, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'create', - ], + resource: [ 'hubs' ], + operation: [ 'create' ], }, }, options: [ teamsField ], @@ -110,14 +96,13 @@ export const hubFields = [ default: {}, displayOptions: { show: { - resource: [ - 'hubs', - ], - operation: [ - 'update', - ], + resource: [ 'hubs' ], + operation: [ 'update' ], }, - }, - options: [ nameField, teamsField ], + }, + options: [ + nameField, + teamsField, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts index 5eb02db77081d..123372c8c67a6 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -9,9 +9,7 @@ export const organizationOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'organizations', - ], + resource: [ 'organizations' ], }, }, options: [ @@ -38,12 +36,8 @@ export const organizationFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'organizations', - ], - operation: [ - 'getDelegatee', - ], + resource: [ 'organizations' ], + operation: [ 'getDelegatee' ], }, }, default: '', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index 7746864d1d139..71be41c7e84df 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -9,16 +9,14 @@ export const recipientOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'recipients', - ], + resource: [ 'recipients' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new Onfleet recipient.', + description: 'Add a new Onfleet recipient.', }, { name: 'Get', @@ -48,14 +46,14 @@ const additionalRecipientFields = [ name: 'recipientSkipSMSNotifications', type: 'boolean', default: false, - description: 'Whether this recipient has requested to not receive SMS notifications.', + description: 'Whether this recipient has requested to skip SMS notifications.', }, { displayName: 'Skip recipient phone number validation', name: 'recipientSkipPhoneNumberValidation', type: 'boolean', default: false, - description: 'Whether to skip validation of this recipient\'s phone number.', + description: 'Whether to skip validation for this recipient\'s phone number.', }, ]; @@ -88,14 +86,14 @@ const additionalRecipientFieldsUpdate = [ name: 'skipSMSNotifications', type: 'boolean', default: false, - description: 'Whether this recipient has requested to not receive SMS notifications.', + description: 'Whether this recipient has requested to skip SMS notifications.', }, { displayName: 'Skip recipient phone number validation', name: 'skipPhoneNumberValidation', type: 'boolean', default: false, - description: 'Whether to skip validation of this recipient\'s phone number.', + description: 'Whether to skip validation for this recipient\'s phone number.', }, ]; @@ -106,20 +104,25 @@ export const recipientFields = [ type: 'options', displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'get', - ], + resource: [ 'recipients' ], + operation: [ 'get' ], }, }, options: [ - { name: 'ID', value: 'id' }, - { name: 'Phone', value: 'phone' }, - { name: 'Name', value: 'name' }, + { + name: 'ID', + value: 'id', + }, + { + name: 'Phone', + value: 'phone', + }, + { + name: 'Name', + value: 'name', + }, ], - description: 'Field which is used for looking up.', + description: 'The variable that is used for looking up a recipient.', required: true, default: 'id', }, @@ -129,16 +132,14 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'recipients', - ], + resource: [ 'recipients' ], operation: [ 'get' ], getBy: [ 'id' ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the recipient object for lookup.', }, { displayName: 'ID', @@ -146,15 +147,13 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'recipients', - ], + resource: [ 'recipients' ], operation: [ 'update' ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the recipient object for lookup.', }, { displayName: 'Name', @@ -162,20 +161,14 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'get', - ], - getBy: [ - 'name', - ], + resource: [ 'recipients' ], + operation: [ 'get' ], + getBy: [ 'name' ], }, }, default: '', required: true, - description: 'The Name for lookup.', + description: 'The name of the recipient for lookup.', }, { displayName: 'Phone', @@ -183,20 +176,14 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'get', - ], - getBy: [ - 'phone', - ], + resource: [ 'recipients' ], + operation: [ 'get' ], + getBy: [ 'phone' ], }, }, default: '', required: true, - description: 'The Phone for lookup.', + description: 'The phone of the recipient for lookup.', }, { displayName: 'Recipient', @@ -204,11 +191,10 @@ export const recipientFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], }, }, @@ -219,13 +205,12 @@ export const recipientFields = [ { displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], - recipient: [ true, ], + recipient: [ true ], }, }, ...recipientName, @@ -234,12 +219,8 @@ export const recipientFields = [ { displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'create', - ], + resource: [ 'recipients' ], + operation: [ 'create' ], }, }, ...recipientName, @@ -248,13 +229,12 @@ export const recipientFields = [ { displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], - recipient: [ true, ], + recipient: [ true ], }, }, ...recipientPhone, @@ -263,12 +243,8 @@ export const recipientFields = [ { displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'create', - ], + resource: [ 'recipients' ], + operation: ['create' ], }, }, ...recipientPhone, @@ -282,12 +258,8 @@ export const recipientFields = [ default: {}, displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'create', - ], + resource: [ 'recipients' ], + operation: [ 'create' ], }, }, options: additionalRecipientFields, @@ -300,13 +272,12 @@ export const recipientFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], - recipient: [ true, ], + recipient: [ true ], }, }, options: additionalRecipientFields, @@ -319,12 +290,8 @@ export const recipientFields = [ default: {}, displayOptions: { show: { - resource: [ - 'recipients', - ], - operation: [ - 'update', - ], + resource: [ 'recipients' ], + operation: [ 'update' ], }, }, options: additionalRecipientFieldsUpdate, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 6ce401bf5262e..8d923a964a4f8 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -9,21 +9,19 @@ export const taskOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], }, }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add new Onfleet task.', + description: 'Create a new Onfleet task.', }, { - name: 'Add multiple tasks', + name: 'Create multiple tasks', value: 'createBatch', - description: 'Add new Onfleet tasks.', + description: 'Creating multiple tasks in batch.', }, { name: 'Clone', @@ -42,7 +40,7 @@ export const taskOperations = [ }, { name: 'List', - value: 'list', + value: 'getAll', description: 'List Onfleet tasks.', }, { @@ -61,6 +59,70 @@ export const taskOperations = [ }, ] as INodeProperties[]; +const merchantIdField = { + displayName: 'Merchant ID', + name: 'merchant', + type: 'string', + default: '', + description: 'The ID of the organization that will be displayed to the recipient of the task.', +} as INodeProperties; + +const executorIdField = { + displayName: 'Executor ID', + name: 'executor', + type: 'string', + default: '', + description: 'The ID of the organization that will be responsible for fulfilling the task.', +} as INodeProperties; + +const completeAfterField = { + displayName: 'CompleteAfter', + name: 'completeAfter', + type: 'dateTime', + default: null, + description: 'The earliest time the task should be completed.', +} as INodeProperties; + +const completeBeforeField = { + displayName: 'CompleteBefore', + name: 'completeBefore', + type: 'dateTime', + default: null, + description: 'The latest time the task should be completed.', +} as INodeProperties; + +const pickupTaskField = { + displayName: 'PickupTask', + name: 'pickupTask', + type: 'boolean', + default: false, + description: 'Whether the task is a pickup task.', +} as INodeProperties; + +const notesField = { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + description: 'Notes for the task.', +} as INodeProperties; + +const quantityField = { + displayName: 'Quantity', + name: 'quantity', + type: 'number', + default: 0, + description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', +} as INodeProperties; + +const serviceTimeField = { + displayName: 'Service Time', + name: 'serviceTime', + type: 'number', + default: 0, + description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes.', +} as INodeProperties; + export const taskFields = [ { displayName: 'ID', @@ -68,19 +130,19 @@ export const taskFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], }, hide: { operation: [ - 'create', 'createBatch', 'list', + 'create', + 'createBatch', + 'getAll', ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the task object for lookup.', }, { displayName: 'Short ID', @@ -88,16 +150,12 @@ export const taskFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'get', - ], + resource: [ 'tasks' ], + operation: [ 'get' ], }, }, required: true, - description: 'Whether the short ID is used for lookup.', + description: 'Whether the task short ID is used for lookup.', }, { displayName: 'From', @@ -105,12 +163,8 @@ export const taskFields = [ type: 'dateTime', displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'list', - ], + resource: [ 'tasks' ], + operation: [ 'getAll' ], }, }, description: 'The starting time of the range. Tasks created or completed at or after this time will be included.', @@ -123,12 +177,8 @@ export const taskFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'complete', - ], + resource: [ 'tasks' ], + operation: [ 'complete' ], }, }, description: 'Whether the task\'s completion was successful.', @@ -143,12 +193,8 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'list', - ], + resource: [ 'tasks' ], + operation: [ 'getAll' ], }, }, options: [ @@ -164,10 +210,22 @@ export const taskFields = [ name: 'state', type: 'multiOptions', options: [ - { value: 0, name: 'Unassigned' }, - { value: 1, name: 'Assigned' }, - { value: 2, name: 'Active' }, - { value: 3, name: 'Completed' }, + { + name: 'Unassigned', + value: 0, + }, + { + name: 'Assigned', + value: 1, + }, + { + name: 'Active', + value: 2, + }, + { + name: 'Completed', + value: 3, + }, ], default: null, description: 'The state of the tasks.', @@ -189,12 +247,8 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'clone', - ], + resource: [ 'tasks' ], + operation: [ 'clone' ], }, }, options: [ @@ -232,71 +286,19 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'update', - ], + resource: [ 'tasks' ], + operation: [ 'update' ], }, }, options: [ - { - displayName: 'Merchant ID', - name: 'merchant', - type: 'string', - default: '', - description: 'The ID of the organization that will be displayed to the recipient of the task.', - }, - { - displayName: 'Executor ID', - name: 'executor', - type: 'string', - default: '', - description: 'The ID of the organization that will be responsible for fulfilling the task.', - }, - { - displayName: 'CompleteAfter', - name: 'completeAfter', - type: 'dateTime', - default: null, - description: 'The earliest time the task should be completed.', - }, - { - displayName: 'CompleteBefore', - name: 'completeBefore', - type: 'dateTime', - default: null, - description: 'The latest time the task should be completed.', - }, - { - displayName: 'PickupTask', - name: 'pickupTask', - type: 'boolean', - default: false, - description: 'Whether the task is a pickup task.', - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes for the task.', - }, - { - displayName: 'Quantity', - name: 'quantity', - type: 'number', - default: 0, - description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', - }, - { - displayName: 'Service Time', - name: 'serviceTime', - type: 'number', - default: 0, - description: 'The number of minutes to be spent by the worker on arrival at this task\s destination, for route optimization purposes.', - }, + merchantIdField, + executorIdField, + completeAfterField, + completeBeforeField, + pickupTaskField, + notesField, + quantityField, + serviceTimeField, ], }, { @@ -307,12 +309,8 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], - operation: [ - 'complete', - ], + resource: [ 'tasks' ], + operation: [ 'complete' ], }, }, options: [ @@ -321,7 +319,7 @@ export const taskFields = [ name: 'notes', type: 'string', default: '', - description: 'Notes for the task.', + description: 'Completion Notes.', }, ], }, @@ -333,71 +331,22 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ - 'tasks', - ], + resource: [ 'tasks' ], operation: [ - 'create', 'createBatch', + 'create', + 'createBatch', ], }, }, options: [ - { - displayName: 'Merchant ID', - name: 'merchant', - type: 'string', - default: '', - description: 'The ID of the organization that will be displayed to the recipient of the task.', - }, - { - displayName: 'Executor ID', - name: 'executor', - type: 'string', - default: '', - description: 'The ID of the organization that will be responsible for fulfilling the task.', - }, - { - displayName: 'CompleteAfter', - name: 'completeAfter', - type: 'dateTime', - default: null, - description: 'The earliest time the task should be completed.', - }, - { - displayName: 'CompleteBefore', - name: 'completeBefore', - type: 'dateTime', - default: null, - description: 'The latest time the task should be completed.', - }, - { - displayName: 'PickupTask', - name: 'pickupTask', - type: 'boolean', - default: false, - description: 'Whether the task is a pickup task.', - }, - { - displayName: 'Notes', - name: 'notes', - type: 'string', - default: '', - description: 'Notes for the task.', - }, - { - displayName: 'Quantity', - name: 'quantity', - type: 'number', - default: 0, - description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', - }, - { - displayName: 'Service Time', - name: 'serviceTime', - type: 'number', - default: 0, - description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes.', - }, + merchantIdField, + executorIdField, + completeAfterField, + completeBeforeField, + pickupTaskField, + notesField, + quantityField, + serviceTimeField, { displayName: 'Recipient Name Override', name: 'recipientNameOverride', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index 4b19fd5f9fbab..c171901970ae7 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -9,16 +9,14 @@ export const teamOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'teams', - ], + resource: [ 'teams' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new Onfleet team.', + description: 'Add a new Onfleet team.', }, { name: 'Update', @@ -58,15 +56,15 @@ const workersField = { name: 'workers', type: 'json', default: '[]', - description: 'An array of worker IDs.', + description: 'An array of workers IDs.', } as INodeProperties; const managersField = { - displayName: 'Managers (JSON)', + displayName: 'Administrators (JSON)', name: 'managers', type: 'json', default: '[]', - description: 'An array of managing administrators IDs.', + description: 'An array of managing administrator IDs.', } as INodeProperties; const hubField = { @@ -92,28 +90,24 @@ export const teamFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'teams', - ], + resource: [ 'teams' ], operation: [ - 'get', 'update', 'delete', + 'get', + 'update', + 'delete', ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the team object for lookup.', }, { ...nameField, displayOptions: { show: { - resource: [ - 'teams', - ], - operation: [ - 'create', - ], + resource: [ 'teams' ], + operation: [ 'create' ], }, }, required: true, @@ -122,12 +116,8 @@ export const teamFields = [ ...workersField, displayOptions: { show: { - resource: [ - 'teams', - ], - operation: [ - 'create', - ], + resource: [ 'teams' ], + operation: [ 'create' ], }, }, required: true, @@ -136,12 +126,8 @@ export const teamFields = [ ...managersField, displayOptions: { show: { - resource: [ - 'teams', - ], - operation: [ - 'create', - ], + resource: [ 'teams' ], + operation: [ 'create' ], }, }, required: true, @@ -154,15 +140,14 @@ export const teamFields = [ default: {}, displayOptions: { show: { - resource: [ - 'teams', - ], - operation: [ - 'create', - ], + resource: [ 'teams' ], + operation: [ 'create' ], }, }, - options: [ hubField, enableSelfAssignmentField ], + options: [ + hubField, + enableSelfAssignmentField, + ], }, { displayName: 'Additional fields', @@ -172,14 +157,16 @@ export const teamFields = [ default: {}, displayOptions: { show: { - resource: [ - 'teams', - ], - operation: [ - 'update', - ], + resource: [ 'teams' ], + operation: [ 'update' ], }, }, - options: [ nameField, workersField, managersField, hubField, enableSelfAssignmentField ], + options: [ + nameField, + workersField, + managersField, + hubField, + enableSelfAssignmentField, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts index 7c8bb39518d1f..20cfcdccd903c 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -10,16 +10,14 @@ export const webhookOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'webhooks', - ], + resource: [ 'webhooks' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Add new Onfleet webhook.', + description: 'Add a new Onfleet webhook.', }, { name: 'Remove', @@ -78,28 +76,20 @@ export const webhookFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'webhooks', - ], - operation: [ - 'delete', - ], + resource: [ 'webhooks' ], + operation: [ 'delete' ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the webhook object for lookup.', }, { ...urlField, displayOptions: { show: { - resource: [ - 'webhooks', - ], - operation: [ - 'create', - ], + resource: [ 'webhooks' ], + operation: [ 'create' ], }, }, required: true, @@ -108,12 +98,8 @@ export const webhookFields = [ ...nameField, displayOptions: { show: { - resource: [ - 'webhooks', - ], - operation: [ - 'create', - ], + resource: [ 'webhooks' ], + operation: [ 'create' ], }, }, required: true, @@ -122,12 +108,8 @@ export const webhookFields = [ ...triggerField, displayOptions: { show: { - resource: [ - 'webhooks', - ], - operation: [ - 'create', - ], + resource: [ 'webhooks' ], + operation: [ 'create' ], }, }, required: true, @@ -140,12 +122,8 @@ export const webhookFields = [ default: {}, displayOptions: { show: { - resource: [ - 'webhooks', - ], - operation: [ - 'create', - ], + resource: [ 'webhooks' ], + operation: [ 'create' ], }, }, options: [ thresholdField ], diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index defbf61f60c44..66c47236ad84d 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -9,16 +9,14 @@ export const workerOperations = [ type: 'options', displayOptions: { show: { - resource: [ - 'workers', - ], + resource: [ 'workers' ], }, }, options: [ { name: 'Add', value: 'create', - description: 'Create new Onfleet worker.', + description: 'Create a new Onfleet worker.', }, { name: 'Remove', @@ -32,7 +30,7 @@ export const workerOperations = [ }, { name: 'List workers by location', - value: 'getAllLocation', + value: 'getAllByLocation', description: 'List all Onfleet workers who are currently within a centain target area.', }, { @@ -65,7 +63,7 @@ const nameField = { name: 'name', type: 'string', default: '', - description: 'The worker’s complete name.', + description: 'The worker\'s name.', } as INodeProperties; const phoneField = { @@ -73,7 +71,7 @@ const phoneField = { name: 'phone', type: 'string', default: '', - description: 'A valid phone number as per the worker’s organization’s country.', + description: 'A valid phone number as per the worker\'s organization\'s country.', } as INodeProperties; const capacityField = { @@ -172,9 +170,18 @@ const statesFilterField = { name: 'states', type: 'multiOptions', options: [ - { name: 'Off-duty', value: 0 }, - { name: 'Idle (on-duty, no active task)', value: 1 }, - { name: 'Active (on-duty, active task)', value: 2 }, + { + name: 'Off-duty', + value: 0, + }, + { + name: 'Idle (on-duty, no active task)', + value: 1, + }, + { + name: 'Active (on-duty, active task)', + value: 2, + }, ], default: '', description: 'List of worker states.', @@ -196,7 +203,7 @@ const filterField = { description: 'A comma-separated list of fields to return, if all are not desired. For example, name, location.', } as INodeProperties; -const longitudFilterField = { +const longitudeFilterField = { displayName: 'Longitude', name: 'longitude', type: 'number', @@ -207,7 +214,7 @@ const longitudFilterField = { description: 'The longitude component of the coordinate pair.', } as INodeProperties; -const latitudFilterField = { +const latitudeFilterField = { displayName: 'Latitude', name: 'latitude', type: 'number', @@ -218,8 +225,8 @@ const latitudFilterField = { description: 'The latitude component of the coordinate pair.', } as INodeProperties; -const radiousFilterField = { - displayName: 'Radious', +const radiusFilterField = { + displayName: 'Radius', name: 'radius', type: 'number', typeOptions: { @@ -269,17 +276,19 @@ export const workerFields = [ type: 'string', displayOptions: { show: { - resource: [ - 'workers', - ], + resource: [ 'workers' ], operation: [ - 'get', 'getSchedule', 'setSchedule', 'update', 'delete', + 'get', + 'getSchedule', + 'setSchedule', + 'update', + 'delete', ], }, }, default: '', required: true, - description: 'The ID of the object for lookup.', + description: 'The ID of the worker object for lookup.', }, { displayName: 'Analytics', @@ -287,28 +296,20 @@ export const workerFields = [ type: 'boolean', displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'get', - ], + resource: [ 'workers' ], + operation: [ 'get' ], }, }, default: true, required: true, - description: 'A more detailed response.', + description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics.', }, { ...nameField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'create', - ], + resource: [ 'workers' ], + operation: [ 'create' ], }, }, required: true, @@ -317,12 +318,8 @@ export const workerFields = [ ...phoneField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'create', - ], + resource: [ 'workers' ], + operation: [ 'create' ], }, }, required: true, @@ -331,11 +328,10 @@ export const workerFields = [ ...vehicleField, displayOptions: { show: { - resource: [ - 'workers', - ], + resource: [ 'workers' ], operation: [ - 'create', 'update', + 'create', + 'update', ], }, }, @@ -345,15 +341,12 @@ export const workerFields = [ ...vehicleTypeField, displayOptions: { show: { - resource: [ - 'workers', - ], + resource: [ 'workers' ], operation: [ - 'create', 'update', - ], - vehicle: [ - true, + 'create', + 'update', ], + vehicle: [ true ], }, }, required: true, @@ -362,40 +355,28 @@ export const workerFields = [ ...teamsField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'create', - ], + resource: [ 'workers' ], + operation: [ 'create' ], }, }, required: true, }, { - ...longitudFilterField, + ...longitudeFilterField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'getAllLocation', - ], + resource: [ 'workers' ], + operation: [ 'getAllByLocation' ], }, }, required: true, }, { - ...latitudFilterField, + ...latitudeFilterField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'getAllLocation', - ], + resource: [ 'workers' ], + operation: [ 'getAllByLocation' ], }, }, required: true, @@ -408,15 +389,11 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'getAllLocation', - ], + resource: [ 'workers' ], + operation: [ 'getAllByLocation' ], }, }, - options: [ radiousFilterField ], + options: [ radiusFilterField ], }, { displayName: 'Additional vehicle fields', @@ -426,18 +403,19 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], + resource: [ 'workers' ], operation: [ - 'create', 'update', - ], - vehicle: [ - true, + 'create', + 'update', ], + vehicle: [ true ], }, }, - options: [ vehicleDescriptionField, vehicleLicensePlateField, vehicleColorField ], + options: [ + vehicleDescriptionField, + vehicleLicensePlateField, + vehicleColorField, + ], }, { displayName: 'Additional fields', @@ -447,15 +425,14 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'create', - ], + resource: [ 'workers' ], + operation: [ 'create' ], }, }, - options: [ capacityField, displayNameField ], + options: [ + capacityField, + displayNameField, + ], }, { displayName: 'Additional fields', @@ -465,15 +442,16 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'update', - ], + resource: [ 'workers' ], + operation: [ 'update' ], }, }, - options: [ nameField, capacityField, displayNameField, teamsField ], + options: [ + nameField, + capacityField, + displayNameField, + teamsField, + ], }, { displayName: 'Additional fields', @@ -483,15 +461,16 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'getAll', - ], + resource: [ 'workers' ], + operation: [ 'getAll' ], }, }, - options: [ filterField, teamsFilterField, statesFilterField, phonesFilterField ], + options: [ + filterField, + teamsFilterField, + statesFilterField, + phonesFilterField, + ], }, { displayName: 'Additional fields', @@ -501,12 +480,8 @@ export const workerFields = [ default: {}, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'get', - ], + resource: [ 'workers' ], + operation: [ 'get' ], }, }, options: [ filterField ], @@ -515,12 +490,8 @@ export const workerFields = [ ...scheduleDateField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'setSchedule', - ], + resource: [ 'workers' ], + operation: [ 'setSchedule' ], }, }, required: true, @@ -529,12 +500,8 @@ export const workerFields = [ ...scheduleTimezoneField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'setSchedule', - ], + resource: [ 'workers' ], + operation: [ 'setSchedule' ], }, }, required: true, @@ -543,12 +510,8 @@ export const workerFields = [ ...scheduleStartField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'setSchedule', - ], + resource: [ 'workers' ], + operation: [ 'setSchedule' ], }, }, required: true, @@ -557,12 +520,8 @@ export const workerFields = [ ...scheduleEndField, displayOptions: { show: { - resource: [ - 'workers', - ], - operation: [ - 'setSchedule', - ], + resource: [ 'workers' ], + operation: [ 'setSchedule' ], }, }, required: true, From 4c36754014e57d879b1185e390edd00d9c5f066f Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Tue, 21 Dec 2021 08:27:45 -0500 Subject: [PATCH 03/12] refactor: changed add to create in comments and labels --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 16 ++++++++-------- .../descriptions/AdministratorDescription.ts | 4 ++-- .../descriptions/DestinationDescription.ts | 4 ++-- .../nodes/Onfleet/descriptions/HubDescription.ts | 4 ++-- .../Onfleet/descriptions/RecipientDescription.ts | 4 ++-- .../Onfleet/descriptions/TeamDescription.ts | 4 ++-- .../Onfleet/descriptions/WebhookDescription.ts | 4 ++-- .../Onfleet/descriptions/WorkerDescription.ts | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index e573dd8d2e054..3650ea466eefa 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -577,7 +577,7 @@ export class Onfleet implements INodeType { ): Promise { if (operation === 'createBatch') { /* -------------------------------------------------------------------------- */ - /* Add tasks by batch */ + /* Create multiple tasks by batch */ /* -------------------------------------------------------------------------- */ const path = `${resource}/batch`; const tasksData = { tasks: items.map((_item, index) => Onfleet.getTaskFields.call(this, index, operation)) }; @@ -591,7 +591,7 @@ export class Onfleet implements INodeType { try { if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new task */ + /* Create a new task */ /* -------------------------------------------------------------------------- */ const taskData = Onfleet.getTaskFields.call(this, index, operation); if (!taskData) { continue ;} @@ -771,7 +771,7 @@ export class Onfleet implements INodeType { try { if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new recipient */ + /* Create a new recipient */ /* -------------------------------------------------------------------------- */ const recipientData = Onfleet.getRecipientFields.call(this, index, operation); if (!recipientData) { continue; } @@ -832,7 +832,7 @@ export class Onfleet implements INodeType { responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new admin */ + /* Create a new admin */ /* -------------------------------------------------------------------------- */ const adminData = Onfleet.getAdminFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, adminData)); @@ -890,7 +890,7 @@ export class Onfleet implements INodeType { responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new hub */ + /* Create a new hub */ /* -------------------------------------------------------------------------- */ const hubData = Onfleet.getHubFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, hubData)); @@ -955,7 +955,7 @@ export class Onfleet implements INodeType { responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, workerFilters)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new worker */ + /* Create a new worker */ /* -------------------------------------------------------------------------- */ const workerData = Onfleet.getWorkerFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, workerData)); @@ -1038,7 +1038,7 @@ export class Onfleet implements INodeType { responseData.push(...await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new webhook */ + /* Create a new webhook */ /* -------------------------------------------------------------------------- */ const webhookData = Onfleet.getWebhookFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, webhookData)); @@ -1157,7 +1157,7 @@ export class Onfleet implements INodeType { responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Add a new team */ + /* Create a new team */ /* -------------------------------------------------------------------------- */ const teamData = Onfleet.getTeamFields.call(this, index, operation); responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, resource, teamData)); diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts index c79660da910a6..b5d19a3f1aee0 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -14,9 +14,9 @@ export const adminOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new Onfleet admin.', + description: 'Create a new Onfleet admin.', }, { name: 'Remove', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 079f7c39610f7..7aa30b915e1d3 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -14,9 +14,9 @@ export const destinationOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new destination.', + description: 'Create a new destination.', }, { name: 'Get', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index 634decafb51bd..c089f1562c9ab 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -14,9 +14,9 @@ export const hubOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new Onfleet hub.', + description: 'Create a new Onfleet hub.', }, { name: 'List hubs', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index 71be41c7e84df..b23ccf8530382 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -14,9 +14,9 @@ export const recipientOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new Onfleet recipient.', + description: 'Create a new Onfleet recipient.', }, { name: 'Get', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index c171901970ae7..c550ee1164a15 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -14,9 +14,9 @@ export const teamOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new Onfleet team.', + description: 'Create a new Onfleet team.', }, { name: 'Update', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts index 20cfcdccd903c..a1faaa83f3066 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -15,9 +15,9 @@ export const webhookOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', - description: 'Add a new Onfleet webhook.', + description: 'Create a new Onfleet webhook.', }, { name: 'Remove', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index 66c47236ad84d..c7f8f761c81ce 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -14,7 +14,7 @@ export const workerOperations = [ }, options: [ { - name: 'Add', + name: 'Create', value: 'create', description: 'Create a new Onfleet worker.', }, From 56d6e773a211fec96a50e43b4ea931a5e544f639 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Wed, 22 Dec 2021 07:46:50 -0500 Subject: [PATCH 04/12] feat: added name field to onfleet trigger node --- .../nodes/Onfleet/OnfleetTrigger.node.ts | 41 ++++++++++++++++--- .../descriptions/OnfleetWebhookDescription.ts | 18 ++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index efa9b80879aa0..25000abb23095 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -12,7 +12,7 @@ import { IWebhookFunctions, } from 'n8n-core'; -import { eventDisplay } from './descriptions/OnfleetWebhookDescription'; +import { eventDisplay, eventNameField } from './descriptions/OnfleetWebhookDescription'; import { onfleetApiRequest } from './GenericFunctions'; import { webhookMapping } from './WebhookMapping'; @@ -53,6 +53,7 @@ export class OnfleetTrigger implements INodeType { ], properties: [ eventDisplay, + eventNameField, ], }; @@ -63,6 +64,7 @@ export class OnfleetTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node') as IDataObject; const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; const event = this.getNodeParameter('event', 0) as string; + const { name = '' } = this.getNodeParameter('additionalFields', 0) as IDataObject; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); if (!webhookData[event] || typeof webhookData[event] !== 'string') { @@ -71,10 +73,32 @@ export class OnfleetTrigger implements INodeType { } // Webhook got created before so check if it still exists - const endpoint = `/webhooks/${webhookData[event]}`; + const endpoint = '/webhooks'; try { - await onfleetApiRequest.call(this, 'GET', encodedApiKey, endpoint); + const webhooks = await onfleetApiRequest.call(this, 'GET', encodedApiKey, endpoint); + // tslint:disable-next-line: no-any + const exist = webhooks.some((webhook: any) => webhook.id === webhookData[event]); + if (!exist) { + delete webhookData[event]; + } else { + // Changing the name if it's different + // tslint:disable-next-line: no-any + const webhook = webhooks.find((webhook: any) => webhook.id === webhookData[event]); + + // Webhook name according to the field + let newWebhookName = `[N8N] ${webhookMapping[event].name}`; + if (name) { + newWebhookName = `[N8N] ${name}`; + } + + // If webhook name is different so, it's updated + if (webhook && webhook.name !== newWebhookName) { + const path = `${endpoint}/${webhook.id}`; + await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { name: newWebhookName }); + } + } + return exist; } catch (error) { const { httpCode = '' } = error as { httpCode: string }; if (httpCode === '404') { @@ -87,8 +111,6 @@ export class OnfleetTrigger implements INodeType { throw error; } - // If it did not error then the webhook exists - return true; }, async create(this: IHookFunctions): Promise { const webhookUrl = this.getNodeWebhookUrl('default') as string; @@ -96,14 +118,21 @@ export class OnfleetTrigger implements INodeType { const webhookData = this.getWorkflowStaticData('node'); const event = this.getNodeParameter('event', 0) as string; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const { name = '' } = this.getNodeParameter('additionalFields', 0) as IDataObject; if (webhookUrl.includes('//localhost')) { throw new NodeOperationError(this.getNode(), 'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!'); } + // Webhook name according to the field + let newWebhookName = `[N8N] ${webhookMapping[event].name}`; + if (name) { + newWebhookName = `[N8N] ${name}`; + } + const path = `/webhooks`; const body = { - name : `[N8N] ${webhookMapping[event].name}`, + name : newWebhookName, url : webhookUrl, trigger : webhookMapping[event].key, }; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts index 93217e5ae2b07..899c65756d7d5 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts @@ -15,3 +15,21 @@ export const eventDisplay: INodeProperties = { default: [], description: 'The event to listen to.', }; + +export const eventNameField = { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: false, + default: null, + description: 'A name for the webhook for identification.', + }, + ], +} as INodeProperties; From 19d90e91fb8001f7285089600d80c7d8dbe536d0 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Mon, 17 Jan 2022 11:20:09 -0500 Subject: [PATCH 05/12] feat: added team endpoints to onfleet node Added team auto-dispatch and driver time estimate endpoints to Onfleet node --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 61 +++- .../Onfleet/descriptions/TeamDescription.ts | 281 ++++++++++++++++++ .../nodes-base/nodes/Onfleet/interfaces.ts | 17 ++ 3 files changed, 358 insertions(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index 3650ea466eefa..6a21eb0f1b016 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -16,9 +16,11 @@ import { OnfleetTask, OnfleetTaskComplete, OnfleetTaskUpdate, + OnfleetTeamAutoDispatch, OnfleetTeams, OnfleetWebhook, OnfleetWorker, + OnfleetWorkerEstimates, OnfleetWorkerFilter, OnfleetWorkerSchedule } from './interfaces'; @@ -525,7 +527,7 @@ export class Onfleet implements INodeType { * @param operation Current team opration * @returns {OnfleetTeams} Team information */ - static getTeamFields(this: IExecuteFunctions, item: number, operation: string): OnfleetTeams | null { + static getTeamFields(this: IExecuteFunctions, item: number, operation: string): OnfleetTeams | OnfleetWorkerEstimates | OnfleetTeamAutoDispatch | null { if (operation === 'create') { /* -------------------------------------------------------------------------- */ /* Get fields to create a team */ @@ -555,6 +557,47 @@ export class Onfleet implements INodeType { } Object.assign(teamData, additionalFields); return teamData; + } else if (operation === 'getTimeEstimates') { + /* -------------------------------------------------------------------------- */ + /* Get driver time estimates for tasks that haven't been created yet */ + /* -------------------------------------------------------------------------- */ + const dropoff = this.getNodeParameter('dropoff', item) as boolean; + const pickup = this.getNodeParameter('pickup', item) as boolean; + if (!dropoff && !pickup) throw new Error('At least 1 of dropoffLocation or pickupLocation must be selected'); + const longitudeField = `${dropoff ? 'dropoff' : 'pickup'}Longitude`; + const latitudeField = `${dropoff ? 'dropoff' : 'pickup'}Latitude`; + const longitude = this.getNodeParameter(longitudeField, item) as string; + const latitude = this.getNodeParameter(latitudeField, item) as string; + + const wokrerTimeEstimates = {} as OnfleetWorkerEstimates; + if (pickup) { + wokrerTimeEstimates.pickupLocation = `${longitude},${latitude}`; + wokrerTimeEstimates.pickupTime = (new Date(this.getNodeParameter('pickupTime', item) as Date)).getTime() / 1000; + } + if(dropoff) { + wokrerTimeEstimates.dropoffLocation = `${longitude},${latitude}`; + } + + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + Object.assign(wokrerTimeEstimates, additionalFields); + return wokrerTimeEstimates; + } else if (operation === 'autoDispatch') { + /* -------------------------------------------------------------------------- */ + /* Dynamically dispatching tasks on the fly */ + /* -------------------------------------------------------------------------- */ + const teamAutoDispatch = {} as OnfleetTeamAutoDispatch; + const { + taskTimeWindow, scheduleTimeWindow, ...additionalFields + } = this.getNodeParameter('additionalFields', item) as IDataObject; + if (taskTimeWindow) { + teamAutoDispatch.taskTimeWindow= JSON.parse((taskTimeWindow as string)); + } + if (scheduleTimeWindow) { + teamAutoDispatch.scheduleTimeWindow= JSON.parse((scheduleTimeWindow as string)); + } + + Object.assign(teamAutoDispatch, additionalFields); + return teamAutoDispatch; } return null; } @@ -1176,6 +1219,22 @@ export class Onfleet implements INodeType { const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + } else if (operation === 'getTimeEstimates') { + /* -------------------------------------------------------------------------- */ + /* Get driver time estimates for tasks that haven't been created yet */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const workerTimeEstimates = Onfleet.getTeamFields.call(this, index, operation) as OnfleetWorkerSchedule; + const path = `${resource}/${id}/estimate`; + responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, workerTimeEstimates)); + } else if (operation === 'autoDispatch') { + /* -------------------------------------------------------------------------- */ + /* Dynamically dispatching tasks on the fly */ + /* -------------------------------------------------------------------------- */ + const id = this.getNodeParameter('id', index) as string; + const teamAutoDispatch = Onfleet.getTeamFields.call(this, index, operation) as OnfleetWorkerSchedule; + const path = `${resource}/${id}/dispatch`; + responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, teamAutoDispatch)); } } catch (error) { if (this.continueOnFail()) { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index c550ee1164a15..1eeabfe70af3a 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -38,6 +38,16 @@ export const teamOperations = [ value: 'getAll', description: 'List all Onfleet teams.', }, + { + name: 'Auto-Dispatch', + value: 'autoDispatch', + description: 'Dynamically dispatching tasks on the fly.', + }, + { + name: 'Get time estimates', + value: 'getTimeEstimates', + description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet.', + }, ], default: 'getAll', }, @@ -83,6 +93,169 @@ const enableSelfAssignmentField = { description: 'This toggles Team Self-Assignment that allows Drivers to Self Assign Tasks that are in the Team unassigned container.', } as INodeProperties; +const maxTasksPerRouteField = { + displayName: 'Max number of tasks per route', + name: 'maxTasksPerRoute', + type: 'number', + default: 100, + typeOptions: { + maxValue: 200, + minValue: 1, + }, + description: 'Total number of tasks allowed on a route.', +}as INodeProperties; + +const taskTimeWindowField = { + displayName: 'Task time window (JSON)', + name: 'taskTimeWindow', + type: 'json', + default: '{}', + description: 'This is the time window of tasks to include in the optimization. Param must be an array of length 2 in unix time in seconds precision, [start, end]', +} as INodeProperties; + +const scheduleTimeWindowField = { + displayName: 'Schedule time window (JSON)', + name: 'scheduleTimeWindow', + type: 'json', + default: '{}', + description: 'This is the Driver\'s scheduled time window. Param must be an array of length 2 in unix time in seconds precision, [start, end]', +} as INodeProperties; + +const serviceTImeField = { + displayName: 'Service time', + name: 'serviceTIme', + type: 'number', + default: 2, + typeOptions: { + minValue: 0, + }, + description: 'The default service time to apply in Minutes to the tasks when no task service time exists.', +} as INodeProperties; + +const routeEndField = { + displayName: 'Route end', + name: 'routeEnd', + type: 'string', + default: '', + description: 'Where the route will end.', +} as INodeProperties; + +const maxAllowedDelayField = { + displayName: 'Max allowed delay', + name: 'maxAllowedDelay', + type: 'number', + default: 10, + description: '', + typeOptions: { + minValue: 1, + }, +} as INodeProperties; + +const dropoffField = { + displayName: 'Dropoff', + name: 'dropoff', + type: 'boolean', + default: false, + description: 'Dropoff.', +} as INodeProperties; + +const pickupField = { + displayName: 'Pickup', + name: 'pickup', + type: 'boolean', + default: false, + description: 'Pickup.', +} as INodeProperties; + +const longitudeDropoffField = { + displayName: 'Dropoff longitude', + name: 'dropoffLongitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The longitude for dropoff location.', +} as INodeProperties; + +const latitudeDropoffField = { + displayName: 'Dropoff latitude', + name: 'dropoffLatitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The latitude for dropoff location.', +} as INodeProperties; + +const longitudePickupField = { + displayName: 'Pickup longitude', + name: 'pickupLongitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The longitude for pickup location.', +} as INodeProperties; + +const latitudePickupField = { + displayName: 'Pickup latitude', + name: 'pickupLatitude', + type: 'number', + typeOptions: { + numberPrecision: 14, + }, + default: '', + description: 'The latitude for pickup location.', +} as INodeProperties; + +const pickupTimeField = { + displayName: 'Pickup time', + name: 'pickupTime', + type: 'dateTime', + default: Date.now(), + description: 'If the request includes pickupLocation pickupTime must be present if the time is fewer than 3 hours in the future.', +} as INodeProperties; + +const restrictedVehicleTypesField = { + displayName: 'Restricted vehicle types', + name: 'restrictedVehicleTypes', + type: 'options', + options: [ + { + name: 'Car', + value: 'CAR', + }, + { + name: 'Motorcycle', + value: 'MOTORCYCLE', + }, + { + name: 'Bicycle', + value: 'BICYCLE', + }, + { + name: 'Truck', + value: 'TRUCK', + }, + ], + default: 'CAR', + description: 'Vehicle types to ignore in the query.', +} as INodeProperties; + +const serviceTimeEstimateField = { + displayName: 'Service time', + name: 'serviceTIme', + type: 'number', + default: 120, + typeOptions: { + minValue: 0, + }, + description: 'The expected time a worker will take at the pickupLocation, dropoffLocation, or both (as applicable) Unit: seconds.', +} as INodeProperties; + export const teamFields = [ { displayName: 'ID', @@ -95,6 +268,8 @@ export const teamFields = [ 'get', 'update', 'delete', + 'getTimeEstimates', + 'autoDispatch', ], }, }, @@ -169,4 +344,110 @@ export const teamFields = [ enableSelfAssignmentField, ], }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'autoDispatch' ], + }, + }, + options: [ + maxTasksPerRouteField, + taskTimeWindowField, + scheduleTimeWindowField, + serviceTImeField, + routeEndField, + maxAllowedDelayField, + ], + }, + { + ...dropoffField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + }, + }, + }, + { + ...longitudeDropoffField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + dropoff: [ true ], + }, + }, + }, + { + ...latitudeDropoffField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + dropoff: [ true ], + }, + }, + }, + { + ...pickupField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + }, + }, + }, + { + ...longitudePickupField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + pickup: [ true ], + }, + }, + }, + { + ...latitudePickupField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + pickup: [ true ], + }, + }, + }, + { + ...pickupTimeField, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + pickup: [ true ], + }, + }, + }, + { + displayName: 'Additional fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add fields', + default: {}, + displayOptions: { + show: { + resource: [ 'teams' ], + operation: [ 'getTimeEstimates' ], + }, + }, + options: [ + restrictedVehicleTypesField, + serviceTimeEstimateField, + ], + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/interfaces.ts b/packages/nodes-base/nodes/Onfleet/interfaces.ts index 226c1d8637761..2fba8f80d4082 100644 --- a/packages/nodes-base/nodes/Onfleet/interfaces.ts +++ b/packages/nodes-base/nodes/Onfleet/interfaces.ts @@ -155,3 +155,20 @@ export interface OnfleetWebhookMapping { export interface OnfleetWebhooksMapping { [key: string]: OnfleetWebhookMapping; } + +export interface OnfleetWorkerEstimates { + dropoffLocation?: string; + pickupLocation?: string; + pickupTime?: number; + restrictedVehicleTypes?: string; + serviceTime?: number; +} + +export interface OnfleetTeamAutoDispatch { + maxTasksPerRoute?: number; + taskTimeWindow?: [number, number]; + scheduleTimeWindow?: [number, number]; + serviceTime?: number; + routeEnd?: string; + maxAllowedDelay?: number; +} From 49a8e03cb1a682ff21fd057f5561ae9a7df959e0 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Wed, 19 Jan 2022 09:48:31 -0500 Subject: [PATCH 06/12] style: remove dots in descriptions and fixed some typos --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 14 ++--- .../nodes/Onfleet/OnfleetTrigger.node.ts | 4 +- .../descriptions/AdministratorDescription.ts | 18 +++--- .../descriptions/ContainerDescription.ts | 18 +++--- .../descriptions/DestinationDescription.ts | 26 ++++---- .../Onfleet/descriptions/HubDescription.ts | 12 ++-- .../descriptions/OnfleetWebhookDescription.ts | 4 +- .../descriptions/OrganizationDescription.ts | 6 +- .../descriptions/RecipientDescription.ts | 34 +++++----- .../Onfleet/descriptions/TaskDescription.ts | 56 ++++++++--------- .../Onfleet/descriptions/TeamDescription.ts | 54 ++++++++-------- .../descriptions/WebhookDescription.ts | 16 ++--- .../Onfleet/descriptions/WorkerDescription.ts | 62 +++++++++---------- 13 files changed, 162 insertions(+), 162 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index 6a21eb0f1b016..9d126d75d9c3c 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -108,7 +108,7 @@ export class Onfleet implements INodeType { }, ], default: 'tasks', - description: 'The resource to perform operations on.', + description: 'The resource to perform operations on', }, // Operations ...adminOperations, @@ -569,18 +569,18 @@ export class Onfleet implements INodeType { const longitude = this.getNodeParameter(longitudeField, item) as string; const latitude = this.getNodeParameter(latitudeField, item) as string; - const wokrerTimeEstimates = {} as OnfleetWorkerEstimates; + const workerTimeEstimates = {} as OnfleetWorkerEstimates; if (pickup) { - wokrerTimeEstimates.pickupLocation = `${longitude},${latitude}`; - wokrerTimeEstimates.pickupTime = (new Date(this.getNodeParameter('pickupTime', item) as Date)).getTime() / 1000; + workerTimeEstimates.pickupLocation = `${longitude},${latitude}`; + workerTimeEstimates.pickupTime = (new Date(this.getNodeParameter('pickupTime', item) as Date)).getTime() / 1000; } if(dropoff) { - wokrerTimeEstimates.dropoffLocation = `${longitude},${latitude}`; + workerTimeEstimates.dropoffLocation = `${longitude},${latitude}`; } const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; - Object.assign(wokrerTimeEstimates, additionalFields); - return wokrerTimeEstimates; + Object.assign(workerTimeEstimates, additionalFields); + return workerTimeEstimates; } else if (operation === 'autoDispatch') { /* -------------------------------------------------------------------------- */ /* Dynamically dispatching tasks on the fly */ diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 25000abb23095..72e8b100d0d93 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -24,7 +24,7 @@ export class OnfleetTrigger implements INodeType { group: [ 'trigger' ], version: 1, subtitle: '={{$parameter["events"]}}', - description: 'Starts the workflow when Onfleet events occur.', + description: 'Starts the workflow when Onfleet events occur', defaults: { name: 'Onfleet Trigger', color: '#AA81F3', @@ -142,7 +142,7 @@ export class OnfleetTrigger implements INodeType { .then(responseData => { if (responseData.id === undefined) { // Required data is missing so was not successful - throw new NodeApiError(this.getNode(), responseData, { message: 'Onfleet webhook creation response did not contain the expected data.' }); + throw new NodeApiError(this.getNode(), responseData, { message: 'Onfleet webhook creation response did not contain the expected data' }); } webhookData[event] = responseData.id as string; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts index b5d19a3f1aee0..027d8ec323468 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -16,22 +16,22 @@ export const adminOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet admin.', + description: 'Create a new Onfleet admin', }, { name: 'Remove', value: 'delete', - description: 'Remove an Onfleet admin.', + description: 'Remove an Onfleet admin', }, { name: 'List', value: 'getAll', - description: 'List all Onfleet admins.', + description: 'List all Onfleet admins', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet admin.', + description: 'Update an Onfleet admin', }, ], default: 'getAll', @@ -43,7 +43,7 @@ const adminNameField = { name: 'name', type: 'string', default: '', - description: 'The administrator\'s name.', + description: 'The administrator\'s name', } as INodeProperties; const adminEmailField = { @@ -51,7 +51,7 @@ const adminEmailField = { name: 'email', type: 'string', default: '', - description: 'The administrator\'s email address.', + description: 'The administrator\'s email address', } as INodeProperties; const adminPhoneField = { @@ -59,7 +59,7 @@ const adminPhoneField = { name: 'phone', type: 'string', default: '', - description: 'The administrator\'s phone number.', + description: 'The administrator\'s phone number', } as INodeProperties; const adminReadOnlyField = { @@ -67,7 +67,7 @@ const adminReadOnlyField = { name: 'isReadOnly', type: 'boolean', default: false, - description: 'Whether this administrator can perform write operations.', + description: 'Whether this administrator can perform write operations', } as INodeProperties; export const adminFields = [ @@ -88,7 +88,7 @@ export const adminFields = [ }, default: '', required: true, - description: 'The ID of the admin object for lookup.', + description: 'The ID of the admin object for lookup', }, { displayOptions: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts index 43821c0d324a1..d02726cef778b 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -16,17 +16,17 @@ export const containerOperations = [ { name: 'Insert tasks (or append)', value: 'add', - description: 'Insert tasks at index (or append).', + description: 'Insert tasks at index (or append)', }, { name: 'Update tasks', value: 'update', - description: 'Fully replace a container\'s tasks.', + description: 'Fully replace a container\'s tasks', }, { name: 'Get container', value: 'get', - description: 'Get container information.', + description: 'Get container information', }, ], default: 'get', @@ -52,7 +52,7 @@ const containerTypeField = { }, ], default: '', - description: 'Container type.', + description: 'Container type', } as INodeProperties; const containerIdField = { @@ -60,7 +60,7 @@ const containerIdField = { name: 'containerId', type: 'string', default: '', - description: 'The object ID according to the container chosen.', + description: 'The object ID according to the container chosen', } as INodeProperties; const insertTypeField = { @@ -82,7 +82,7 @@ const insertTypeField = { }, ], default: '', - description: 'The index given indicates the position where the tasks are going to be inserted.', + description: 'The index given indicates the position where the tasks are going to be inserted', } as INodeProperties; const indexField = { @@ -90,7 +90,7 @@ const indexField = { name: 'index', type: 'number', default: '', - description: 'The index given indicates the position where the tasks are going to be inserted.', + description: 'The index given indicates the position where the tasks are going to be inserted', } as INodeProperties; const tasksField = { @@ -98,7 +98,7 @@ const tasksField = { name: 'tasks', type: 'json', default: '[]', - description: 'Array witht the task\'s ID that are going to be used in JSON format.', + description: 'Array witht the task\'s ID that are going to be used in JSON format', } as INodeProperties; const considerDependenciesField = { @@ -106,7 +106,7 @@ const considerDependenciesField = { name: 'considerDependencies', type: 'boolean', default: false, - description: 'Whether to include the target task\'s dependency family (parent and child tasks) in the resulting assignment operation.', + description: 'Whether to include the target task\'s dependency family (parent and child tasks) in the resulting assignment operation', } as INodeProperties; export const containerFields = [ diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 7aa30b915e1d3..9e99d76b955a5 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -16,12 +16,12 @@ export const destinationOperations = [ { name: 'Create', value: 'create', - description: 'Create a new destination.', + description: 'Create a new destination', }, { name: 'Get', value: 'get', - description: 'Get a specific destination.', + description: 'Get a specific destination', }, ], @@ -33,7 +33,7 @@ const unparsedField = { displayName: 'Unparsed adress', name: 'unparsed', type: 'boolean', - description: 'Whether the address is specified in a single.', + description: 'Whether the address is specified in a single', default: false, } as INodeProperties; @@ -41,7 +41,7 @@ const unparsedAddressField = { displayName: 'Destination address', name: 'address', type: 'string', - description: 'The destination\'s street address details.', + description: 'The destination\'s street address details', default: null, } as INodeProperties; @@ -49,7 +49,7 @@ const unparsedAddressNumberField = { displayName: 'Number', name: 'addressNumber', type: 'string', - description: 'The number component of this address, it may also contain letters.', + description: 'The number component of this address, it may also contain letters', default: '', } as INodeProperties; @@ -57,7 +57,7 @@ const unparsedAddressStreetField = { displayName: 'Street', name: 'addressStreet', type: 'string', - description: 'The name of the street.', + description: 'The name of the street', default: '', } as INodeProperties; @@ -65,7 +65,7 @@ const unparsedAddressCityField = { displayName: 'City', name: 'addressCity', type: 'string', - description: 'The name of the municipality.', + description: 'The name of the municipality', default: '', } as INodeProperties; @@ -73,7 +73,7 @@ const unparsedAddressCountryField = { displayName: 'Country', name: 'addressCountry', type: 'string', - description: 'The name of the country.', + description: 'The name of the country', default: '', } as INodeProperties; @@ -82,7 +82,7 @@ const addressNameField = { name: 'addressName', type: 'string', default: '', - description: 'A name associated with this address.', + description: 'A name associated with this address', } as INodeProperties; const addressApartmentField = { @@ -90,7 +90,7 @@ const addressApartmentField = { name: 'addressApartment', type: 'string', default: '', - description: 'The suite or apartment number, or any additional relevant information.', + description: 'The suite or apartment number, or any additional relevant information', } as INodeProperties; const addressNoteField = { @@ -98,7 +98,7 @@ const addressNoteField = { name: 'addressNotes', type: 'string', default: '', - description: 'Notes about the destination.', + description: 'Notes about the destination', } as INodeProperties; const addressPostalCodeField = { @@ -106,7 +106,7 @@ const addressPostalCodeField = { name: 'addressPostalCode', type: 'string', default: '', - description: 'The postal or zip code.', + description: 'The postal or zip code', } as INodeProperties; export const destinationFields = [ @@ -124,7 +124,7 @@ export const destinationFields = [ }, default: '', required: true, - description: 'The ID of the destination object for lookup.', + description: 'The ID of the destination object for lookup', }, { ...unparsedField, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index c089f1562c9ab..324661d8df4a6 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -16,17 +16,17 @@ export const hubOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet hub.', + description: 'Create a new Onfleet hub', }, { name: 'List hubs', value: 'getAll', - description: 'List Onfleet hubs.', + description: 'List Onfleet hubs', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet hub.', + description: 'Update an Onfleet hub', }, ], default: 'get', @@ -38,7 +38,7 @@ const nameField = { name: 'name', type: 'string', default: '', - description: 'A name to identify the hub.', + description: 'A name to identify the hub', } as INodeProperties; const teamsField = { @@ -46,7 +46,7 @@ const teamsField = { name: 'teams', type: 'json', default: '[]', - description: 'This is the team ID(s) that this Hub will be assigned to.', + description: 'This is the team ID(s) that this Hub will be assigned to', } as INodeProperties; export const hubFields = [ @@ -62,7 +62,7 @@ export const hubFields = [ }, default: '', required: true, - description: 'The ID of the hub object for lookup.', + description: 'The ID of the hub object for lookup', }, { ...nameField, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts index 899c65756d7d5..f5207eede5e10 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts @@ -13,7 +13,7 @@ export const eventDisplay: INodeProperties = { }), required: true, default: [], - description: 'The event to listen to.', + description: 'The event to listen to', }; export const eventNameField = { @@ -29,7 +29,7 @@ export const eventNameField = { type: 'string', required: false, default: null, - description: 'A name for the webhook for identification.', + description: 'A name for the webhook for identification', }, ], } as INodeProperties; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts index 123372c8c67a6..3353edfd3f453 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -16,12 +16,12 @@ export const organizationOperations = [ { name: 'Get details', value: 'get', - description: 'Retrieve your own organization\'s details.', + description: 'Retrieve your own organization\'s details', }, { name: 'Get delegatee details', value: 'getDelegatee', - description: 'Retrieve the details of an organization with which you are connected.', + description: 'Retrieve the details of an organization with which you are connected', }, ], @@ -42,6 +42,6 @@ export const organizationFields = [ }, default: '', required: true, - description: 'The ID of the delegatees for lookup.', + description: 'The ID of the delegatees for lookup', }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index b23ccf8530382..cd10fd611c80f 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -16,17 +16,17 @@ export const recipientOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet recipient.', + description: 'Create a new Onfleet recipient', }, { name: 'Get', value: 'get', - description: 'Get a specific Onfleet recipient.', + description: 'Get a specific Onfleet recipient', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet recipient.', + description: 'Update an Onfleet recipient', }, ], default: 'get', @@ -39,21 +39,21 @@ const additionalRecipientFields = [ name: 'recipientNotes', type: 'string', default: '', - description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific.', + description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific', }, { displayName: 'Skip recipient SMS notifications', name: 'recipientSkipSMSNotifications', type: 'boolean', default: false, - description: 'Whether this recipient has requested to skip SMS notifications.', + description: 'Whether this recipient has requested to skip SMS notifications', }, { displayName: 'Skip recipient phone number validation', name: 'recipientSkipPhoneNumberValidation', type: 'boolean', default: false, - description: 'Whether to skip validation for this recipient\'s phone number.', + description: 'Whether to skip validation for this recipient\'s phone number', }, ]; @@ -61,14 +61,14 @@ const recipientName = { displayName: 'Recipient name', name: 'recipientName', type: 'string', - description: 'The recipient\'s complete name.', + description: 'The recipient\'s complete name', } as INodeProperties; const recipientPhone = { displayName: 'Recipient phone', name: 'recipientPhone', type: 'string', - description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting.', + description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting', } as INodeProperties; const additionalRecipientFieldsUpdate = [ @@ -79,21 +79,21 @@ const additionalRecipientFieldsUpdate = [ name: 'notes', type: 'string', default: '', - description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific.', + description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific', }, { displayName: 'Skip recipient SMS notifications', name: 'skipSMSNotifications', type: 'boolean', default: false, - description: 'Whether this recipient has requested to skip SMS notifications.', + description: 'Whether this recipient has requested to skip SMS notifications', }, { displayName: 'Skip recipient phone number validation', name: 'skipPhoneNumberValidation', type: 'boolean', default: false, - description: 'Whether to skip validation for this recipient\'s phone number.', + description: 'Whether to skip validation for this recipient\'s phone number', }, ]; @@ -122,7 +122,7 @@ export const recipientFields = [ value: 'name', }, ], - description: 'The variable that is used for looking up a recipient.', + description: 'The variable that is used for looking up a recipient', required: true, default: 'id', }, @@ -139,7 +139,7 @@ export const recipientFields = [ }, default: '', required: true, - description: 'The ID of the recipient object for lookup.', + description: 'The ID of the recipient object for lookup', }, { displayName: 'ID', @@ -153,7 +153,7 @@ export const recipientFields = [ }, default: '', required: true, - description: 'The ID of the recipient object for lookup.', + description: 'The ID of the recipient object for lookup', }, { displayName: 'Name', @@ -168,7 +168,7 @@ export const recipientFields = [ }, default: '', required: true, - description: 'The name of the recipient for lookup.', + description: 'The name of the recipient for lookup', }, { displayName: 'Phone', @@ -183,7 +183,7 @@ export const recipientFields = [ }, default: '', required: true, - description: 'The phone of the recipient for lookup.', + description: 'The phone of the recipient for lookup', }, { displayName: 'Recipient', @@ -198,7 +198,7 @@ export const recipientFields = [ ], }, }, - description: 'Whether the task has a recipient associated.', + description: 'Whether the task has a recipient associated', required: true, default: true, }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 8d923a964a4f8..66452a5465147 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -16,42 +16,42 @@ export const taskOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet task.', + description: 'Create a new Onfleet task', }, { name: 'Create multiple tasks', value: 'createBatch', - description: 'Creating multiple tasks in batch.', + description: 'Creating multiple tasks in batch', }, { name: 'Clone', value: 'clone', - description: 'Clone an Onfleet task.', + description: 'Clone an Onfleet task', }, { name: 'Complete', value: 'complete', - description: 'Force-complete a started Onfleet task.', + description: 'Force-complete a started Onfleet task', }, { name: 'Remove', value: 'delete', - description: 'Remove an Onfleet task.', + description: 'Remove an Onfleet task', }, { name: 'List', value: 'getAll', - description: 'List Onfleet tasks.', + description: 'List Onfleet tasks', }, { name: 'Get', value: 'get', - description: 'Get a specific Onfleet task.', + description: 'Get a specific Onfleet task', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet task.', + description: 'Update an Onfleet task', }, ], @@ -64,7 +64,7 @@ const merchantIdField = { name: 'merchant', type: 'string', default: '', - description: 'The ID of the organization that will be displayed to the recipient of the task.', + description: 'The ID of the organization that will be displayed to the recipient of the task', } as INodeProperties; const executorIdField = { @@ -72,7 +72,7 @@ const executorIdField = { name: 'executor', type: 'string', default: '', - description: 'The ID of the organization that will be responsible for fulfilling the task.', + description: 'The ID of the organization that will be responsible for fulfilling the task', } as INodeProperties; const completeAfterField = { @@ -80,7 +80,7 @@ const completeAfterField = { name: 'completeAfter', type: 'dateTime', default: null, - description: 'The earliest time the task should be completed.', + description: 'The earliest time the task should be completed', } as INodeProperties; const completeBeforeField = { @@ -88,7 +88,7 @@ const completeBeforeField = { name: 'completeBefore', type: 'dateTime', default: null, - description: 'The latest time the task should be completed.', + description: 'The latest time the task should be completed', } as INodeProperties; const pickupTaskField = { @@ -96,7 +96,7 @@ const pickupTaskField = { name: 'pickupTask', type: 'boolean', default: false, - description: 'Whether the task is a pickup task.', + description: 'Whether the task is a pickup task', } as INodeProperties; const notesField = { @@ -104,7 +104,7 @@ const notesField = { name: 'notes', type: 'string', default: '', - description: 'Notes for the task.', + description: 'Notes for the task', } as INodeProperties; const quantityField = { @@ -112,7 +112,7 @@ const quantityField = { name: 'quantity', type: 'number', default: 0, - description: 'The number of units to be dropped off while completing this task, for route optimization purposes.', + description: 'The number of units to be dropped off while completing this task, for route optimization purposes', } as INodeProperties; const serviceTimeField = { @@ -120,7 +120,7 @@ const serviceTimeField = { name: 'serviceTime', type: 'number', default: 0, - description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes.', + description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes', } as INodeProperties; export const taskFields = [ @@ -142,7 +142,7 @@ export const taskFields = [ }, default: '', required: true, - description: 'The ID of the task object for lookup.', + description: 'The ID of the task object for lookup', }, { displayName: 'Short ID', @@ -155,7 +155,7 @@ export const taskFields = [ }, }, required: true, - description: 'Whether the task short ID is used for lookup.', + description: 'Whether the task short ID is used for lookup', }, { displayName: 'From', @@ -167,7 +167,7 @@ export const taskFields = [ operation: [ 'getAll' ], }, }, - description: 'The starting time of the range. Tasks created or completed at or after this time will be included.', + description: 'The starting time of the range. Tasks created or completed at or after this time will be included', required: true, default: null, }, @@ -181,7 +181,7 @@ export const taskFields = [ operation: [ 'complete' ], }, }, - description: 'Whether the task\'s completion was successful.', + description: 'Whether the task\'s completion was successful', required: true, default: true, }, @@ -203,7 +203,7 @@ export const taskFields = [ name: 'to', type: 'dateTime', default: null, - description: 'The ending time of the range. Defaults to current time if not specified.', + description: 'The ending time of the range. Defaults to current time if not specified', }, { displayName: 'State', @@ -228,14 +228,14 @@ export const taskFields = [ }, ], default: null, - description: 'The state of the tasks.', + description: 'The state of the tasks', }, { displayName: 'LastId', name: 'lastId', type: 'string', default: null, - description: 'The last Id to walk the paginated response.', + description: 'The last Id to walk the paginated response', }, ], }, @@ -319,7 +319,7 @@ export const taskFields = [ name: 'notes', type: 'string', default: '', - description: 'Completion Notes.', + description: 'Completion Notes', }, ], }, @@ -352,28 +352,28 @@ export const taskFields = [ name: 'recipientNameOverride', type: 'string', default: '', - description: 'Override the recipient name for this task only.', + description: 'Override the recipient name for this task only', }, { displayName: 'Recipient Notes Override', name: 'recipientNotes', type: 'string', default: '', - description: 'Override the recipient notes for this task only.', + description: 'Override the recipient notes for this task only', }, { displayName: 'Recipient Skip SMS Notifications Override', name: 'recipientSkipSMSNotifications', type: 'boolean', default: '', - description: 'Override the recipient notification settings for this task only.', + description: 'Override the recipient notification settings for this task only', }, { displayName: 'Use Merchant For Proxy Override', name: 'useMerchantForProxy', type: 'boolean', default: '', - description: 'Override the organization ID to use the merchant orgID when set to true for this task only.', + description: 'Override the organization ID to use the merchant orgID when set to true for this task only', }, ], }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index 1eeabfe70af3a..daa3fd2c77195 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -16,37 +16,37 @@ export const teamOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet team.', + description: 'Create a new Onfleet team', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet team.', + description: 'Update an Onfleet team', }, { name: 'Remove', value: 'delete', - description: 'Remove an Onfleet team.', + description: 'Remove an Onfleet team', }, { name: 'Get', value: 'get', - description: 'Get a specific Onfleet team.', + description: 'Get a specific Onfleet team', }, { name: 'List', value: 'getAll', - description: 'List all Onfleet teams.', + description: 'List all Onfleet teams', }, { name: 'Auto-Dispatch', value: 'autoDispatch', - description: 'Dynamically dispatching tasks on the fly.', + description: 'Dynamically dispatching tasks on the fly', }, { name: 'Get time estimates', value: 'getTimeEstimates', - description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet.', + description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet', }, ], default: 'getAll', @@ -58,7 +58,7 @@ const nameField = { name: 'name', type: 'string', default: '', - description: 'A unique name for the team.', + description: 'A unique name for the team', } as INodeProperties; const workersField = { @@ -66,7 +66,7 @@ const workersField = { name: 'workers', type: 'json', default: '[]', - description: 'An array of workers IDs.', + description: 'An array of workers IDs', } as INodeProperties; const managersField = { @@ -74,7 +74,7 @@ const managersField = { name: 'managers', type: 'json', default: '[]', - description: 'An array of managing administrator IDs.', + description: 'An array of managing administrator IDs', } as INodeProperties; const hubField = { @@ -82,7 +82,7 @@ const hubField = { name: 'hub', type: 'string', default: '', - description: 'The ID of the team\'s hub.', + description: 'The ID of the team\'s hub', } as INodeProperties; const enableSelfAssignmentField = { @@ -90,7 +90,7 @@ const enableSelfAssignmentField = { name: 'enableSelfAssignment', type: 'boolean', default: false, - description: 'This toggles Team Self-Assignment that allows Drivers to Self Assign Tasks that are in the Team unassigned container.', + description: 'This toggles Team Self-Assignment that allows Drivers to Self Assign Tasks that are in the Team unassigned container', } as INodeProperties; const maxTasksPerRouteField = { @@ -102,7 +102,7 @@ const maxTasksPerRouteField = { maxValue: 200, minValue: 1, }, - description: 'Total number of tasks allowed on a route.', + description: 'Total number of tasks allowed on a route', }as INodeProperties; const taskTimeWindowField = { @@ -121,7 +121,7 @@ const scheduleTimeWindowField = { description: 'This is the Driver\'s scheduled time window. Param must be an array of length 2 in unix time in seconds precision, [start, end]', } as INodeProperties; -const serviceTImeField = { +const serviceTimeField = { displayName: 'Service time', name: 'serviceTIme', type: 'number', @@ -129,7 +129,7 @@ const serviceTImeField = { typeOptions: { minValue: 0, }, - description: 'The default service time to apply in Minutes to the tasks when no task service time exists.', + description: 'The default service time to apply in Minutes to the tasks when no task service time exists', } as INodeProperties; const routeEndField = { @@ -137,7 +137,7 @@ const routeEndField = { name: 'routeEnd', type: 'string', default: '', - description: 'Where the route will end.', + description: 'Where the route will end', } as INodeProperties; const maxAllowedDelayField = { @@ -156,7 +156,7 @@ const dropoffField = { name: 'dropoff', type: 'boolean', default: false, - description: 'Dropoff.', + description: 'Dropoff', } as INodeProperties; const pickupField = { @@ -164,7 +164,7 @@ const pickupField = { name: 'pickup', type: 'boolean', default: false, - description: 'Pickup.', + description: 'Pickup', } as INodeProperties; const longitudeDropoffField = { @@ -175,7 +175,7 @@ const longitudeDropoffField = { numberPrecision: 14, }, default: '', - description: 'The longitude for dropoff location.', + description: 'The longitude for dropoff location', } as INodeProperties; const latitudeDropoffField = { @@ -186,7 +186,7 @@ const latitudeDropoffField = { numberPrecision: 14, }, default: '', - description: 'The latitude for dropoff location.', + description: 'The latitude for dropoff location', } as INodeProperties; const longitudePickupField = { @@ -197,7 +197,7 @@ const longitudePickupField = { numberPrecision: 14, }, default: '', - description: 'The longitude for pickup location.', + description: 'The longitude for pickup location', } as INodeProperties; const latitudePickupField = { @@ -208,7 +208,7 @@ const latitudePickupField = { numberPrecision: 14, }, default: '', - description: 'The latitude for pickup location.', + description: 'The latitude for pickup location', } as INodeProperties; const pickupTimeField = { @@ -216,7 +216,7 @@ const pickupTimeField = { name: 'pickupTime', type: 'dateTime', default: Date.now(), - description: 'If the request includes pickupLocation pickupTime must be present if the time is fewer than 3 hours in the future.', + description: 'If the request includes pickupLocation pickupTime must be present if the time is fewer than 3 hours in the future', } as INodeProperties; const restrictedVehicleTypesField = { @@ -242,7 +242,7 @@ const restrictedVehicleTypesField = { }, ], default: 'CAR', - description: 'Vehicle types to ignore in the query.', + description: 'Vehicle types to ignore in the query', } as INodeProperties; const serviceTimeEstimateField = { @@ -253,7 +253,7 @@ const serviceTimeEstimateField = { typeOptions: { minValue: 0, }, - description: 'The expected time a worker will take at the pickupLocation, dropoffLocation, or both (as applicable) Unit: seconds.', + description: 'The expected time a worker will take at the pickupLocation, dropoffLocation, or both (as applicable) Unit: seconds', } as INodeProperties; export const teamFields = [ @@ -275,7 +275,7 @@ export const teamFields = [ }, default: '', required: true, - description: 'The ID of the team object for lookup.', + description: 'The ID of the team object for lookup', }, { ...nameField, @@ -360,7 +360,7 @@ export const teamFields = [ maxTasksPerRouteField, taskTimeWindowField, scheduleTimeWindowField, - serviceTImeField, + serviceTimeField, routeEndField, maxAllowedDelayField, ], diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts index a1faaa83f3066..e70b759cb51f8 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -17,17 +17,17 @@ export const webhookOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet webhook.', + description: 'Create a new Onfleet webhook', }, { name: 'Remove', value: 'delete', - description: 'Remove an Onfleet webhook.', + description: 'Remove an Onfleet webhook', }, { name: 'List', value: 'getAll', - description: 'List all Onfleet webhooks.', + description: 'List all Onfleet webhooks', }, ], default: 'getAll', @@ -39,7 +39,7 @@ const urlField = { name: 'url', type: 'string', default: '', - description: 'The URL that Onfleet should issue a request against as soon as the trigger condition is met. It must be HTTPS and have a valid certificate.', + description: 'The URL that Onfleet should issue a request against as soon as the trigger condition is met. It must be HTTPS and have a valid certificate', } as INodeProperties; const nameField = { @@ -47,7 +47,7 @@ const nameField = { name: 'name', type: 'string', default: '', - description: 'A name for the webhook for identification.', + description: 'A name for the webhook for identification', } as INodeProperties; const triggerField = { @@ -58,7 +58,7 @@ const triggerField = { return { name, value }; }), default: '', - description: 'The number corresponding to the trigger condition on which the webhook should fire.', + description: 'The number corresponding to the trigger condition on which the webhook should fire', } as INodeProperties; const thresholdField = { @@ -66,7 +66,7 @@ const thresholdField = { name: 'threshold', type: 'number', default: '', - description: 'For trigger Task Eta, the time threshold in seconds; for trigger Task Arrival, the distance threshold in meters.', + description: 'For trigger Task Eta, the time threshold in seconds; for trigger Task Arrival, the distance threshold in meters', } as INodeProperties; export const webhookFields = [ @@ -82,7 +82,7 @@ export const webhookFields = [ }, default: '', required: true, - description: 'The ID of the webhook object for lookup.', + description: 'The ID of the webhook object for lookup', }, { ...urlField, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index c7f8f761c81ce..26dadafde9d89 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -16,42 +16,42 @@ export const workerOperations = [ { name: 'Create', value: 'create', - description: 'Create a new Onfleet worker.', + description: 'Create a new Onfleet worker', }, { name: 'Remove', value: 'delete', - description: 'Remove an Onfleet worker.', + description: 'Remove an Onfleet worker', }, { name: 'List', value: 'getAll', - description: 'List all Onfleet workers.', + description: 'List all Onfleet workers', }, { name: 'List workers by location', value: 'getAllByLocation', - description: 'List all Onfleet workers who are currently within a centain target area.', + description: 'List all Onfleet workers who are currently within a centain target area', }, { name: 'Get', value: 'get', - description: 'Get a specific Onfleet worker.', + description: 'Get a specific Onfleet worker', }, { name: 'Get Schedule', value: 'getSchedule', - description: 'Get a specific Onfleet worker schedule.', + description: 'Get a specific Onfleet worker schedule', }, { name: 'Set worker\'s schedule', value: 'setSchedule', - description: 'Set the worker\'s schedule.', + description: 'Set the worker\'s schedule', }, { name: 'Update', value: 'update', - description: 'Update an Onfleet worker.', + description: 'Update an Onfleet worker', }, ], default: 'get', @@ -63,7 +63,7 @@ const nameField = { name: 'name', type: 'string', default: '', - description: 'The worker\'s name.', + description: 'The worker\'s name', } as INodeProperties; const phoneField = { @@ -71,7 +71,7 @@ const phoneField = { name: 'phone', type: 'string', default: '', - description: 'A valid phone number as per the worker\'s organization\'s country.', + description: 'A valid phone number as per the worker\'s organization\'s country', } as INodeProperties; const capacityField = { @@ -79,7 +79,7 @@ const capacityField = { name: 'capacity', type: 'number', default: 0, - description: 'The maximum number of units this worker can carry, for route optimization purposes.', + description: 'The maximum number of units this worker can carry, for route optimization purposes', } as INodeProperties; const displayNameField = { @@ -87,7 +87,7 @@ const displayNameField = { name: 'displayName', type: 'string', default: '', - description: 'This value is used in place of the worker\'s actual name within sms notifications, delivery tracking pages, and across organization boundaries.', + description: 'This value is used in place of the worker\'s actual name within sms notifications, delivery tracking pages, and across organization boundaries', } as INodeProperties; // Vehicles fields @@ -96,7 +96,7 @@ const vehicleField = { name: 'vehicle', type: 'boolean', default: false, - description: 'Whether the worker has vehicle or not.', + description: 'Whether the worker has vehicle or not', } as INodeProperties; const vehicleTypeField = { @@ -122,7 +122,7 @@ const vehicleTypeField = { }, ], default: 'CAR', - description: 'Whether the worker has vehicle or not.', + description: 'Whether the worker has vehicle or not', } as INodeProperties; const vehicleDescriptionField = { @@ -130,7 +130,7 @@ const vehicleDescriptionField = { name: 'description', type: 'string', default: '', - description: 'The vehicle\'s make, model, year, or any other relevant identifying details.', + description: 'The vehicle\'s make, model, year, or any other relevant identifying details', } as INodeProperties; const vehicleLicensePlateField = { @@ -138,7 +138,7 @@ const vehicleLicensePlateField = { name: 'licensePlate', type: 'string', default: '', - description: 'The vehicle\'s license plate number.', + description: 'The vehicle\'s license plate number', } as INodeProperties; const vehicleColorField = { @@ -146,7 +146,7 @@ const vehicleColorField = { name: 'color', type: 'string', default: '', - description: 'The vehicle\'s color.', + description: 'The vehicle\'s color', } as INodeProperties; const teamsField = { @@ -154,7 +154,7 @@ const teamsField = { name: 'teams', type: 'json', default: '[]', - description: 'One or more team IDs of which the worker is a member.', + description: 'One or more team IDs of which the worker is a member', } as INodeProperties; const teamsFilterField = { @@ -162,7 +162,7 @@ const teamsFilterField = { name: 'teams', type: 'string', default: '', - description: 'A comma-separated list of the team IDs that workers must be part of.', + description: 'A comma-separated list of the team IDs that workers must be part of', } as INodeProperties; const statesFilterField = { @@ -184,7 +184,7 @@ const statesFilterField = { }, ], default: '', - description: 'List of worker states.', + description: 'List of worker states', } as INodeProperties; const phonesFilterField = { @@ -192,7 +192,7 @@ const phonesFilterField = { name: 'phones', type: 'string', default: '', - description: 'A comma-separated list of workers\' phone numbers.', + description: 'A comma-separated list of workers\' phone numbers', } as INodeProperties; const filterField = { @@ -200,7 +200,7 @@ const filterField = { name: 'filter', type: 'string', default: '', - description: 'A comma-separated list of fields to return, if all are not desired. For example, name, location.', + description: 'A comma-separated list of fields to return, if all are not desired. For example, name, location', } as INodeProperties; const longitudeFilterField = { @@ -211,7 +211,7 @@ const longitudeFilterField = { numberPrecision: 14, }, default: '', - description: 'The longitude component of the coordinate pair.', + description: 'The longitude component of the coordinate pair', } as INodeProperties; const latitudeFilterField = { @@ -222,7 +222,7 @@ const latitudeFilterField = { numberPrecision: 14, }, default: '', - description: 'The latitude component of the coordinate pair.', + description: 'The latitude component of the coordinate pair', } as INodeProperties; const radiusFilterField = { @@ -234,7 +234,7 @@ const radiusFilterField = { minValue: 0, }, default: 1000, - description: 'The length in meters of the radius of the spherical area in which to look for workers. Defaults to 1000 if missing. Maximum value is 10000.', + description: 'The length in meters of the radius of the spherical area in which to look for workers. Defaults to 1000 if missing. Maximum value is 10000', } as INodeProperties; const scheduleDateField = { @@ -242,7 +242,7 @@ const scheduleDateField = { name: 'date', type: 'dateTime', default: Date.now(), - description: 'Schedule\'s date.', + description: 'Schedule\'s date', } as INodeProperties; const scheduleTimezoneField = { @@ -250,7 +250,7 @@ const scheduleTimezoneField = { name: 'timezone', type: 'string', default: '', - description: 'A valid timezone.', + description: 'A valid timezone', } as INodeProperties; const scheduleStartField = { @@ -258,7 +258,7 @@ const scheduleStartField = { name: 'start', type: 'dateTime', default: Date.now(), - description: 'Start time.', + description: 'Start time', } as INodeProperties; const scheduleEndField = { @@ -266,7 +266,7 @@ const scheduleEndField = { name: 'end', type: 'dateTime', default: Date.now(), - description: 'End time.', + description: 'End time', } as INodeProperties; export const workerFields = [ @@ -288,7 +288,7 @@ export const workerFields = [ }, default: '', required: true, - description: 'The ID of the worker object for lookup.', + description: 'The ID of the worker object for lookup', }, { displayName: 'Analytics', @@ -302,7 +302,7 @@ export const workerFields = [ }, default: true, required: true, - description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics.', + description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics', }, { ...nameField, From 9e597ec5010a08e04c1dbdeefb03fda108922109 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Thu, 27 Jan 2022 09:38:53 -0500 Subject: [PATCH 07/12] feat: added fixes according to comments made on the n8n PR added new fixed collections, refactored the code according to comments made on the n8n pr --- .../nodes/Onfleet/GenericFunctions.ts | 78 ++- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 568 +++++++++++------- packages/nodes-base/nodes/Onfleet/Onfleet.png | Bin 1327 -> 0 bytes packages/nodes-base/nodes/Onfleet/Onfleet.svg | 14 + .../nodes-base/nodes/Onfleet/Onfleet@2x.png | Bin 2913 -> 0 bytes .../nodes/Onfleet/OnfleetTrigger.node.ts | 89 +-- .../descriptions/AdministratorDescription.ts | 32 +- .../descriptions/ContainerDescription.ts | 51 +- .../descriptions/DestinationDescription.ts | 326 ++++------ .../Onfleet/descriptions/HubDescription.ts | 64 +- .../descriptions/OnfleetWebhookDescription.ts | 4 +- .../descriptions/OrganizationDescription.ts | 10 +- .../descriptions/RecipientDescription.ts | 165 +++-- .../Onfleet/descriptions/TaskDescription.ts | 129 ++-- .../Onfleet/descriptions/TeamDescription.ts | 324 +++++----- .../descriptions/WebhookDescription.ts | 26 +- .../Onfleet/descriptions/WorkerDescription.ts | 483 ++++++++++----- .../nodes-base/nodes/Onfleet/interfaces.ts | 12 +- 18 files changed, 1367 insertions(+), 1008 deletions(-) delete mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.png create mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet.svg delete mode 100644 packages/nodes-base/nodes/Onfleet/Onfleet@2x.png diff --git a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts index 5e8da96ed19af..b5f540516d5c4 100644 --- a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts @@ -1,5 +1,7 @@ import { + ICredentialDataDecryptedObject, IDataObject, + INodePropertyOptions, JsonObject, NodeApiError } from 'n8n-workflow'; @@ -14,6 +16,8 @@ import { OptionsWithUri, } from 'request'; +import * as moment from 'moment-timezone'; + export async function onfleetApiRequest( this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, @@ -21,9 +25,7 @@ export async function onfleetApiRequest( resource: string, body: any = {}, // tslint:disable-line:no-any qs?: any, // tslint:disable-line:no-any - uri?: string, - headers: IDataObject = {}, - option: IDataObject = {}): Promise { // tslint:disable-line:no-any + uri?: string): Promise { // tslint:disable-line:no-any const options: OptionsWithUri = { headers: { 'Content-Type': 'application/json', @@ -40,17 +42,63 @@ export async function onfleetApiRequest( //@ts-ignore return await this.helpers.request(options); } catch (error) { - const apiError = error as IDataObject; - const { message: messageError } = apiError.error as IDataObject; - if (messageError) { - const { message = '', cause = '' } = messageError as IDataObject; - if (message && cause) { - apiError.message = `${message}: ${cause}`; - } else { - apiError.message = message; - } - throw new NodeApiError(this.getNode(), apiError as JsonObject); - } - throw new NodeApiError(this.getNode(), apiError as JsonObject); + throw new NodeApiError(this.getNode(), error as JsonObject); // TODO: Check error } } + +export const resourceLoaders = { + async getTeams(this: ILoadOptionsFunctions): Promise { + try { + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const teams = await onfleetApiRequest.call(this, 'GET', encodedApiKey, 'teams') as IDataObject[]; + return teams.map(({name = '', id: value = ''}) => ( {name, value} )) as INodePropertyOptions[]; + } catch (error) { + return []; + } + }, + + async getWorkers(this: ILoadOptionsFunctions): Promise { + try { + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const workers = await onfleetApiRequest.call(this, 'GET', encodedApiKey, 'workers') as IDataObject[]; + return workers.map(({name = '', id: value = ''}) => ( {name, value} )) as INodePropertyOptions[]; + } catch (error) { + return []; + } + }, + + async getAdmins (this: ILoadOptionsFunctions): Promise { + try { + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const admins = await onfleetApiRequest.call(this, 'GET', encodedApiKey, 'admins') as IDataObject[]; + return admins.map(({name = '', id: value = ''}) => ( {name, value} )) as INodePropertyOptions[]; + } catch (error) { + return []; + } + }, + + async getHubs (this: ILoadOptionsFunctions): Promise { + try { + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const hubs = await onfleetApiRequest.call(this, 'GET', encodedApiKey, 'hubs') as IDataObject[]; + return hubs.map(({name = '', id: value = ''}) => ( {name, value} )) as INodePropertyOptions[]; + } catch (error) { + return []; + } + }, + + async getTimezones(this: ILoadOptionsFunctions): Promise { + const returnData = [] as INodePropertyOptions[]; + for (const timezone of moment.tz.names()) { + returnData.push({ + name: timezone, + value: timezone, + }); + } + return returnData; + }, +}; diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index 9d126d75d9c3c..a66c271a1fa10 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -5,8 +5,11 @@ import { INodeType, INodeTypeDescription, } from 'n8n-workflow'; +import * as moment from 'moment-timezone'; + import { OnfleetAdmins, + OnfleetCloneOverrideTaskOptions, OnfleetCloneTask, OnfleetCloneTaskOptions, OnfleetDestination, @@ -22,13 +25,14 @@ import { OnfleetWorker, OnfleetWorkerEstimates, OnfleetWorkerFilter, - OnfleetWorkerSchedule + OnfleetWorkerSchedule, + OnfleetWorkerScheduleEntry } from './interfaces'; import { taskFields, taskOperations } from './descriptions/TaskDescription'; import { IExecuteFunctions } from 'n8n-core'; import { destinationFields, destinationOperations } from './descriptions/DestinationDescription'; -import { onfleetApiRequest } from './GenericFunctions'; +import { onfleetApiRequest, resourceLoaders } from './GenericFunctions'; import { recipientFields, recipientOperations } from './descriptions/RecipientDescription'; import { organizationFields, organizationOperations } from './descriptions/OrganizationDescription'; import { adminFields, adminOperations } from './descriptions/AdministratorDescription'; @@ -42,7 +46,7 @@ export class Onfleet implements INodeType { description: INodeTypeDescription = { displayName: 'Onfleet', name: 'onfleet', - icon: 'file:Onfleet.png', + icon: 'file:Onfleet.svg', group: [ 'input' ], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', @@ -67,74 +71,119 @@ export class Onfleet implements INodeType { type: 'options', options: [ { - name: 'Admins', - value: 'admins', + name: 'Admin', + value: 'admin', }, { - name: 'Containers', - value: 'containers', + name: 'Container', + value: 'container', }, { - name: 'Destinations', - value: 'destinations', + name: 'Destination', + value: 'destination', }, { - name: 'Organization', - value: 'organizations', + name: 'Hub', + value: 'hub', }, { - name: 'Recipients', - value: 'recipients', + name: 'Organization', + value: 'organization', }, { - name: 'Tasks', - value: 'tasks', + name: 'Recipient', + value: 'recipient', }, { - name: 'Teams', - value: 'teams', + name: 'Task', + value: 'task', }, { - name: 'Workers', - value: 'workers', + name: 'Team', + value: 'team', }, { - name: 'Webhooks', - value: 'webhooks', + name: 'Webhook', + value: 'webhook', }, { - name: 'Hubs', - value: 'hubs', + name: 'Worker', + value: 'worker', }, ], - default: 'tasks', + default: 'task', description: 'The resource to perform operations on', }, - // Operations + // Operations & fields ...adminOperations, - ...recipientOperations, - ...taskOperations, - ...destinationOperations, - ...organizationOperations, - ...hubOperations, - ...workerOperations, - ...webhookOperations, - ...containerOperations, - ...teamOperations, - // Display Fields ...adminFields, + ...containerOperations, + ...containerFields, + ...destinationOperations, ...destinationFields, + ...hubOperations, + ...hubFields, + ...organizationOperations, + ...organizationFields, + ...recipientOperations, ...recipientFields, + ...taskOperations, ...taskFields, - ...organizationFields, - ...hubFields, - ...workerFields, - ...webhookFields, - ...containerFields, + ...teamOperations, ...teamFields, + ...webhookOperations, + ...webhookFields, + ...workerOperations, + ...workerFields, ], }; + methods = { + loadOptions: resourceLoaders, + }; + + static formatAddress ( + unparsed: boolean, + address: string, + addressNumber: string, + addressStreet: string, + addressCity: string, + addressCountry: string, + additionalFields: IDataObject, + ): OnfleetDestination { + let destination: OnfleetDestination; + if (unparsed) { + destination = { address: { unparsed: address } }; + } else { + destination = { + address: { + number: addressNumber, + street: addressStreet, + city: addressCity, + country: addressCountry, + }, + }; + } + + // Adding destination extra fields + if (additionalFields.addressName) { + destination.address.name = additionalFields.addressName as string; + } + if (additionalFields.addressApartment) { + destination.address.apartment = additionalFields.addressApartment as string; + } + if (additionalFields.addressState) { + destination.address.state = additionalFields.addressState as string; + } + if (additionalFields.addressPostalCode) { + destination.address.postalCode = additionalFields.addressPostalCode as string; + } + if (additionalFields.addressNotes) { + destination.notes = additionalFields.addressNotes as string; + } + return destination; + } + /** * Gets the properties of a destination according to the operation chose * @param this Current node execution function @@ -142,49 +191,46 @@ export class Onfleet implements INodeType { * @param operation Current destination opration * @returns {OnfleetDestination} Destination information */ - static getDestinationFields(this: IExecuteFunctions, item: number, operation: string) { + static getDestinationFields( + this: IExecuteFunctions, item: number, operation: string, shared = false, + ): OnfleetDestination | OnfleetDestination[] | null { if (['create', 'createBatch', 'update'].includes(operation)) { /* -------------------------------------------------------------------------- */ /* Get fields for create, createBatch and update task */ /* -------------------------------------------------------------------------- */ - const unparsed = this.getNodeParameter('unparsed', item) as boolean; - const addDestinationFields = this.getNodeParameter('additionalDestinationFields', item) as IDataObject; - let destination: OnfleetDestination; - if (unparsed) { - destination = { - address: { - unparsed: this.getNodeParameter('address', item) as string, - }, - }; - } else { - destination = { - address: { - number: this.getNodeParameter('addressNumber', item) as string, - street: this.getNodeParameter('addressStreet', item) as string, - city: this.getNodeParameter('addressCity', item) as string, - country: this.getNodeParameter('addressCountry', item) as string, - }, - }; - } + if (shared) { + const { destinationProperties: destination } = this.getNodeParameter('destination', item) as IDataObject; - // Adding destination extra fields - if (addDestinationFields.addressName) { - destination.address.name = addDestinationFields.addressName as string; - } - if (addDestinationFields.addressApartment) { - destination.address.apartment = addDestinationFields.addressApartment as string; - } - if (addDestinationFields.addressState) { - destination.address.state = addDestinationFields.addressState as string; - } - if (addDestinationFields.addressPostalCode) { - destination.address.postalCode = addDestinationFields.addressPostalCode as string; - } - if (addDestinationFields.addressNotes) { - destination.notes = addDestinationFields.addressNotes as string; + if (!destination || Object.keys((destination) as IDataObject).length === 0) { + return []; + } + + const { + unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields, + } = destination as IDataObject; + return Onfleet.formatAddress( + unparsed as boolean, + address as string, + addressNumber as string, + addressStreet as string, + addressCity as string, + addressCountry as string, + additionalFields as IDataObject, + ) as OnfleetDestination; + } else { + const unparsed = this.getNodeParameter('unparsed', item) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const address = this.getNodeParameter('address', item) as string; + const addressNumber = this.getNodeParameter('addressNumber', item) as string; + const addressStreet = this.getNodeParameter('addressStreet', item) as string; + const addressCity = this.getNodeParameter('addressCity', item) as string; + const addressCountry = this.getNodeParameter('addressCountry', item) as string; + + return Onfleet.formatAddress( + unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields, + ) as OnfleetDestination; } - return destination; } return null; } @@ -214,10 +260,10 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields for update admin */ /* -------------------------------------------------------------------------- */ - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; const adminData: OnfleetAdmins = {}; // Adding additional fields - Object.assign(adminData, additionalFields); + Object.assign(adminData, updateFields); return adminData; } return null; @@ -235,30 +281,27 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields for create hub */ /* -------------------------------------------------------------------------- */ - const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination; const name = this.getNodeParameter('name', item) as string; - const { teams } = this.getNodeParameter('additionalFields', item) as IDataObject; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; const hubData: OnfleetHubs = { name, ...destination }; + // Adding additional fields - if (teams) { - Object.assign(hubData, { teams: JSON.parse(teams as string) }); - } + Object.assign(hubData, additionalFields); + return hubData; } else if (operation === 'update') { /* -------------------------------------------------------------------------- */ /* Get fields for update hub */ /* -------------------------------------------------------------------------- */ - const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination; const hubData: OnfleetHubs = { ...destination }; // Adding additional fields - const {teams, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; - if (teams) { - Object.assign(hubData, { teams: JSON.parse(teams as string) }); - } - Object.assign(hubData, additionalFields); + const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; + Object.assign(hubData, updateFields); return hubData; } return null; @@ -271,22 +314,21 @@ export class Onfleet implements INodeType { * @param operation Current worker opration * @returns {OnfleetWorker|OnfleetWorkerFilter|OnfleetWorkerSchedule} Worker information */ - static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | null { + static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | OnfleetWorkerSchedule | null { if (operation === 'create') { /* -------------------------------------------------------------------------- */ /* Get fields for create worker */ /* -------------------------------------------------------------------------- */ const name = this.getNodeParameter('name', item) as string; const phone = this.getNodeParameter('phone', item) as string; - const teams = JSON.parse(this.getNodeParameter('teams', item) as string) as string[]; - const vehicle = this.getNodeParameter('vehicle', item) as boolean; + const teams = this.getNodeParameter('teams', item) as string[]; + const { vehicleProperties: vehicle } = this.getNodeParameter('vehicle', item) as IDataObject; const workerData: OnfleetWorker = { name, phone, teams }; // Addding vehicule fields - if (vehicle) { - const type = this.getNodeParameter('type', item) as string; - const additionalVehicleFields = this.getNodeParameter('additionalVehicleFields', item) as IDataObject; - Object.assign(workerData, { vehicle: { type, ...additionalVehicleFields} }); + if (Object.keys((vehicle as IDataObject)).length > 0) { + const { type, additionalFields: additionalVehicleFields } = vehicle as IDataObject; + Object.assign(workerData, { vehicle: { type, ...(additionalVehicleFields as IDataObject) } }); } // Adding additional fields @@ -298,58 +340,60 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields for update worker */ /* -------------------------------------------------------------------------- */ - const vehicle = this.getNodeParameter('vehicle', item) as boolean; - const workerData: OnfleetWorker = {}; - - // Addding vehicule fields - if (vehicle) { - const type = this.getNodeParameter('type', item) as string; - const additionalVehicleFields = this.getNodeParameter('additionalVehicleFields', item) as IDataObject; - Object.assign(workerData, { vehicle: { type, ...additionalVehicleFields} }); - } + const {vehicleProperties} = this.getNodeParameter('vehicle', item) as IDataObject; + const { additionalFields: vehicle } = vehicleProperties as IDataObject; + const workerData: OnfleetWorker = { vehicle: (vehicle as IDataObject) }; // Adding additional fields - const {teams, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; - Object.assign(workerData, additionalFields); - if (teams) { - workerData.teams = JSON.parse(teams as string); - } + const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; + Object.assign(workerData, updateFields); return workerData; } else if (['getAll', 'get'].includes(operation)) { /* -------------------------------------------------------------------------- */ /* Get fields for get and getAll workers */ /* -------------------------------------------------------------------------- */ - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; - const workerFilter: OnfleetWorkerFilter = {}; - if (additionalFields.states) { - additionalFields.states = (additionalFields.states as number[]).join(','); - } - Object.assign(workerFilter, additionalFields); - return workerFilter; + const { + filter, states, teams, phones, analytics, ...filterFields + } = this.getNodeParameter('filterFields', item) as IDataObject; + const workerFilter: OnfleetWorkerFilter = {}; + + if (states) { + filterFields.states = (states as number[]).join(','); + } + if (filter) { + filterFields.filter = (filter as string[]).join(','); + } + if (teams) { + filterFields.teams = (teams as string[]).join(','); + } + if (phones) { + filterFields.phones = (phones as string[]).join(','); + } + if (typeof analytics === 'boolean') { + filterFields.analytics = analytics ? 'true' : 'false'; + } + + Object.assign(workerFilter, filterFields); + return workerFilter; } else if (operation === 'setSchedule') { /* -------------------------------------------------------------------------- */ - /* Get fields for setSchedule to worker */ + /* Set a worker schedule */ /* -------------------------------------------------------------------------- */ - const scheduleDate = new Date(this.getNodeParameter('date', item) as Date); - const timezone = this.getNodeParameter('timezone', item) as string; - const start = new Date(this.getNodeParameter('start', item) as Date); - const end = new Date(this.getNodeParameter('end', item) as Date); - const datestring = scheduleDate.getFullYear() - + '-' + (scheduleDate.getMonth() + 1).toString().padStart(2, '0') - + '-' + scheduleDate.getDate().toString().padStart(2, '0'); - const workerSchedule: OnfleetWorkerSchedule = { - entries: [ - { - date: datestring, - timezone, - shifts: [[ - start.getTime(), end.getTime(), - ]], - }, - ], - }; - return workerSchedule; + const { scheduleProperties } = this.getNodeParameter('schedule', item) as IDataObject; + const entries = (scheduleProperties as IDataObject[]).map(entry => { + const { timezone, date, shifts } = entry as IDataObject; + const { shiftsProperties } = shifts as IDataObject; + return { + timezone: timezone as string, + date: moment(new Date(date as Date)).format('YYYY-MM-DD'), + shifts: (shiftsProperties as IDataObject[]).map(({ start, end}) => [ + new Date(start as Date).getTime(), + new Date(end as Date).getTime(), + ]), + } as OnfleetWorkerScheduleEntry; + }) as OnfleetWorkerScheduleEntry[]; + return { entries } as OnfleetWorkerSchedule; } return null; } @@ -380,6 +424,25 @@ export class Onfleet implements INodeType { return null; } + static formatRecipient( + name: string, phone: string, additionalFields: IDataObject, + ): OnfleetRecipient { + const recipient: OnfleetRecipient = { name, phone }; + + // Adding recipient extra fields + if (additionalFields.recipientNotes) { + recipient.notes = additionalFields.recipientNotes as string; + } + if (additionalFields.recipientSkipSMSNotifications) { + recipient.skipSMSNotifications = additionalFields.recipientSkipSMSNotifications as boolean; + } + if (additionalFields.recipientSkipPhoneNumberValidation) { + recipient.skipPhoneNumberValidation = additionalFields.recipientSkipPhoneNumberValidation as boolean; + } + + return recipient; + } + /** * Gets the properties of a recipient according to the operation chose * @param this Current node execution function @@ -387,36 +450,52 @@ export class Onfleet implements INodeType { * @param operation Current recipient opration * @returns {OnfleetRecipient} Recipient information */ - static getRecipientFields(this: IExecuteFunctions, item: number, operation: string) { + static getRecipientFields( + this: IExecuteFunctions, item: number, operation: string, shared = false, multiple = false, + ): OnfleetRecipient | OnfleetRecipient[] | null { if (['create', 'createBatch'].includes(operation)) { /* -------------------------------------------------------------------------- */ /* Get fields to create recipient */ /* -------------------------------------------------------------------------- */ - const addRecipientFields = this.getNodeParameter('additionalRecipientFields', item) as IDataObject; - const recipient: OnfleetRecipient = { - name: this.getNodeParameter('recipientName', item) as string, - phone: this.getNodeParameter('recipientPhone', item) as string, - }; - - // Adding recipient extra fields - if (addRecipientFields.recipientNotes) { - recipient.notes = addRecipientFields.recipientNotes as string; - } - if (addRecipientFields.skipSMSNotifications) { - recipient.skipSMSNotifications = addRecipientFields.skipSMSNotifications as boolean; - } - if (addRecipientFields.skipPhoneNumberValidation) { - recipient.skipPhoneNumberValidation = addRecipientFields.skipPhoneNumberValidation as boolean; + if (shared) { + if (multiple) { + const { recipientProperties: recipients } = this.getNodeParameter('recipient', item) as IDataObject; + if (!recipients || Object.keys(recipients).length === 0) { + return []; + } + return (recipients as IDataObject[]).map(recipient => { + const { recipientName: name, recipientPhone: phone, additionalFields } = recipient as IDataObject; + return Onfleet.formatRecipient( + name as string, + phone as string, + additionalFields as IDataObject, + ); + }); + } else { + const { recipientProperties: recipient } = this.getNodeParameter('recipient', item) as IDataObject; + if (!recipient || Object.keys(recipient).length === 0) { + return null; + } + const { recipientName: name, recipientPhone: phone, additionalFields } = recipient as IDataObject; + return Onfleet.formatRecipient( + name as string, + phone as string, + additionalFields as IDataObject, + ); + } + } else { + const name = this.getNodeParameter('name', item) as string; + const phone = this.getNodeParameter('phone', item) as string; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + return Onfleet.formatRecipient(name, phone, additionalFields) as OnfleetRecipient; } - - return recipient; } else if (operation === 'update') { /* -------------------------------------------------------------------------- */ /* Get fields to update recipient */ /* -------------------------------------------------------------------------- */ const { recipientName: name = '', recipientPhone: phone = '', ...additionalFields - } = this.getNodeParameter('additionalFields', item) as IDataObject; + } = this.getNodeParameter('updateFields', item) as IDataObject; const recipientData: OnfleetRecipient = {}; @@ -430,6 +509,7 @@ export class Onfleet implements INodeType { Object.assign(recipientData, additionalFields); return recipientData; } + return null; } /** @@ -446,17 +526,12 @@ export class Onfleet implements INodeType { /* Get fields to create and createBatch tasks */ /* -------------------------------------------------------------------------- */ const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; - const destination = Onfleet.getDestinationFields.call(this, item, operation) as OnfleetDestination; + const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination; // Adding recipients information - const hasRecipient = this.getNodeParameter('recipient', item) as boolean; - const recipients: OnfleetRecipient[] = []; - if (hasRecipient) { - const recipient = Onfleet.getRecipientFields.call(this, item, operation) as OnfleetRecipient; - recipients.push(recipient); - } + const recipient = Onfleet.getRecipientFields.call(this, item, operation, true, false) as OnfleetRecipient; - const taskData: OnfleetTask = { destination, recipients }; + const taskData: OnfleetTask = { destination, recipients: [ recipient ] }; const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields; if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime(); if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime(); @@ -467,9 +542,9 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields to update task */ /* -------------------------------------------------------------------------- */ - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; const taskData: OnfleetTaskUpdate = {}; - const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields; + const { completeAfter = null, completeBefore = null, ...extraFields } = updateFields; if (completeAfter) taskData.completeAfter = new Date(completeAfter as Date).getTime(); if (completeBefore) taskData.completeBefore = new Date(completeBefore as Date).getTime(); Object.assign(taskData, extraFields); @@ -478,32 +553,49 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields to clone task */ /* -------------------------------------------------------------------------- */ - const optionFields = this.getNodeParameter('options', item) as IDataObject; + const { overrides, ...optionFields } = this.getNodeParameter('options', item) as IDataObject; + const { overrideProperties } = overrides as IDataObject; const options: OnfleetCloneTaskOptions = {}; if (optionFields.includeMetadata) options.includeMetadata = optionFields.includeMetadata as boolean; if (optionFields.includeBarcodes) options.includeBarcodes = optionFields.includeBarcodes as boolean; if (optionFields.includeDependencies) options.includeDependencies = optionFields.includeDependencies as boolean; - if (optionFields.overrides) options.overrides = optionFields.overrides as object; + + // Adding overrides data + if (overrideProperties && Object.keys(overrideProperties).length > 0) { + const { + notes, pickupTask, serviceTime, completeAfter, completeBefore, + } = overrideProperties as IDataObject; + const overridesData = {} as OnfleetCloneOverrideTaskOptions; + + if (notes) overridesData.notes = notes as string; + if (typeof pickupTask !== 'undefined') overridesData.pickupTask = pickupTask as boolean; + if (serviceTime) overridesData.serviceTime = serviceTime as number; + if (completeAfter) overridesData.completeAfter = new Date(completeAfter as Date).getTime(); + if (completeBefore) overridesData.completeBefore = new Date(completeBefore as Date).getTime(); + + options.overrides = overridesData; + } + return { options } as OnfleetCloneTask; } else if (operation === 'getAll') { /* -------------------------------------------------------------------------- */ /* Get fields to list tasks */ /* -------------------------------------------------------------------------- */ - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; + const filterFields = this.getNodeParameter('filterFields', item) as IDataObject; const listTaskData: OnfleetListTaskFilters = { from: new Date(this.getNodeParameter('from', 0) as Date).getTime(), }; // Adding extra fields to search tasks - if (additionalFields.to) { - listTaskData.to = new Date(additionalFields.to as Date).getTime(); + if (filterFields.to) { + listTaskData.to = new Date(filterFields.to as Date).getTime(); } - if (additionalFields.state) { - listTaskData.state = (additionalFields.state as number[]).join(','); + if (filterFields.state) { + listTaskData.state = (filterFields.state as number[]).join(','); } - if (additionalFields.lastId) { - listTaskData.lastId = additionalFields.lastId as string; + if (filterFields.lastId) { + listTaskData.lastId = filterFields.lastId as string; } return listTaskData; @@ -533,11 +625,11 @@ export class Onfleet implements INodeType { /* Get fields to create a team */ /* -------------------------------------------------------------------------- */ const name = this.getNodeParameter('name', item) as string; - const workers = this.getNodeParameter('workers', item) as string; - const managers = this.getNodeParameter('managers', item) as string; + const workers = this.getNodeParameter('workers', item) as string[]; + const managers = this.getNodeParameter('managers', item) as string[]; const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; - const teamData: OnfleetTeams = { name, workers: JSON.parse(workers), managers: JSON.parse(managers) }; + const teamData: OnfleetTeams = { name, workers, managers }; // Adding additional fields Object.assign(teamData, additionalFields); @@ -548,33 +640,35 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const teamData: OnfleetTeams = {}; // Adding additional fields - const {workers, managers, ...additionalFields} = this.getNodeParameter('additionalFields', item) as IDataObject; - if (workers) { - Object.assign(teamData, { workers: JSON.parse(workers as string) }); - } - if (managers) { - Object.assign(teamData, { managers: JSON.parse(managers as string) }); - } - Object.assign(teamData, additionalFields); + const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; + Object.assign(teamData, updateFields); return teamData; } else if (operation === 'getTimeEstimates') { /* -------------------------------------------------------------------------- */ /* Get driver time estimates for tasks that haven't been created yet */ /* -------------------------------------------------------------------------- */ - const dropoff = this.getNodeParameter('dropoff', item) as boolean; - const pickup = this.getNodeParameter('pickup', item) as boolean; - if (!dropoff && !pickup) throw new Error('At least 1 of dropoffLocation or pickupLocation must be selected'); - const longitudeField = `${dropoff ? 'dropoff' : 'pickup'}Longitude`; - const latitudeField = `${dropoff ? 'dropoff' : 'pickup'}Latitude`; - const longitude = this.getNodeParameter(longitudeField, item) as string; - const latitude = this.getNodeParameter(latitudeField, item) as string; + const { dropoffProperties } = this.getNodeParameter('dropoff', item) as IDataObject; + const { pickUpProperties } = this.getNodeParameter('pickUp', item) as IDataObject; + const dropoff = dropoffProperties as IDataObject; + const pickup = pickUpProperties as IDataObject; + const hasPickUp = pickup && Object.keys(pickup).length > 0; + const hasDropoff = dropoff && Object.keys(dropoff).length > 0; + + if (!hasPickUp && !hasDropoff) throw new Error('At least 1 of dropoffLocation or pickupLocation must be selected'); const workerTimeEstimates = {} as OnfleetWorkerEstimates; - if (pickup) { + if (hasPickUp) { + const { + pickupLongitude: longitude, pickupLatitude: latitude, additionalFields, + } = pickup; + const { pickupTime } = additionalFields as IDataObject; workerTimeEstimates.pickupLocation = `${longitude},${latitude}`; - workerTimeEstimates.pickupTime = (new Date(this.getNodeParameter('pickupTime', item) as Date)).getTime() / 1000; + if (pickupTime) { + workerTimeEstimates.pickupTime = moment(new Date(pickupTime as Date)).local().unix(); + } } - if(dropoff) { + if(hasDropoff) { + const {dropoffLongitude: longitude, dropoffLatitude: latitude} = dropoff; workerTimeEstimates.dropoffLocation = `${longitude},${latitude}`; } @@ -587,13 +681,23 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const teamAutoDispatch = {} as OnfleetTeamAutoDispatch; const { - taskTimeWindow, scheduleTimeWindow, ...additionalFields + scheduleTimeWindow, taskTimeWindow, ...additionalFields } = this.getNodeParameter('additionalFields', item) as IDataObject; - if (taskTimeWindow) { - teamAutoDispatch.taskTimeWindow= JSON.parse((taskTimeWindow as string)); + const { scheduleTimeWindowProperties } = scheduleTimeWindow as IDataObject; + const { taskTimeWindowProperties } = taskTimeWindow as IDataObject; + + if (scheduleTimeWindowProperties && Object.keys((scheduleTimeWindowProperties as IDataObject)).length > 0) { + const { startTime, endTime } = scheduleTimeWindowProperties as IDataObject; + teamAutoDispatch.scheduleTimeWindow = [ + moment(new Date(startTime as Date)).local().unix(), moment(new Date(endTime as Date)).local().unix(), + ]; } - if (scheduleTimeWindow) { - teamAutoDispatch.scheduleTimeWindow= JSON.parse((scheduleTimeWindow as string)); + + if (taskTimeWindowProperties && Object.keys((taskTimeWindowProperties as IDataObject)).length > 0) { + const { startTime, endTime } = taskTimeWindowProperties as IDataObject; + teamAutoDispatch.taskTimeWindow = [ + moment(new Date(startTime as Date)).local().unix(), moment(new Date(endTime as Date)).local().unix(), + ]; } Object.assign(teamAutoDispatch, additionalFields); @@ -652,7 +756,7 @@ export class Onfleet implements INodeType { /* Clone a task */ /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; - const taskData = Onfleet.getTaskFields.call(this, index, operation); + const taskData = Onfleet.getTaskFields.call(this, index, operation) as any; if (!taskData) { continue; } const path = `${resource}/${id}/clone`; responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, taskData)); @@ -982,19 +1086,30 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get all workers */ /* -------------------------------------------------------------------------- */ - const workerFilters = Onfleet.getWorkerFields.call(this, 0, operation) as OnfleetWorkerFilter; - - responseData.push(... await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource, {}, workerFilters)); + const byLocation = this.getNodeParameter('byLocation', index) as boolean; + + if (byLocation) { + const longitude = this.getNodeParameter('longitude', index) as string; + const latitude = this.getNodeParameter('latitude', index) as number; + const filterFields = this.getNodeParameter('filterFields', index) as IDataObject; + const path = `${resource}/location`; + const { workers } = await onfleetApiRequest.call( + this, 'GET', encodedApiKey, path, {}, { longitude, latitude, ...filterFields}, + ); + responseData.push(...workers); + } else { + const workerFilters = Onfleet.getWorkerFields.call(this, 0, operation) as OnfleetWorkerFilter; + + responseData.push(... await onfleetApiRequest.call(this, 'GET', encodedApiKey, resource, {}, workerFilters)); + } } else if (operation === 'get') { /* -------------------------------------------------------------------------- */ /* Get a worker */ /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const workerFilters = Onfleet.getWorkerFields.call(this, index, operation) as OnfleetWorkerFilter; - const analytics = this.getNodeParameter('analytics', index) as boolean; const path = `${resource}/${id}`; - workerFilters.analytics = analytics ? 'true' : 'false'; responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, workerFilters)); } else if (operation === 'create') { /* -------------------------------------------------------------------------- */ @@ -1024,16 +1139,6 @@ export class Onfleet implements INodeType { const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}/schedule`; responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); - } else if (operation === 'getAllByLocation') { - /* -------------------------------------------------------------------------- */ - /* Get worker location */ - /* -------------------------------------------------------------------------- */ - const longitude = this.getNodeParameter('longitude', index) as string; - const latitude = this.getNodeParameter('latitude', index) as number; - const additionalFields = this.getNodeParameter('additionalFields', index) as IDataObject; - const path = `${resource}/location`; - const { workers } = await onfleetApiRequest.call(this, 'GET', encodedApiKey, path, {}, { longitude, latitude }); - responseData.push(...workers); } else if (operation === 'setSchedule') { /* -------------------------------------------------------------------------- */ /* Set a worker schedule */ @@ -1138,9 +1243,9 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const containerId = this.getNodeParameter('containerId', index) as string; const containerType = this.getNodeParameter('containerType', index) as string; - const considerDependencies = this.getNodeParameter('considerDependencies', index) as boolean; + const options = this.getNodeParameter('options', index) as IDataObject; - const tasks = JSON.parse(this.getNodeParameter('tasks', index) as string) as Array; + const tasks = this.getNodeParameter('tasks', index) as Array; if (operation === 'add') { const type = this.getNodeParameter('type', index) as number; if (type === 1) { @@ -1150,9 +1255,10 @@ export class Onfleet implements INodeType { tasks.unshift(type); } } + const path = `${resource}/${containerType}/${containerId}`; responseData.push( - await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { tasks, considerDependencies }), + await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { tasks, ...options }), ); } } catch (error) { @@ -1256,19 +1362,19 @@ export class Onfleet implements INodeType { const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); const operations: { [ key:string ]: Function} = { - tasks: Onfleet.executeTaskOperations, - destinations: Onfleet.executeDestinationOperations, - organizations: Onfleet.executeOrganizationOperations, - admins: Onfleet.executeAdministratorOperations, - recipients: Onfleet.executeRecipientOperations, - hubs: Onfleet.executeHubOperations, - workers: Onfleet.executeWorkerOperations, - webhooks: Onfleet.executeWebhookOperations, - containers: Onfleet.executeContainerOperations, - teams: Onfleet.executeTeamOperations, + task: Onfleet.executeTaskOperations, + destination: Onfleet.executeDestinationOperations, + organization: Onfleet.executeOrganizationOperations, + admin: Onfleet.executeAdministratorOperations, + recipient: Onfleet.executeRecipientOperations, + hub: Onfleet.executeHubOperations, + worker: Onfleet.executeWorkerOperations, + webhook: Onfleet.executeWebhookOperations, + container: Onfleet.executeContainerOperations, + team: Onfleet.executeTeamOperations, }; - const responseData = await operations[resource].call(this, resource, operation, items, encodedApiKey); + const responseData = await operations[resource].call(this, `${resource}s`, operation, items, encodedApiKey); // Map data to n8n data return [this.helpers.returnJsonArray(responseData)]; } diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.png b/packages/nodes-base/nodes/Onfleet/Onfleet.png deleted file mode 100644 index 2bfbacd3e151d90aefaa36f5d6ebef0e30cc7d29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1327 zcma)+eLT|%9LIkiCXFS|)0Eayj)hv?E89edFl-!C5hV|qnj*VArHvd&b3_UF7TL-qB)n*k(M2 z9@y$(BM#8%CeO#eseH#>8CVmnypIuz5iWKCOU-E>@9j^aiCa0N&=O5|+HDIJ?;*T1 zNj)bNRa9WQBTv&B`ZF9=Fy-Y|PPRYvF7!HW(v{|D9`R6#A62MrL~WTe9C0+ifo|gZ z9G|aA6I2=zMUiX8xm|rtz=*$N$Yc1dy-Vd(sOq0HBU=fOZn(JFt;wbmT~y8EW&uMI8pr4cC4B{E*$P^&&i$WY(cJP7%RJf z2|o~r+VCl}dijl|6!yr*PF|x0?+Wx(d&ZF%ynPHY)GJ%mrXRiweM%*_Wu?#G^V6Yj zza>P2(>wm6586?23Y1%7ZLP=2kiyzQilHq6Q=`W$A#r+!lVm1Em=;N-nIT}SyYls$GEvZ)=KS_zHiUauXpzQD#m zXYr;l`m;#ylL)?5x76GQwmo6c^1(X;swr!7=ClFtXzOdfbattk=?q~IL6f@cfAdV;k>(#sLi_1st4a#Tji?|hv!jUt35Kw)-f5C_=t+1!ql~r)= b|3&MtMo}V9nw4d>`K)lq2~G_TLDYW$%42XD diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.svg b/packages/nodes-base/nodes/Onfleet/Onfleet.svg new file mode 100644 index 0000000000000..a8e2b261c1500 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.svg @@ -0,0 +1,14 @@ + + + Group 2 + + + + + + + + + + + diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet@2x.png b/packages/nodes-base/nodes/Onfleet/Onfleet@2x.png deleted file mode 100644 index 95311be0abc3cefbb24c8158fb9fa22b877c07b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2913 zcmeHJ)n5~i7T<_5V3Z;Vl3sPh1}GuYAxe&rNex8|YP5_V2nf=ps4!YW&`E8yl!7=J zDlnRnKe}U5s22V^(08*zK3;@Qs0GR$-P9b;-0Dv(M2w*&A;NMyv z!+*K~d5r(ne~sX2>Y#@B82H7IwF?gyxg^m(`?fz37j$p!JY@TSuqpA zD|k$eCpD;Z99cFV>N#QTe^MMA6m%fDF`ewmum8=OgDLTqF_W~b7C+x9P;8gFOy?k0YKM*ApE8hssIlsb7P+(m=U#kfmVs8{f_&I|Vi1nFW%&qD@^bExQ5@XyXw^Cj#h<5X)ujjI9q zW_hXkLd`VSxMB|lu7zTTrh{K{q0`$}*{Yd`B(o%cLVD@5*$iLp7^4ihAw9%;`BYgc zk6ARCZms*d)(_;;mjw3H6e`y8%80RLiG)G#8U5OSIBYArS!3Ua+8N1_b3fMk@ql2} z`^aS@*F~^pMZxquMzvA5&P$@f&pQQ!{g-*oY+;y*#g)bPh`8*pwl9J-gr#j)P&q{- z3sd^xP;Xp8EH5eJJ*7sRmg(5GN{Z~Kg-qj-?b*#V8gI7hH5!a%$W4^1ucNV`|2N;e z#jHS;qmoOBT&hq#^^piCU|nU#2uvwg+DyrWH#YrYdqbe|o?#kUINR{YMRDX4eVe!@d`SkLi&Axlb#s9PmtflPhTY4ctS2SXw4@- zScnr34U9~HNXDM2{rF;3yi+%#D3I3s*9**O4wu%xVx5VF&@sd zycoEhIY{l0Em~N5E9AZpV^AtM>sh*6kH2ngr*XEi@sV}tsOE!@&)(^XoE3NeV zsI z+xM@b%n@S2FFnGP6z%i;Pu{@jJ&y@{^Bcl#qB(jA4@x*px2{m3TjwVInyVwU7p9&a zP>gGnDhLq+mxk0elw;0RMu%;YHm6nA*18TtAIlkiI)2npN3k8W)bvc4UHqQst2!7M z_QH`Jw_NSoLLkyOCin0blrBf~wBhGB`<2+>-M3EmBKz!(%u1QBvT)0}ilDJS`29t5;qq|drC2YPp zgLVpp$;&@fT3eWQBT#a@XgVi|%HF5oLuQTkYsoQ1m#jpg!bL5yg4Z2pIWfO5797?q zy=5US@-{w|UL;e^u1UNEmkcK>=h2hmHy4qMEfnHR2;cz}U3er$1t4HPY*A{}_br)d zS**5ARcdwDZ~5%(c{ba4N_Q&+_AFKwu$E{@savi4Q2`iHUK@|_Q%Bj_bFNct8iq-B?oJI-+IKWspo}z^8gmj5=4f+KP*Om=Tlq><;^$y{A~m;{HV3&Y z3Z?NseaT<$T)&b5lmQ2BT(a9NUQOfz^ECi5dIQ_3wHZ#|-3l_G=SJ(eW-CFThF9#l zTfFU}%GJznm}3ut@xv$a!L<5s*TjcLzR$Nxl)CYXpP)+&L0#hE@3gr-Wpw_I~D-fYzrsU)9c%Z6z9 zbm#>qs5}L08GCSgVz__g*UYWhxG$HuiDaEaAszaiR*%i&bpzKlqFJu(aL#9#Tii(` z3wQq{RNLT{w234;0&M1t-Qkz|fVAyd`gysY`;7xN$f=3pFsC)im^SUhStKFT$)Vk51B<9J^c)^?F(&k=S?MmlMkFy5lwW3e`< z8V#f?;oK6Sc1O)tSCNTx4!BgMC~n(*xtcWCV=okT?3i?Lg8NWkQ=Ha**B9`j>K;zI zV;dr3EbY{k@$~ig;E(SRK2oNiPWq{{aq9rx{8D1;C}aQ(e5-!d>?3^b@z4^29?AYg z9cE--C8ci~DtQmqt9RnWS>*D9eXU9{z#2VF3{^yw#uFDN*PXz(-(W570HVW_H7>w2 znu5e(V-uAvMQdxG%?o`?jFP7PXz@J8w&TK=^IMCsMEmx@>Vc}A`WMv7kyaAewRV+x zyL3qz>GUk$_uU9qk;9>a#b{!TAHIyAcRXFd&;;(uU@RO_$oeX!S%|wKT|&NgTcKxN zMBF7Zc+XitO?-&4q9>pnICK4+gWS&sWi7iu@Cf`a;cM{l)9#2oIe!e~STQXHy!cPS z9*3#kH~V}G50uc>%$z*U#;cx~*g$z24sYW&o=OZa5;7xHUCz@I>(zTL0OFOrCBZ7g zv-_o#;Hs2A3mTSex)s;T^X%pB?=dFNL$l6h@`PgKd@`i9hnqelS6nNZl^ofrkZum3 nK;)1ZW(Q=V3+3Mb6AC?StjUy%tmokO_q{dHL)^scI7Iv#I9Xnj diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 72e8b100d0d93..58ef0e90517a1 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -20,7 +20,7 @@ export class OnfleetTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Onfleet Trigger', name: 'onfleetTrigger', - icon: 'file:Onfleet.png', + icon: 'file:Onfleet.svg', group: [ 'trigger' ], version: 1, subtitle: '={{$parameter["events"]}}', @@ -61,11 +61,12 @@ export class OnfleetTrigger implements INodeType { webhookMethods = { default: { async checkExists(this: IHookFunctions): Promise { - const webhookData = this.getWorkflowStaticData('node') as IDataObject; - const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; - const event = this.getNodeParameter('event', 0) as string; const { name = '' } = this.getNodeParameter('additionalFields', 0) as IDataObject; + const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const event = this.getNodeParameter('event', 0) as string; + const webhookData = this.getWorkflowStaticData('node') as IDataObject; + const webhookUrl = this.getNodeWebhookUrl('default') as string; if (!webhookData[event] || typeof webhookData[event] !== 'string') { // No webhook id is set so no webhook can exist @@ -78,25 +79,22 @@ export class OnfleetTrigger implements INodeType { try { const webhooks = await onfleetApiRequest.call(this, 'GET', encodedApiKey, endpoint); // tslint:disable-next-line: no-any - const exist = webhooks.some((webhook: any) => webhook.id === webhookData[event]); - if (!exist) { - delete webhookData[event]; - } else { - // Changing the name if it's different - // tslint:disable-next-line: no-any - const webhook = webhooks.find((webhook: any) => webhook.id === webhookData[event]); - - // Webhook name according to the field - let newWebhookName = `[N8N] ${webhookMapping[event].name}`; - if (name) { - newWebhookName = `[N8N] ${name}`; - } - - // If webhook name is different so, it's updated - if (webhook && webhook.name !== newWebhookName) { - const path = `${endpoint}/${webhook.id}`; - await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { name: newWebhookName }); - } + const exist = webhooks.some((webhook: any) => webhook.url === webhookUrl); + + // Changing the name if it's different + // tslint:disable-next-line: no-any + const webhook = webhooks.find((webhook: any) => webhook.url === webhookUrl); + + // Webhook name according to the field + let newWebhookName = `[N8N] ${webhookMapping[event].name}`; + if (name) { + newWebhookName = `[N8N] ${name}`; + } + + // If webhook name is different so, it's updated + if (webhook && webhook.name !== newWebhookName) { + const path = `${endpoint}/${webhook.id}`; + await onfleetApiRequest.call(this, 'PUT', encodedApiKey, path, { name: newWebhookName }); } return exist; } catch (error) { @@ -113,12 +111,12 @@ export class OnfleetTrigger implements INodeType { }, async create(this: IHookFunctions): Promise { - const webhookUrl = this.getNodeWebhookUrl('default') as string; + const { name = '' } = this.getNodeParameter('additionalFields', 0) as IDataObject; const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; - const webhookData = this.getWorkflowStaticData('node'); - const event = this.getNodeParameter('event', 0) as string; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); - const { name = '' } = this.getNodeParameter('additionalFields', 0) as IDataObject; + const event = this.getNodeParameter('event', 0) as string; + const webhookData = this.getWorkflowStaticData('node'); + const webhookUrl = this.getNodeWebhookUrl('default') as string; if (webhookUrl.includes('//localhost')) { throw new NodeOperationError(this.getNode(), 'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!'); @@ -145,21 +143,11 @@ export class OnfleetTrigger implements INodeType { throw new NodeApiError(this.getNode(), responseData, { message: 'Onfleet webhook creation response did not contain the expected data' }); } - webhookData[event] = responseData.id as string; return Promise.resolve(true); }); } catch (error) { const { httpCode = '' } = error as { httpCode: string }; if (httpCode === '422') { - // Webhook exists already - - // Get the data of the already registered webhook - onfleetApiRequest.call(this, 'GET', encodedApiKey, path) - .then((responseData: IDataObject[]) => { - const webhook = responseData.find(webhook => webhook.url === webhookUrl); - webhookData[event] = webhook!.id; - return Promise.resolve(true); - }); throw new NodeOperationError(this.getNode(), 'A webhook with the identical URL probably exists already. Please delete it manually in Onfleet!'); } @@ -168,24 +156,15 @@ export class OnfleetTrigger implements INodeType { return true; }, async delete(this: IHookFunctions): Promise { - const webhookData = this.getWorkflowStaticData('node'); const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; - const event = this.getNodeParameter('event', 0) as string; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + const webhookUrl = this.getNodeWebhookUrl('default') as string; - if (webhookData[event] !== undefined) { - const endpoint = `/webhooks/${webhookData[event]}`; - - try { - await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, endpoint); - } catch (error) { - return false; - } - - // Remove from the static workflow data so that it is clear - // that no webhooks are registred anymore - delete webhookData[event]; - } + // Get the data of the already registered webhook + const webhooks = await onfleetApiRequest.call(this, 'GET', encodedApiKey, 'webhooks'); + const webhook = webhooks.find((webhook: IDataObject) => webhook.url === webhookUrl); + const endpoint = `/webhooks/${webhook.id}`; + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, endpoint); return true; }, @@ -209,11 +188,7 @@ export class OnfleetTrigger implements INodeType { } const bodyData = this.getBodyData(); - const returnData: IDataObject[] = [{ - body: bodyData, - headers: this.getHeaderData(), - query: this.getQueryData(), - }]; + const returnData: IDataObject = bodyData; return { workflowData: [ diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts index 027d8ec323468..375706b90bebd 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -9,7 +9,7 @@ export const adminOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], }, }, options: [ @@ -19,14 +19,14 @@ export const adminOperations = [ description: 'Create a new Onfleet admin', }, { - name: 'Remove', + name: 'Delete', value: 'delete', - description: 'Remove an Onfleet admin', + description: 'Delete an Onfleet admin', }, { - name: 'List', + name: 'Get all', value: 'getAll', - description: 'List all Onfleet admins', + description: 'Get all Onfleet admins', }, { name: 'Update', @@ -72,12 +72,12 @@ const adminReadOnlyField = { export const adminFields = [ { - displayName: 'ID', + displayName: 'Admin ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], }, hide: { operation: [ @@ -93,7 +93,7 @@ export const adminFields = [ { displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], operation: [ 'create' ], }, }, @@ -103,7 +103,7 @@ export const adminFields = [ { displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], operation: [ 'create' ], }, }, @@ -111,14 +111,14 @@ export const adminFields = [ ...adminEmailField, }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], operation: [ 'create' ], }, }, @@ -128,14 +128,14 @@ export const adminFields = [ ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'admins' ], + resource: [ 'admin' ], operation: [ 'update' ], }, }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts index d02726cef778b..5af0b137da2b3 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -9,7 +9,7 @@ export const containerOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], }, }, options: [ @@ -24,7 +24,7 @@ export const containerOperations = [ description: 'Fully replace a container\'s tasks', }, { - name: 'Get container', + name: 'Get', value: 'get', description: 'Get container information', }, @@ -34,7 +34,7 @@ export const containerOperations = [ ] as INodeProperties[]; const containerTypeField = { - displayName: 'Container', + displayName: 'Container Type', name: 'containerType', type: 'options', options: [ @@ -56,7 +56,7 @@ const containerTypeField = { } as INodeProperties; const containerIdField = { - displayName: 'ID', + displayName: 'Container ID', name: 'containerId', type: 'string', default: '', @@ -64,7 +64,7 @@ const containerIdField = { } as INodeProperties; const insertTypeField = { - displayName: 'Insert type', + displayName: 'Insert Type', name: 'type', type: 'options', options: [ @@ -89,20 +89,24 @@ const indexField = { displayName: 'Index', name: 'index', type: 'number', - default: '', + default: 0, description: 'The index given indicates the position where the tasks are going to be inserted', } as INodeProperties; const tasksField = { - displayName: 'Tasks (JSON)', + displayName: 'Tasks', name: 'tasks', - type: 'json', - default: '[]', - description: 'Array witht the task\'s ID that are going to be used in JSON format', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Task', + }, + default: [], + description: 'Task\'s ID that are going to be used', } as INodeProperties; const considerDependenciesField = { - displayName: 'Consider dependencies', + displayName: 'Consider Dependencies', name: 'considerDependencies', type: 'boolean', default: false, @@ -114,7 +118,7 @@ export const containerFields = [ ...containerTypeField, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'get', 'add', @@ -128,7 +132,7 @@ export const containerFields = [ ...containerIdField, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'get', 'add', @@ -142,7 +146,7 @@ export const containerFields = [ ...insertTypeField, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'add' ], }, }, @@ -152,7 +156,7 @@ export const containerFields = [ ...indexField, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'add' ], type: [ 1 ], }, @@ -163,7 +167,7 @@ export const containerFields = [ ...tasksField, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'add', 'update', @@ -173,16 +177,25 @@ export const containerFields = [ required: true, }, { - ...considerDependenciesField, + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, displayOptions: { show: { - resource: [ 'containers' ], + resource: [ 'container' ], operation: [ 'add', 'update', ], }, }, - required: true, + options: [ + { + ...considerDependenciesField, + required: false, + }, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 9e99d76b955a5..4f72445803885 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -9,7 +9,7 @@ export const destinationOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'destinations' ], + resource: [ 'destination' ], }, }, options: [ @@ -30,7 +30,7 @@ export const destinationOperations = [ ] as INodeProperties[]; const unparsedField = { - displayName: 'Unparsed adress', + displayName: 'Unparsed Address', name: 'unparsed', type: 'boolean', description: 'Whether the address is specified in a single', @@ -38,7 +38,7 @@ const unparsedField = { } as INodeProperties; const unparsedAddressField = { - displayName: 'Destination address', + displayName: 'Destination Address', name: 'address', type: 'string', description: 'The destination\'s street address details', @@ -78,7 +78,7 @@ const unparsedAddressCountryField = { } as INodeProperties; const addressNameField = { - displayName: 'Address name', + displayName: 'Address Name', name: 'addressName', type: 'string', default: '', @@ -94,7 +94,7 @@ const addressApartmentField = { } as INodeProperties; const addressNoteField = { - displayName: 'Address notes', + displayName: 'Address Notes', name: 'addressNotes', type: 'string', default: '', @@ -102,21 +102,121 @@ const addressNoteField = { } as INodeProperties; const addressPostalCodeField = { - displayName: 'Postal code', + displayName: 'Postal Code', name: 'addressPostalCode', type: 'string', default: '', description: 'The postal or zip code', } as INodeProperties; +export const destinationExternalField = { + displayName: 'Destination', + name: 'destination', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Destination Properties', + name: 'destinationProperties', + default: {}, + values: [ + { + ...unparsedField, + required: false, + }, + { + ...unparsedAddressField, + displayOptions: { + show: { + unparsed: [ true ], + }, + }, + required: true, + }, + { + ...unparsedAddressNumberField, + displayOptions: { + show: { + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressStreetField, + displayOptions: { + show: { + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCityField, + displayOptions: { + show: { + unparsed: [ false ], + }, + }, + required: true, + }, + { + ...unparsedAddressCountryField, + displayOptions: { + show: { + unparsed: [ false ], + }, + }, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + unparsed: [ true ], + }, + }, + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + ], + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + unparsed: [ false ], + }, + }, + options: [ + addressNameField, + addressApartmentField, + addressNoteField, + addressPostalCodeField, + ], + }, + ], + }, + ], + } as INodeProperties; + export const destinationFields = [ { - displayName: 'ID', + displayName: 'Destination ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'destinations' ], + resource: [ 'destination' ], }, hide: { operation: [ 'create' ], @@ -130,15 +230,8 @@ export const destinationFields = [ ...unparsedField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], }, }, required: true, @@ -147,15 +240,8 @@ export const destinationFields = [ ...unparsedAddressField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ true ], }, }, @@ -165,15 +251,8 @@ export const destinationFields = [ ...unparsedAddressNumberField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ false ], }, }, @@ -183,15 +262,8 @@ export const destinationFields = [ ...unparsedAddressStreetField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ false ], }, }, @@ -201,15 +273,8 @@ export const destinationFields = [ ...unparsedAddressCityField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ false ], }, }, @@ -219,37 +284,23 @@ export const destinationFields = [ ...unparsedAddressCountryField, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ false ], }, }, required: true, }, { - displayName: 'Additional destination fields', - name: 'additionalDestinationFields', + displayName: 'Additional Fields', + name: 'additionalFields', type: 'collection', - placeholder: 'Add destination fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ true ], }, }, @@ -260,135 +311,18 @@ export const destinationFields = [ ], }, { - displayName: 'Additional destination fields', - name: 'additionalDestinationFields', + displayName: 'Additional Fields', + name: 'additionalFields', type: 'collection', - placeholder: 'Add destination fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ - 'tasks', - 'hubs', - 'destinations', - ], - operation: [ - 'create', - 'createBatch', - ], - unparsed: [ - false, - null, - ], - }, - }, - options: [ - addressNameField, - addressApartmentField, - addressNoteField, - addressPostalCodeField, - ], - }, - { - ...unparsedField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - }, - }, - required: true, - }, - { - ...unparsedAddressField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ true ], - }, - }, - required: true, - }, - { - ...unparsedAddressNumberField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ false ], - }, - }, - required: true, - }, - { - ...unparsedAddressStreetField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ false ], - }, - }, - required: true, - }, - { - ...unparsedAddressCityField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ false ], - }, - }, - required: true, - }, - { - ...unparsedAddressCountryField, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], + resource: [ 'destination' ], + operation: [ 'create' ], unparsed: [ false ], }, }, - required: true, - }, - { - displayName: 'Additional destination fields', - name: 'additionalDestinationFields', - type: 'collection', - placeholder: 'Add destination fields', - default: {}, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ true ], - }, - }, - options: [ - addressNameField, - addressApartmentField, - addressNoteField, - ], - }, - { - displayName: 'Additional destination fields', - name: 'additionalDestinationFields', - type: 'collection', - placeholder: 'Add destination fields', - default: {}, - displayOptions: { - show: { - resource: [ 'hubs' ], - operation: [ 'update' ], - unparsed: [ - false, - null, - ], - }, - }, options: [ addressNameField, addressApartmentField, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index 324661d8df4a6..46e25a62fcffe 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -1,6 +1,7 @@ import { INodeProperties } from 'n8n-workflow'; +import { destinationExternalField } from './DestinationDescription'; export const hubOperations = [ { @@ -9,7 +10,7 @@ export const hubOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'hubs' ], + resource: [ 'hub' ], }, }, options: [ @@ -19,9 +20,9 @@ export const hubOperations = [ description: 'Create a new Onfleet hub', }, { - name: 'List hubs', + name: 'Get all', value: 'getAll', - description: 'List Onfleet hubs', + description: 'Get all Onfleet hubs', }, { name: 'Update', @@ -29,7 +30,7 @@ export const hubOperations = [ description: 'Update an Onfleet hub', }, ], - default: 'get', + default: 'getAll', }, ] as INodeProperties[]; @@ -42,21 +43,24 @@ const nameField = { } as INodeProperties; const teamsField = { - displayName: 'Teams (JSON)', + displayName: 'Teams', name: 'teams', - type: 'json', - default: '[]', - description: 'This is the team ID(s) that this Hub will be assigned to', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getTeams', + }, + default: [], + description: 'These are the teams that this Hub will be assigned to', } as INodeProperties; export const hubFields = [ { - displayName: 'ID', + displayName: 'Hub ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'hubs' ], + resource: [ 'hub' ], operation: [ 'update' ], }, }, @@ -68,41 +72,61 @@ export const hubFields = [ ...nameField, displayOptions: { show: { - resource: [ 'hubs' ], + resource: [ 'hub' ], operation: [ 'create' ], }, }, required: true, }, { - displayName: 'Additional fields', + ...destinationExternalField, + displayOptions: { + show: { + resource: [ 'hub' ], + operation: [ + 'create', + 'update', + ], + }, + }, + }, + { + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'hubs' ], + resource: [ 'hub' ], operation: [ 'create' ], }, }, - options: [ teamsField ], + options: [ + { + ...teamsField, + require: false, + }, + ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'hubs' ], + resource: [ 'hub' ], operation: [ 'update' ], }, }, options: [ nameField, - teamsField, + { + ...teamsField, + required: false, + }, ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts index f5207eede5e10..7d0fe7e2ca71d 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts @@ -17,10 +17,10 @@ export const eventDisplay: INodeProperties = { }; export const eventNameField = { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, options: [ { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts index 3353edfd3f453..f3abfa9d26578 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -9,17 +9,17 @@ export const organizationOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'organizations' ], + resource: [ 'organization' ], }, }, options: [ { - name: 'Get details', + name: 'Get My Organization', value: 'get', description: 'Retrieve your own organization\'s details', }, { - name: 'Get delegatee details', + name: 'Get Delegatee Details', value: 'getDelegatee', description: 'Retrieve the details of an organization with which you are connected', }, @@ -31,12 +31,12 @@ export const organizationOperations = [ export const organizationFields = [ { - displayName: 'ID', + displayName: 'Organiation ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'organizations' ], + resource: [ 'organization' ], operation: [ 'getDelegatee' ], }, }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index cd10fd611c80f..8478d5413a6b3 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -9,7 +9,7 @@ export const recipientOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], }, }, options: [ @@ -35,21 +35,21 @@ export const recipientOperations = [ const additionalRecipientFields = [ { - displayName: 'Recipient notes', + displayName: 'Recipient Notes', name: 'recipientNotes', type: 'string', default: '', description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific', }, { - displayName: 'Skip recipient SMS notifications', + displayName: 'Skip Recipient SMS Notifications', name: 'recipientSkipSMSNotifications', type: 'boolean', default: false, description: 'Whether this recipient has requested to skip SMS notifications', }, { - displayName: 'Skip recipient phone number validation', + displayName: 'Skip Recipient Phone Number Validation', name: 'recipientSkipPhoneNumberValidation', type: 'boolean', default: false, @@ -58,38 +58,46 @@ const additionalRecipientFields = [ ]; const recipientName = { - displayName: 'Recipient name', + displayName: 'Recipient Name', name: 'recipientName', type: 'string', description: 'The recipient\'s complete name', + default: '', } as INodeProperties; const recipientPhone = { - displayName: 'Recipient phone', + displayName: 'Recipient Phone', name: 'recipientPhone', type: 'string', description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting', + default: '', } as INodeProperties; -const additionalRecipientFieldsUpdate = [ - recipientName, - recipientPhone, +const updateFields = [ { - displayName: 'Recipient notes', + ...recipientName, + required: false, + }, + { + ...recipientPhone, + required: false, + }, + { + displayName: 'Recipient Notes', name: 'notes', type: 'string', default: '', description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific', }, { - displayName: 'Skip recipient SMS notifications', + displayName: 'Skip Recipient SMS Notifications', name: 'skipSMSNotifications', type: 'boolean', default: false, description: 'Whether this recipient has requested to skip SMS notifications', }, { - displayName: 'Skip recipient phone number validation', + displayName: 'Skip Recipient Phone Number Validation', name: 'skipPhoneNumberValidation', type: 'boolean', default: false, @@ -97,14 +105,46 @@ const additionalRecipientFieldsUpdate = [ }, ]; +export const recipientExternalField = { + displayName: 'Recipient', + name: 'recipient', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Recipient Properties', + name: 'recipientProperties', + default: {}, + values: [ + { + ...recipientName, + required: true, + }, + { + ...recipientPhone, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: additionalRecipientFields, + }, + ], + }, + ], +} as INodeProperties; + export const recipientFields = [ { - displayName: 'Get by', + displayName: 'Get By', name: 'getBy', type: 'options', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'get' ], }, }, @@ -127,12 +167,12 @@ export const recipientFields = [ default: 'id', }, { - displayName: 'ID', + displayName: 'Recipient ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'get' ], getBy: [ 'id' ], }, @@ -142,12 +182,12 @@ export const recipientFields = [ description: 'The ID of the recipient object for lookup', }, { - displayName: 'ID', + displayName: 'Recipient ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'update' ], }, }, @@ -161,7 +201,7 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'get' ], getBy: [ 'name' ], }, @@ -176,7 +216,7 @@ export const recipientFields = [ type: 'string', displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'get' ], getBy: [ 'phone' ], }, @@ -185,41 +225,10 @@ export const recipientFields = [ required: true, description: 'The phone of the recipient for lookup', }, - { - displayName: 'Recipient', - name: 'recipient', - type: 'boolean', - displayOptions: { - show: { - resource: [ 'tasks' ], - operation: [ - 'create', - 'createBatch', - ], - }, - }, - description: 'Whether the task has a recipient associated', - required: true, - default: true, - }, - { - displayOptions: { - show: { - resource: [ 'tasks' ], - operation: [ - 'create', - 'createBatch', - ], - recipient: [ true ], - }, - }, - ...recipientName, - required: true, - }, { displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'create' ], }, }, @@ -229,21 +238,7 @@ export const recipientFields = [ { displayOptions: { show: { - resource: [ 'tasks' ], - operation: [ - 'create', - 'createBatch', - ], - recipient: [ true ], - }, - }, - ...recipientPhone, - required: true, - }, - { - displayOptions: { - show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: ['create' ], }, }, @@ -251,49 +246,31 @@ export const recipientFields = [ required: true, }, { - displayName: 'Additional recipient fields', - name: 'additionalRecipientFields', + displayName: 'Additional Fields', + name: 'additionalFields', type: 'collection', - placeholder: 'Add recipient fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'create' ], }, }, options: additionalRecipientFields, }, { - displayName: 'Additional recipient fields', - name: 'additionalRecipientFields', - type: 'collection', - placeholder: 'Add recipient fields', - default: {}, - displayOptions: { - show: { - resource: [ 'tasks' ], - operation: [ - 'create', - 'createBatch', - ], - recipient: [ true ], - }, - }, - options: additionalRecipientFields, - }, - { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Update fields', default: {}, displayOptions: { show: { - resource: [ 'recipients' ], + resource: [ 'recipient' ], operation: [ 'update' ], }, }, - options: additionalRecipientFieldsUpdate, + options: updateFields, }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 66452a5465147..9f6ed502998e7 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -1,6 +1,8 @@ import { INodeProperties } from 'n8n-workflow'; +import { destinationExternalField } from './DestinationDescription'; +import { recipientExternalField } from './RecipientDescription'; export const taskOperations = [ { @@ -9,7 +11,7 @@ export const taskOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], }, }, options: [ @@ -34,14 +36,14 @@ export const taskOperations = [ description: 'Force-complete a started Onfleet task', }, { - name: 'Remove', + name: 'Delete', value: 'delete', - description: 'Remove an Onfleet task', + description: 'Delete an Onfleet task', }, { - name: 'List', + name: 'Get All', value: 'getAll', - description: 'List Onfleet tasks', + description: 'Get all Onfleet tasks', }, { name: 'Get', @@ -76,7 +78,7 @@ const executorIdField = { } as INodeProperties; const completeAfterField = { - displayName: 'CompleteAfter', + displayName: 'Complete After', name: 'completeAfter', type: 'dateTime', default: null, @@ -84,7 +86,7 @@ const completeAfterField = { } as INodeProperties; const completeBeforeField = { - displayName: 'CompleteBefore', + displayName: 'Complete Before', name: 'completeBefore', type: 'dateTime', default: null, @@ -92,7 +94,7 @@ const completeBeforeField = { } as INodeProperties; const pickupTaskField = { - displayName: 'PickupTask', + displayName: 'Pick Up Task', name: 'pickupTask', type: 'boolean', default: false, @@ -125,12 +127,12 @@ const serviceTimeField = { export const taskFields = [ { - displayName: 'ID', + displayName: 'Task ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], }, hide: { operation: [ @@ -144,13 +146,39 @@ export const taskFields = [ required: true, description: 'The ID of the task object for lookup', }, + { + ...destinationExternalField, + displayOptions: { + show: { + resource: [ 'task' ], + operation: [ + 'create', + 'createBatch', + ], + }, + }, + default: {}, + }, + { + ...recipientExternalField, + displayOptions: { + show: { + resource: [ 'task' ], + operation: [ + 'create', + 'createBatch', + ], + }, + }, + default: {}, + }, { displayName: 'Short ID', name: 'shortId', type: 'boolean', displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'get' ], }, }, @@ -163,7 +191,7 @@ export const taskFields = [ type: 'dateTime', displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'getAll' ], }, }, @@ -177,7 +205,7 @@ export const taskFields = [ type: 'boolean', displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'complete' ], }, }, @@ -186,14 +214,14 @@ export const taskFields = [ default: true, }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Filter Fields', + name: 'filterFields', type: 'collection', - placeholder: 'Add Fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'getAll' ], }, }, @@ -211,21 +239,21 @@ export const taskFields = [ type: 'multiOptions', options: [ { - name: 'Unassigned', - value: 0, + name: 'Active', + value: 2, }, { name: 'Assigned', value: 1, }, - { - name: 'Active', - value: 2, - }, { name: 'Completed', value: 3, }, + { + name: 'Unassigned', + value: 0, + }, ], default: null, description: 'The state of the tasks', @@ -247,7 +275,7 @@ export const taskFields = [ default: {}, displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'clone' ], }, }, @@ -273,20 +301,49 @@ export const taskFields = [ { displayName: 'Overrides', name: 'overrides', - type: 'json', - default: null, + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Override Properties', + name: 'overrideProperties', + default: {}, + values: [ + { + ...notesField, + required: false, + }, + { + ...pickupTaskField, + required: false, + }, + { + ...serviceTimeField, + required: false, + }, + { + ...completeAfterField, + required: false, + }, + { + ...completeBeforeField, + required: false, + }, + ], + }, + ], }, ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add Fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'update' ], }, }, @@ -302,14 +359,14 @@ export const taskFields = [ ], }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add Fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'complete' ], }, }, @@ -324,14 +381,14 @@ export const taskFields = [ ], }, { - displayName: 'Additional task fields', + displayName: 'Additional Task Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add Fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'tasks' ], + resource: [ 'task' ], operation: [ 'create', 'createBatch', diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index daa3fd2c77195..8f50513faaae1 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -9,24 +9,24 @@ export const teamOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], }, }, options: [ + { + name: 'Auto-Dispatch', + value: 'autoDispatch', + description: 'Dynamically dispatching tasks on the fly', + }, { name: 'Create', value: 'create', description: 'Create a new Onfleet team', }, { - name: 'Update', - value: 'update', - description: 'Update an Onfleet team', - }, - { - name: 'Remove', + name: 'Delete', value: 'delete', - description: 'Remove an Onfleet team', + description: 'Delete an Onfleet team', }, { name: 'Get', @@ -34,20 +34,20 @@ export const teamOperations = [ description: 'Get a specific Onfleet team', }, { - name: 'List', + name: 'Get all', value: 'getAll', description: 'List all Onfleet teams', }, - { - name: 'Auto-Dispatch', - value: 'autoDispatch', - description: 'Dynamically dispatching tasks on the fly', - }, { name: 'Get time estimates', value: 'getTimeEstimates', description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet', }, + { + name: 'Update', + value: 'update', + description: 'Update an Onfleet team', + }, ], default: 'getAll', }, @@ -62,31 +62,40 @@ const nameField = { } as INodeProperties; const workersField = { - displayName: 'Workers (JSON)', + displayName: 'Workers', name: 'workers', - type: 'json', - default: '[]', - description: 'An array of workers IDs', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getWorkers', + }, + default: [], + description: 'A list of workers', } as INodeProperties; const managersField = { - displayName: 'Administrators (JSON)', + displayName: 'Administrators', name: 'managers', - type: 'json', - default: '[]', - description: 'An array of managing administrator IDs', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getAdmins', + }, + default: [], + description: 'A list of managing administrator', } as INodeProperties; const hubField = { displayName: 'Hub', name: 'hub', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getHubs', + }, default: '', - description: 'The ID of the team\'s hub', + description: 'The team\'s hub', } as INodeProperties; const enableSelfAssignmentField = { - displayName: 'Self assignment', + displayName: 'Self Assignment', name: 'enableSelfAssignment', type: 'boolean', default: false, @@ -94,7 +103,7 @@ const enableSelfAssignmentField = { } as INodeProperties; const maxTasksPerRouteField = { - displayName: 'Max number of tasks per route', + displayName: 'Max Number Of Tasks Per Route', name: 'maxTasksPerRoute', type: 'number', default: 100, @@ -105,24 +114,8 @@ const maxTasksPerRouteField = { description: 'Total number of tasks allowed on a route', }as INodeProperties; -const taskTimeWindowField = { - displayName: 'Task time window (JSON)', - name: 'taskTimeWindow', - type: 'json', - default: '{}', - description: 'This is the time window of tasks to include in the optimization. Param must be an array of length 2 in unix time in seconds precision, [start, end]', -} as INodeProperties; - -const scheduleTimeWindowField = { - displayName: 'Schedule time window (JSON)', - name: 'scheduleTimeWindow', - type: 'json', - default: '{}', - description: 'This is the Driver\'s scheduled time window. Param must be an array of length 2 in unix time in seconds precision, [start, end]', -} as INodeProperties; - const serviceTimeField = { - displayName: 'Service time', + displayName: 'Service Time', name: 'serviceTIme', type: 'number', default: 2, @@ -133,7 +126,7 @@ const serviceTimeField = { } as INodeProperties; const routeEndField = { - displayName: 'Route end', + displayName: 'Route End', name: 'routeEnd', type: 'string', default: '', @@ -141,7 +134,7 @@ const routeEndField = { } as INodeProperties; const maxAllowedDelayField = { - displayName: 'Max allowed delay', + displayName: 'Max Allowed Delay', name: 'maxAllowedDelay', type: 'number', default: 10, @@ -151,24 +144,8 @@ const maxAllowedDelayField = { }, } as INodeProperties; -const dropoffField = { - displayName: 'Dropoff', - name: 'dropoff', - type: 'boolean', - default: false, - description: 'Dropoff', -} as INodeProperties; - -const pickupField = { - displayName: 'Pickup', - name: 'pickup', - type: 'boolean', - default: false, - description: 'Pickup', -} as INodeProperties; - const longitudeDropoffField = { - displayName: 'Dropoff longitude', + displayName: 'Dropoff Longitude', name: 'dropoffLongitude', type: 'number', typeOptions: { @@ -179,7 +156,7 @@ const longitudeDropoffField = { } as INodeProperties; const latitudeDropoffField = { - displayName: 'Dropoff latitude', + displayName: 'Dropoff Latitude', name: 'dropoffLatitude', type: 'number', typeOptions: { @@ -190,7 +167,7 @@ const latitudeDropoffField = { } as INodeProperties; const longitudePickupField = { - displayName: 'Pickup longitude', + displayName: 'Pick Up Longitude', name: 'pickupLongitude', type: 'number', typeOptions: { @@ -201,7 +178,7 @@ const longitudePickupField = { } as INodeProperties; const latitudePickupField = { - displayName: 'Pickup latitude', + displayName: 'Pick Up Latitude', name: 'pickupLatitude', type: 'number', typeOptions: { @@ -212,15 +189,15 @@ const latitudePickupField = { } as INodeProperties; const pickupTimeField = { - displayName: 'Pickup time', + displayName: 'Pick Up Time', name: 'pickupTime', type: 'dateTime', - default: Date.now(), + default: '', description: 'If the request includes pickupLocation pickupTime must be present if the time is fewer than 3 hours in the future', } as INodeProperties; const restrictedVehicleTypesField = { - displayName: 'Restricted vehicle types', + displayName: 'Restricted Vehicle Types', name: 'restrictedVehicleTypes', type: 'options', options: [ @@ -246,7 +223,7 @@ const restrictedVehicleTypesField = { } as INodeProperties; const serviceTimeEstimateField = { - displayName: 'Service time', + displayName: 'Service Time', name: 'serviceTIme', type: 'number', default: 120, @@ -258,12 +235,12 @@ const serviceTimeEstimateField = { export const teamFields = [ { - displayName: 'ID', + displayName: 'Team ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'get', 'update', @@ -281,7 +258,7 @@ export const teamFields = [ ...nameField, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'create' ], }, }, @@ -291,7 +268,7 @@ export const teamFields = [ ...workersField, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'create' ], }, }, @@ -301,21 +278,21 @@ export const teamFields = [ ...managersField, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'create' ], }, }, required: true, }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'create' ], }, }, @@ -325,14 +302,14 @@ export const teamFields = [ ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'update' ], }, }, @@ -345,109 +322,170 @@ export const teamFields = [ ], }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'autoDispatch' ], }, }, options: [ + maxAllowedDelayField, maxTasksPerRouteField, - taskTimeWindowField, - scheduleTimeWindowField, - serviceTimeField, routeEndField, - maxAllowedDelayField, - ], - }, - { - ...dropoffField, - displayOptions: { - show: { - resource: [ 'teams' ], - operation: [ 'getTimeEstimates' ], - }, - }, - }, - { - ...longitudeDropoffField, - displayOptions: { - show: { - resource: [ 'teams' ], - operation: [ 'getTimeEstimates' ], - dropoff: [ true ], + { + displayName: 'Schedule Time Window', + name: 'scheduleTimeWindow', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Schedule Time Window Properties', + name: 'scheduleTimeWindowProperties', + type: 'fixedCollection', + default: {}, + values: [ + { + displayName: 'Start Time', + name: 'startTime', + type: 'dateTime', + default: '', + }, + { + displayName: 'End Time', + name: 'endTime', + type: 'dateTime', + default: '', + }, + ], + }, + ], }, - }, - }, - { - ...latitudeDropoffField, - displayOptions: { - show: { - resource: [ 'teams' ], - operation: [ 'getTimeEstimates' ], - dropoff: [ true ], + serviceTimeField, + { + displayName: 'Task Time Window', + name: 'taskTimeWindow', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Task Time Window Properties', + name: 'taskTimeWindowProperties', + type: 'fixedCollection', + default: {}, + values: [ + { + displayName: 'Start Time', + name: 'startTime', + type: 'dateTime', + default: '', + }, + { + displayName: 'End Time', + name: 'endTime', + type: 'dateTime', + default: '', + }, + ], + }, + ], }, - }, + ], }, { - ...pickupField, + displayName: 'Dropoff', + name: 'dropoff', + type: 'fixedCollection', displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'getTimeEstimates' ], }, }, - }, - { - ...longitudePickupField, - displayOptions: { - show: { - resource: [ 'teams' ], - operation: [ 'getTimeEstimates' ], - pickup: [ true ], + default: {}, + options: [ + { + displayName: 'Dropoff Properties', + name: 'dropoffProperties', + values: [ + { + ...longitudeDropoffField, + required: true, + }, + { + ...latitudeDropoffField, + required: true, + }, + ], }, - }, + ], }, { - ...latitudePickupField, + displayName: 'Pick Up', + name: 'pickUp', + type: 'fixedCollection', displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'getTimeEstimates' ], - pickup: [ true ], }, }, - }, - { - ...pickupTimeField, - displayOptions: { - show: { - resource: [ 'teams' ], - operation: [ 'getTimeEstimates' ], - pickup: [ true ], + default: {}, + options: [ + { + displayName: 'Pick Up Properties', + name: 'pickUpProperties', + values: [ + { + ...longitudePickupField, + required: true, + }, + { + ...latitudePickupField, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + ...pickupTimeField, + required: false, + }, + ], + }, + ], }, - }, + ], }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add fields', default: {}, displayOptions: { show: { - resource: [ 'teams' ], + resource: [ 'team' ], operation: [ 'getTimeEstimates' ], }, }, options: [ - restrictedVehicleTypesField, - serviceTimeEstimateField, + { + ...restrictedVehicleTypesField, + required: false, + }, + { + ...serviceTimeEstimateField, + required: false, + }, ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts index e70b759cb51f8..fb3e2f47dee95 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -10,7 +10,7 @@ export const webhookOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], }, }, options: [ @@ -20,14 +20,14 @@ export const webhookOperations = [ description: 'Create a new Onfleet webhook', }, { - name: 'Remove', + name: 'Delete', value: 'delete', - description: 'Remove an Onfleet webhook', + description: 'Delete an Onfleet webhook', }, { - name: 'List', + name: 'Get All', value: 'getAll', - description: 'List all Onfleet webhooks', + description: 'Get all Onfleet webhooks', }, ], default: 'getAll', @@ -71,12 +71,12 @@ const thresholdField = { export const webhookFields = [ { - displayName: 'ID', + displayName: 'Webhook ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], operation: [ 'delete' ], }, }, @@ -88,7 +88,7 @@ export const webhookFields = [ ...urlField, displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], operation: [ 'create' ], }, }, @@ -98,7 +98,7 @@ export const webhookFields = [ ...nameField, displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], operation: [ 'create' ], }, }, @@ -108,21 +108,21 @@ export const webhookFields = [ ...triggerField, displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], operation: [ 'create' ], }, }, required: true, }, { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'webhooks' ], + resource: [ 'webhook' ], operation: [ 'create' ], }, }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index 26dadafde9d89..63ea4713c5927 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -9,7 +9,7 @@ export const workerOperations = [ type: 'options', displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], }, }, options: [ @@ -19,32 +19,27 @@ export const workerOperations = [ description: 'Create a new Onfleet worker', }, { - name: 'Remove', + name: 'Delete', value: 'delete', - description: 'Remove an Onfleet worker', - }, - { - name: 'List', - value: 'getAll', - description: 'List all Onfleet workers', - }, - { - name: 'List workers by location', - value: 'getAllByLocation', - description: 'List all Onfleet workers who are currently within a centain target area', + description: 'Delete an Onfleet worker', }, { name: 'Get', value: 'get', description: 'Get a specific Onfleet worker', }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all Onfleet workers', + }, { name: 'Get Schedule', value: 'getSchedule', description: 'Get a specific Onfleet worker schedule', }, { - name: 'Set worker\'s schedule', + name: 'Set Worker\'s Schedule', value: 'setSchedule', description: 'Set the worker\'s schedule', }, @@ -58,6 +53,14 @@ export const workerOperations = [ }, ] as INodeProperties[]; +const byLocationField = { + displayName: 'Search by location', + name: 'byLocation', + type: 'boolean', + default: false, + description: 'Search workers who are currently within a certain target area', +} as INodeProperties; + const nameField = { displayName: 'Name', name: 'name', @@ -83,27 +86,22 @@ const capacityField = { } as INodeProperties; const displayNameField = { - displayName: 'Display name', + displayName: 'Display Name', name: 'displayName', type: 'string', default: '', description: 'This value is used in place of the worker\'s actual name within sms notifications, delivery tracking pages, and across organization boundaries', } as INodeProperties; -// Vehicles fields -const vehicleField = { - displayName: 'Vehicle', - name: 'vehicle', - type: 'boolean', - default: false, - description: 'Whether the worker has vehicle or not', -} as INodeProperties; - const vehicleTypeField = { displayName: 'Type', name: 'type', type: 'options', options: [ + { + name: 'Bicycle', + value: 'BICYCLE', + }, { name: 'Car', value: 'CAR', @@ -112,16 +110,12 @@ const vehicleTypeField = { name: 'Motorcycle', value: 'MOTORCYCLE', }, - { - name: 'Bicycle', - value: 'BICYCLE', - }, { name: 'Truck', value: 'TRUCK', }, ], - default: 'CAR', + default: '', description: 'Whether the worker has vehicle or not', } as INodeProperties; @@ -134,7 +128,7 @@ const vehicleDescriptionField = { } as INodeProperties; const vehicleLicensePlateField = { - displayName: 'License plate', + displayName: 'License Plate', name: 'licensePlate', type: 'string', default: '', @@ -150,19 +144,25 @@ const vehicleColorField = { } as INodeProperties; const teamsField = { - displayName: 'Teams (JSON)', + displayName: 'Teams', name: 'teams', - type: 'json', - default: '[]', - description: 'One or more team IDs of which the worker is a member', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getTeams', + }, + default: [], + description: 'One or more teams of which the worker is a member', } as INodeProperties; const teamsFilterField = { displayName: 'Teams', name: 'teams', - type: 'string', - default: '', - description: 'A comma-separated list of the team IDs that workers must be part of', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getTeams', + }, + default: [], + description: 'A list of the teams that workers must be part of', } as INodeProperties; const statesFilterField = { @@ -171,16 +171,16 @@ const statesFilterField = { type: 'multiOptions', options: [ { - name: 'Off-duty', - value: 0, + name: 'Active (on-duty, active task)', + value: 2, }, { name: 'Idle (on-duty, no active task)', value: 1, }, { - name: 'Active (on-duty, active task)', - value: 2, + name: 'Off-duty', + value: 0, }, ], default: '', @@ -191,16 +191,102 @@ const phonesFilterField = { displayName: 'Phones', name: 'phones', type: 'string', - default: '', - description: 'A comma-separated list of workers\' phone numbers', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Phone', + }, + default: [], + description: 'A list of workers\' phone numbers', } as INodeProperties; const filterField = { - displayName: 'List of fields to return', + displayName: 'List Of Fields To Return', name: 'filter', - type: 'string', + type: 'multiOptions', + options: [ + { + name: 'Account Status', + value: 'accountStatus', + }, + { + name: 'Active Task', + value: 'activeTask', + }, + { + name: 'Capacity', + value: 'capacity', + }, + { + name: 'Delay Time', + value: 'delayTime', + }, + { + name: 'Display Name', + value: 'displayName', + }, + { + name: 'Image Url', + value: 'imageUrl', + }, + { + name: 'Location', + value: 'location', + }, + { + name: 'Metadata', + value: 'metadata', + }, + { + name: 'Name', + value: 'name', + }, + { + name: 'On Duty', + value: 'onDuty', + }, + { + name: 'organization', + value: 'organization', + }, + { + name: 'Phone', + value: 'phone', + }, + { + name: 'Tasks', + value: 'tasks', + }, + { + name: 'Teams', + value: 'teams', + }, + { + name: 'Time Created', + value: 'timeCreated', + }, + { + name: 'Time Last Modified', + value: 'timeLastModified', + }, + { + name: 'Time Last Seen', + value: 'timeLastSeen', + }, + { + name: 'User Data', + value: 'userData', + }, + { + name: 'Vehicle', + value: 'vehicle', + }, + { + name: 'Worker ID', + value: 'id', + }, + ], default: '', - description: 'A comma-separated list of fields to return, if all are not desired. For example, name, location', + description: 'A list of fields to return, if all are not desired', } as INodeProperties; const longitudeFilterField = { @@ -241,14 +327,17 @@ const scheduleDateField = { displayName: 'Date', name: 'date', type: 'dateTime', - default: Date.now(), + default: '', description: 'Schedule\'s date', } as INodeProperties; const scheduleTimezoneField = { displayName: 'Timezone', name: 'timezone', - type: 'string', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getTimezones', + }, default: '', description: 'A valid timezone', } as INodeProperties; @@ -257,7 +346,7 @@ const scheduleStartField = { displayName: 'Start', name: 'start', type: 'dateTime', - default: Date.now(), + default: '', description: 'Start time', } as INodeProperties; @@ -265,18 +354,28 @@ const scheduleEndField = { displayName: 'End', name: 'end', type: 'dateTime', - default: Date.now(), + default: '', description: 'End time', } as INodeProperties; export const workerFields = [ { - displayName: 'ID', + ...byLocationField, + required: true, + displayOptions: { + show: { + resource: [ 'worker' ], + operation: [ 'getAll' ], + }, + }, + }, + { + displayName: 'Worker ID', name: 'id', type: 'string', displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'get', 'getSchedule', @@ -290,25 +389,11 @@ export const workerFields = [ required: true, description: 'The ID of the worker object for lookup', }, - { - displayName: 'Analytics', - name: 'analytics', - type: 'boolean', - displayOptions: { - show: { - resource: [ 'workers' ], - operation: [ 'get' ], - }, - }, - default: true, - required: true, - description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics', - }, { ...nameField, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'create' ], }, }, @@ -318,44 +403,107 @@ export const workerFields = [ ...phoneField, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'create' ], }, }, required: true, }, { - ...vehicleField, + displayName: 'Vehicle', + name: 'vehicle', + type: 'fixedCollection', displayOptions: { show: { - resource: [ 'workers' ], - operation: [ - 'create', - 'update', - ], + resource: [ 'worker' ], + operation: [ 'update' ], }, }, - required: true, + default: {}, + options: [ + { + displayName: 'Vehicle Properties', + name: 'vehicleProperties', + values: [ + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + ...vehicleTypeField, + required: true, + }, + { + ...vehicleDescriptionField, + required: false, + }, + { + ...vehicleLicensePlateField, + required: false, + }, + { + ...vehicleColorField, + required: false, + }, + ], + }, + ], + }, + ], }, { - ...vehicleTypeField, + displayName: 'Vehicle', + name: 'vehicle', + type: 'fixedCollection', displayOptions: { show: { - resource: [ 'workers' ], - operation: [ - 'create', - 'update', - ], - vehicle: [ true ], + resource: [ 'worker' ], + operation: [ 'create' ], }, }, - required: true, + default: {}, + options: [ + { + displayName: 'Vehicle Properties', + name: 'vehicleProperties', + values: [ + { + ...vehicleTypeField, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + ...vehicleDescriptionField, + required: false, + }, + { + ...vehicleLicensePlateField, + required: false, + }, + { + ...vehicleColorField, + required: false, + }, + ], + }, + ], + }, + ], }, { ...teamsField, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'create' ], }, }, @@ -365,8 +513,9 @@ export const workerFields = [ ...longitudeFilterField, displayOptions: { show: { - resource: [ 'workers' ], - operation: [ 'getAllByLocation' ], + resource: [ 'worker' ], + operation: [ 'getAll' ], + byLocation: [ true ], }, }, required: true, @@ -375,57 +524,37 @@ export const workerFields = [ ...latitudeFilterField, displayOptions: { show: { - resource: [ 'workers' ], - operation: [ 'getAllByLocation' ], + resource: [ 'worker' ], + operation: [ 'getAll' ], + byLocation: [ true ], }, }, required: true, }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Filter Fields', + name: 'filterFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'workers' ], - operation: [ 'getAllByLocation' ], + resource: [ 'worker' ], + operation: [ 'getAll' ], + byLocation: [ true ], }, }, options: [ radiusFilterField ], }, { - displayName: 'Additional vehicle fields', - name: 'additionalVehicleFields', - type: 'collection', - placeholder: 'Add vehicle fields', - default: {}, - displayOptions: { - show: { - resource: [ 'workers' ], - operation: [ - 'create', - 'update', - ], - vehicle: [ true ], - }, - }, - options: [ - vehicleDescriptionField, - vehicleLicensePlateField, - vehicleColorField, - ], - }, - { - displayName: 'Additional fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'create' ], }, }, @@ -435,14 +564,14 @@ export const workerFields = [ ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Update Fields', + name: 'updateFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'update' ], }, }, @@ -454,15 +583,16 @@ export const workerFields = [ ], }, { - displayName: 'Additional fields', - name: 'additionalFields', + displayName: 'Filter Fields', + name: 'filterFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'getAll' ], + byLocation: [ false ], }, }, options: [ @@ -473,57 +603,90 @@ export const workerFields = [ ], }, { - displayName: 'Additional fields', + displayName: 'Filter Fields', name: 'additionalFields', type: 'collection', - placeholder: 'Add fields', + placeholder: 'Add Field', default: {}, displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'get' ], }, }, - options: [ filterField ], - }, - { - ...scheduleDateField, - displayOptions: { - show: { - resource: [ 'workers' ], - operation: [ 'setSchedule' ], + options: [ + { + ...filterField, + required: false, }, - }, - required: true, - }, - { - ...scheduleTimezoneField, - displayOptions: { - show: { - resource: [ 'workers' ], - operation: [ 'setSchedule' ], + { + displayName: 'Analytics', + name: 'analytics', + type: 'boolean', + default: true, + required: false, + description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics', }, - }, - required: true, + ], }, { - ...scheduleStartField, + displayName: 'Schedule', + name: 'schedule', + type: 'fixedCollection', displayOptions: { show: { - resource: [ 'workers' ], + resource: [ 'worker' ], operation: [ 'setSchedule' ], }, }, - required: true, - }, - { - ...scheduleEndField, - displayOptions: { - show: { - resource: [ 'workers' ], - operation: [ 'setSchedule' ], - }, + default: {}, + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Schedule', }, - required: true, + options: [ + { + displayName: 'Schedule Properties', + name: 'scheduleProperties', + default: {}, + values: [ + { + ...scheduleDateField, + required: true, + }, + { + ...scheduleTimezoneField, + required: true, + }, + { + displayName: 'Shifts', + name: 'shifts', + type: 'fixedCollection', + default: {}, + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Shift', + }, + options: [ + { + displayName: 'Shifts Properties', + name: 'shiftsProperties', + default: {}, + values: [ + { + ...scheduleStartField, + required: true, + }, + { + ...scheduleEndField, + required: true, + }, + ], + }, + ], + }, + ], + }, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Onfleet/interfaces.ts b/packages/nodes-base/nodes/Onfleet/interfaces.ts index 2fba8f80d4082..2d69ebfe099c2 100644 --- a/packages/nodes-base/nodes/Onfleet/interfaces.ts +++ b/packages/nodes-base/nodes/Onfleet/interfaces.ts @@ -64,11 +64,21 @@ export interface OnfleetListTaskFilters { dependencies?: string; } +export interface OnfleetCloneOverrideTaskOptions { + completeAfter?: number; + completeBefore?: number; + destination?: OnfleetDestination; + notes?: string; + pickupTask?: boolean; + recipients?: OnfleetRecipient[]; + serviceTime?: number; +} + export interface OnfleetCloneTaskOptions { includeMetadata?: boolean; includeBarcodes?: boolean; includeDependencies?: boolean; - overrides?: object; + overrides?: OnfleetCloneOverrideTaskOptions; } export interface OnfleetCloneTask { From 19c67e12faab4c29cdefbfd4a018af474c701bdf Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Thu, 27 Jan 2022 10:07:38 -0500 Subject: [PATCH 08/12] fix: fixed recipient and destination cretion --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index a66c271a1fa10..b4ef0e9a272a1 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -144,11 +144,11 @@ export class Onfleet implements INodeType { static formatAddress ( unparsed: boolean, - address: string, - addressNumber: string, - addressStreet: string, - addressCity: string, - addressCountry: string, + address: string | undefined, + addressNumber: string | undefined, + addressStreet: string | undefined, + addressCity: string | undefined, + addressCountry: string | undefined, additionalFields: IDataObject, ): OnfleetDestination { let destination: OnfleetDestination; @@ -218,13 +218,17 @@ export class Onfleet implements INodeType { additionalFields as IDataObject, ) as OnfleetDestination; } else { - const unparsed = this.getNodeParameter('unparsed', item) as boolean; - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; - const address = this.getNodeParameter('address', item) as string; - const addressNumber = this.getNodeParameter('addressNumber', item) as string; - const addressStreet = this.getNodeParameter('addressStreet', item) as string; - const addressCity = this.getNodeParameter('addressCity', item) as string; - const addressCountry = this.getNodeParameter('addressCountry', item) as string; + let unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields; + unparsed = this.getNodeParameter('unparsed', item) as boolean; + if (unparsed) { + address = this.getNodeParameter('address', item) as string; + } else { + addressNumber = this.getNodeParameter('addressNumber', item) as string; + addressStreet = this.getNodeParameter('addressStreet', item) as string; + addressCity = this.getNodeParameter('addressCity', item) as string; + addressCountry = this.getNodeParameter('addressCountry', item) as string; + } + additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; return Onfleet.formatAddress( unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields, @@ -484,8 +488,8 @@ export class Onfleet implements INodeType { ); } } else { - const name = this.getNodeParameter('name', item) as string; - const phone = this.getNodeParameter('phone', item) as string; + const name = this.getNodeParameter('recipientName', item) as string; + const phone = this.getNodeParameter('recipientPhone', item) as string; const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; return Onfleet.formatRecipient(name, phone, additionalFields) as OnfleetRecipient; } From a95f4a67813cb065d6cbb0d8f9a0e41d107dd2b1 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Thu, 27 Jan 2022 10:12:49 -0500 Subject: [PATCH 09/12] docs: added docstrings for format some functions added docstrings for new functions addded for formatting the destination and recipient objects --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index b4ef0e9a272a1..f5f4f777beae9 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -142,6 +142,17 @@ export class Onfleet implements INodeType { loadOptions: resourceLoaders, }; + /** + * Returns a valid formated destination object + * @param unparsed Whether the address is parsed or not + * @param address Destination address + * @param addressNumber Destination number + * @param addressStreet Destination street + * @param addressCity Destination city + * @param addressCountry Destination country + * @param additionalFields Destination additional fields + * @returns + */ static formatAddress ( unparsed: boolean, address: string | undefined, @@ -428,6 +439,13 @@ export class Onfleet implements INodeType { return null; } + /** + * Returns a valid formated recipient object + * @param name Recipient name + * @param phone Recipient phone + * @param additionalFields Recipient additional fields + * @returns + */ static formatRecipient( name: string, phone: string, additionalFields: IDataObject, ): OnfleetRecipient { From addba39ddd40437b04c15b9a92c46ae2064fc00f Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Thu, 27 Jan 2022 11:25:35 -0500 Subject: [PATCH 10/12] style: formatting the code according to n8n nodelinter --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 45 ++++++++++++++++++- .../nodes/Onfleet/OnfleetTrigger.node.ts | 38 ++++++++++++++++ .../descriptions/AdministratorDescription.ts | 12 ++--- .../descriptions/ContainerDescription.ts | 14 +++--- .../descriptions/DestinationDescription.ts | 10 ++--- .../Onfleet/descriptions/HubDescription.ts | 12 ++--- .../descriptions/OnfleetWebhookDescription.ts | 2 +- .../descriptions/OrganizationDescription.ts | 8 ++-- .../descriptions/RecipientDescription.ts | 14 +++--- .../Onfleet/descriptions/TaskDescription.ts | 37 +++++++-------- .../Onfleet/descriptions/TeamDescription.ts | 24 +++++----- .../descriptions/WebhookDescription.ts | 12 ++--- .../Onfleet/descriptions/WorkerDescription.ts | 28 ++++++------ 13 files changed, 168 insertions(+), 88 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index f5f4f777beae9..e945ab9410868 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -1,9 +1,13 @@ import { ICredentialDataDecryptedObject, + ICredentialsDecrypted, + ICredentialTestFunctions, IDataObject, INodeExecutionData, INodeType, INodeTypeDescription, + NodeCredentialTestResult, + NodeOperationError, } from 'n8n-workflow'; import * as moment from 'moment-timezone'; @@ -41,6 +45,7 @@ import { workerFields, workerOperations } from './descriptions/WorkerDescription import { webhookFields, webhookOperations } from './descriptions/WebhookDescription'; import { containerFields, containerOperations } from './descriptions/ContainerDescription'; import { teamFields, teamOperations } from './descriptions/TeamDescription'; +import { OptionsWithUri } from 'request'; export class Onfleet implements INodeType { description: INodeTypeDescription = { @@ -52,8 +57,10 @@ export class Onfleet implements INodeType { subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Onfleet API', defaults: { - name: 'Onfleet', color: '#AA81F3', + description: 'Use the Onfleet API', + name: 'Onfleet', + testedBy: 'onfeletApiTest', }, inputs: [ 'main' ], outputs: [ 'main' ], @@ -139,6 +146,36 @@ export class Onfleet implements INodeType { }; methods = { + credentialTest: { + async onfeletApiTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise { + const credentials = credential.data as IDataObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + const options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Basic ${encodedApiKey}`, + 'User-Agent': 'n8n-onfleet', + }, + method: 'GET', + uri: 'https://onfleet.com/api/v2/auth/test', + json: true, + }; + + try { + await this.helpers.request(options); + return { + status: 'OK', + message: 'Authentication successful', + }; + } catch (error) { + return { + status: 'Error', + message: `Settings are not valid: ${error}`, + }; + } + }, + }, loadOptions: resourceLoaders, }; @@ -676,7 +713,11 @@ export class Onfleet implements INodeType { const hasPickUp = pickup && Object.keys(pickup).length > 0; const hasDropoff = dropoff && Object.keys(dropoff).length > 0; - if (!hasPickUp && !hasDropoff) throw new Error('At least 1 of dropoffLocation or pickupLocation must be selected'); + if (!hasPickUp && !hasDropoff) { + throw new NodeOperationError( + this.getNode(), 'At least 1 of dropoffLocation or pickupLocation must be selected', + ); + } const workerTimeEstimates = {} as OnfleetWorkerEstimates; if (hasPickUp) { diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 58ef0e90517a1..59f70924c7564 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -1,10 +1,13 @@ import { ICredentialDataDecryptedObject, + ICredentialsDecrypted, + ICredentialTestFunctions, IDataObject, INodeType, INodeTypeDescription, IWebhookResponseData, NodeApiError, + NodeCredentialTestResult, NodeOperationError, } from 'n8n-workflow'; import { @@ -15,6 +18,7 @@ import { import { eventDisplay, eventNameField } from './descriptions/OnfleetWebhookDescription'; import { onfleetApiRequest } from './GenericFunctions'; import { webhookMapping } from './WebhookMapping'; +import { OptionsWithUri } from 'request'; export class OnfleetTrigger implements INodeType { description: INodeTypeDescription = { @@ -28,6 +32,7 @@ export class OnfleetTrigger implements INodeType { defaults: { name: 'Onfleet Trigger', color: '#AA81F3', + description: 'Handle Onfleet events via webhooks', }, inputs: [], outputs: [ 'main' ], @@ -57,6 +62,39 @@ export class OnfleetTrigger implements INodeType { ], }; + methods = { + credentialTest: { + async onfeletApiTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise { + const credentials = credential.data as IDataObject; + const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); + + const options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Basic ${encodedApiKey}`, + 'User-Agent': 'n8n-onfleet', + }, + method: 'GET', + uri: 'https://onfleet.com/api/v2/auth/test', + json: true, + }; + + try { + await this.helpers.request(options); + return { + status: 'OK', + message: 'Authentication successful', + }; + } catch (error) { + return { + status: 'Error', + message: `Settings are not valid: ${error}`, + }; + } + }, + }, + }; + // @ts-ignore (because of request) webhookMethods = { default: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts index 375706b90bebd..3adb397af145d 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/AdministratorDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const adminOperations = [ +export const adminOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -24,7 +24,7 @@ export const adminOperations = [ description: 'Delete an Onfleet admin', }, { - name: 'Get all', + name: 'Get All', value: 'getAll', description: 'Get all Onfleet admins', }, @@ -36,7 +36,7 @@ export const adminOperations = [ ], default: 'getAll', }, -] as INodeProperties[]; +]; const adminNameField = { displayName: 'Name', @@ -63,14 +63,14 @@ const adminPhoneField = { } as INodeProperties; const adminReadOnlyField = { - displayName: 'Read only', + displayName: 'Read Only', name: 'isReadOnly', type: 'boolean', default: false, description: 'Whether this administrator can perform write operations', } as INodeProperties; -export const adminFields = [ +export const adminFields: INodeProperties[] = [ { displayName: 'Admin ID', name: 'id', @@ -145,4 +145,4 @@ export const adminFields = [ adminReadOnlyField, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts index 5af0b137da2b3..c58cf1ef1d3c9 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const containerOperations = [ +export const containerOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -14,12 +14,12 @@ export const containerOperations = [ }, options: [ { - name: 'Insert tasks (or append)', + name: 'Insert Tasks (Or Append)', value: 'add', description: 'Insert tasks at index (or append)', }, { - name: 'Update tasks', + name: 'Update Tasks', value: 'update', description: 'Fully replace a container\'s tasks', }, @@ -31,7 +31,7 @@ export const containerOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; const containerTypeField = { displayName: 'Container Type', @@ -77,7 +77,7 @@ const insertTypeField = { value: 0, }, { - name: 'At specific index', + name: 'At Specific Index', value: 1, }, ], @@ -113,7 +113,7 @@ const considerDependenciesField = { description: 'Whether to include the target task\'s dependency family (parent and child tasks) in the resulting assignment operation', } as INodeProperties; -export const containerFields = [ +export const containerFields: INodeProperties[] = [ { ...containerTypeField, displayOptions: { @@ -198,4 +198,4 @@ export const containerFields = [ }, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 4f72445803885..9bd9904430f9b 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const destinationOperations = [ +export const destinationOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -27,7 +27,7 @@ export const destinationOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; const unparsedField = { displayName: 'Unparsed Address', @@ -42,7 +42,7 @@ const unparsedAddressField = { name: 'address', type: 'string', description: 'The destination\'s street address details', - default: null, + default: '', } as INodeProperties; const unparsedAddressNumberField = { @@ -209,7 +209,7 @@ export const destinationExternalField = { ], } as INodeProperties; -export const destinationFields = [ +export const destinationFields: INodeProperties[] = [ { displayName: 'Destination ID', name: 'id', @@ -330,4 +330,4 @@ export const destinationFields = [ addressPostalCodeField, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index 46e25a62fcffe..7fd67d6742bc2 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -3,7 +3,7 @@ import { } from 'n8n-workflow'; import { destinationExternalField } from './DestinationDescription'; -export const hubOperations = [ +export const hubOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -20,7 +20,7 @@ export const hubOperations = [ description: 'Create a new Onfleet hub', }, { - name: 'Get all', + name: 'Get All', value: 'getAll', description: 'Get all Onfleet hubs', }, @@ -32,7 +32,7 @@ export const hubOperations = [ ], default: 'getAll', }, -] as INodeProperties[]; +]; const nameField = { displayName: 'Name', @@ -53,7 +53,7 @@ const teamsField = { description: 'These are the teams that this Hub will be assigned to', } as INodeProperties; -export const hubFields = [ +export const hubFields: INodeProperties[] = [ { displayName: 'Hub ID', name: 'id', @@ -105,7 +105,7 @@ export const hubFields = [ options: [ { ...teamsField, - require: false, + required: false, }, ], }, @@ -129,4 +129,4 @@ export const hubFields = [ }, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts index 7d0fe7e2ca71d..7408dd14d7b41 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OnfleetWebhookDescription.ts @@ -28,7 +28,7 @@ export const eventNameField = { name: 'name', type: 'string', required: false, - default: null, + default: '', description: 'A name for the webhook for identification', }, ], diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts index f3abfa9d26578..3f67a225f11d2 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const organizationOperations = [ +export const organizationOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -27,9 +27,9 @@ export const organizationOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; -export const organizationFields = [ +export const organizationFields: INodeProperties[] = [ { displayName: 'Organiation ID', name: 'id', @@ -44,4 +44,4 @@ export const organizationFields = [ required: true, description: 'The ID of the delegatees for lookup', }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index 8478d5413a6b3..8ce5926d27e67 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const recipientOperations = [ +export const recipientOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -31,9 +31,9 @@ export const recipientOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; -const additionalRecipientFields = [ +const additionalRecipientFields: INodeProperties[] = [ { displayName: 'Recipient Notes', name: 'recipientNotes', @@ -69,11 +69,11 @@ const recipientPhone = { displayName: 'Recipient Phone', name: 'recipientPhone', type: 'string', - description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting', + description: 'A unique, valid phone number as per the organization\'s country if there\'s no leading + sign. If a phone number has a leading + sign, it will disregard the organization\'s country setting.', default: '', } as INodeProperties; -const updateFields = [ +const updateFields: INodeProperties[] = [ { ...recipientName, required: false, @@ -137,7 +137,7 @@ export const recipientExternalField = { ], } as INodeProperties; -export const recipientFields = [ +export const recipientFields: INodeProperties[] = [ { displayName: 'Get By', name: 'getBy', @@ -273,4 +273,4 @@ export const recipientFields = [ }, options: updateFields, }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 9f6ed502998e7..2e0a59b804bcf 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -4,7 +4,7 @@ import { import { destinationExternalField } from './DestinationDescription'; import { recipientExternalField } from './RecipientDescription'; -export const taskOperations = [ +export const taskOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -21,7 +21,7 @@ export const taskOperations = [ description: 'Create a new Onfleet task', }, { - name: 'Create multiple tasks', + name: 'Create Multiple Tasks', value: 'createBatch', description: 'Creating multiple tasks in batch', }, @@ -59,7 +59,7 @@ export const taskOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; const merchantIdField = { displayName: 'Merchant ID', @@ -125,7 +125,7 @@ const serviceTimeField = { description: 'The number of minutes to be spent by the worker on arrival at this task\'s destination, for route optimization purposes', } as INodeProperties; -export const taskFields = [ +export const taskFields: INodeProperties[] = [ { displayName: 'Task ID', name: 'id', @@ -184,6 +184,7 @@ export const taskFields = [ }, required: true, description: 'Whether the task short ID is used for lookup', + default: false, }, { displayName: 'From', @@ -195,7 +196,7 @@ export const taskFields = [ operation: [ 'getAll' ], }, }, - description: 'The starting time of the range. Tasks created or completed at or after this time will be included', + description: 'The starting time of the range. Tasks created or completed at or after this time will be included.', required: true, default: null, }, @@ -231,7 +232,7 @@ export const taskFields = [ name: 'to', type: 'dateTime', default: null, - description: 'The ending time of the range. Defaults to current time if not specified', + description: 'The ending time of the range. Defaults to current time if not specified.', }, { displayName: 'State', @@ -255,15 +256,15 @@ export const taskFields = [ value: 0, }, ], - default: null, + default: '', description: 'The state of the tasks', }, { - displayName: 'LastId', + displayName: 'Last ID', name: 'lastId', type: 'string', - default: null, - description: 'The last Id to walk the paginated response', + default: '', + description: 'The last ID to walk the paginated response', }, ], }, @@ -284,19 +285,19 @@ export const taskFields = [ displayName: 'Include Metadata', name: 'includeMetadata', type: 'boolean', - default: null, + default: false, }, { displayName: 'Include Barcodes', name: 'includeBarcodes', type: 'boolean', - default: null, + default: false, }, { displayName: 'Include Dependencies', name: 'includeDependencies', type: 'boolean', - default: null, + default: false, }, { displayName: 'Overrides', @@ -422,16 +423,16 @@ export const taskFields = [ displayName: 'Recipient Skip SMS Notifications Override', name: 'recipientSkipSMSNotifications', type: 'boolean', - default: '', - description: 'Override the recipient notification settings for this task only', + default: false, + description: 'Whether override the recipient notification settings for this task only or not', }, { displayName: 'Use Merchant For Proxy Override', name: 'useMerchantForProxy', type: 'boolean', - default: '', - description: 'Override the organization ID to use the merchant orgID when set to true for this task only', + default: false, + description: 'Whether override the organization ID to use the merchant orgID when set to true for this task only', }, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index 8f50513faaae1..ad98463cea76e 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const teamOperations = [ +export const teamOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -34,12 +34,12 @@ export const teamOperations = [ description: 'Get a specific Onfleet team', }, { - name: 'Get all', + name: 'Get All', value: 'getAll', description: 'List all Onfleet teams', }, { - name: 'Get time estimates', + name: 'Get Time Estimates', value: 'getTimeEstimates', description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet', }, @@ -51,7 +51,7 @@ export const teamOperations = [ ], default: 'getAll', }, -] as INodeProperties[]; +]; const nameField = { displayName: 'Name', @@ -99,7 +99,7 @@ const enableSelfAssignmentField = { name: 'enableSelfAssignment', type: 'boolean', default: false, - description: 'This toggles Team Self-Assignment that allows Drivers to Self Assign Tasks that are in the Team unassigned container', + description: 'Whether allows Drivers to Self Assign Tasks that are in the Team unassigned container or not', } as INodeProperties; const maxTasksPerRouteField = { @@ -138,7 +138,7 @@ const maxAllowedDelayField = { name: 'maxAllowedDelay', type: 'number', default: 10, - description: '', + description: 'Max allowed time in minutes that a task can be late', typeOptions: { minValue: 1, }, @@ -151,7 +151,7 @@ const longitudeDropoffField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The longitude for dropoff location', } as INodeProperties; @@ -162,7 +162,7 @@ const latitudeDropoffField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The latitude for dropoff location', } as INodeProperties; @@ -173,7 +173,7 @@ const longitudePickupField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The longitude for pickup location', } as INodeProperties; @@ -184,7 +184,7 @@ const latitudePickupField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The latitude for pickup location', } as INodeProperties; @@ -233,7 +233,7 @@ const serviceTimeEstimateField = { description: 'The expected time a worker will take at the pickupLocation, dropoffLocation, or both (as applicable) Unit: seconds', } as INodeProperties; -export const teamFields = [ +export const teamFields: INodeProperties[] = [ { displayName: 'Team ID', name: 'id', @@ -488,4 +488,4 @@ export const teamFields = [ }, ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts index fb3e2f47dee95..a2606bc52e143 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WebhookDescription.ts @@ -3,7 +3,7 @@ import { } from 'n8n-workflow'; import { webhookMapping } from '../WebhookMapping'; -export const webhookOperations = [ +export const webhookOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -32,14 +32,14 @@ export const webhookOperations = [ ], default: 'getAll', }, -] as INodeProperties[]; +]; const urlField = { displayName: 'Url', name: 'url', type: 'string', default: '', - description: 'The URL that Onfleet should issue a request against as soon as the trigger condition is met. It must be HTTPS and have a valid certificate', + description: 'The URL that Onfleet should issue a request against as soon as the trigger condition is met. It must be HTTPS and have a valid certificate.', } as INodeProperties; const nameField = { @@ -65,11 +65,11 @@ const thresholdField = { displayName: 'Threshold', name: 'threshold', type: 'number', - default: '', + default: 0, description: 'For trigger Task Eta, the time threshold in seconds; for trigger Task Arrival, the distance threshold in meters', } as INodeProperties; -export const webhookFields = [ +export const webhookFields: INodeProperties[] = [ { displayName: 'Webhook ID', name: 'id', @@ -128,4 +128,4 @@ export const webhookFields = [ }, options: [ thresholdField ], }, -] as INodeProperties[]; +]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index 63ea4713c5927..6ee153712f1e6 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties } from 'n8n-workflow'; -export const workerOperations = [ +export const workerOperations: INodeProperties[] = [ { displayName: 'Operation', name: 'operation', @@ -51,14 +51,14 @@ export const workerOperations = [ ], default: 'get', }, -] as INodeProperties[]; +]; const byLocationField = { - displayName: 'Search by location', + displayName: 'Search By Location', name: 'byLocation', type: 'boolean', default: false, - description: 'Search workers who are currently within a certain target area', + description: 'Whether searching workers who are currently within a certain target area or not', } as INodeProperties; const nameField = { @@ -171,15 +171,15 @@ const statesFilterField = { type: 'multiOptions', options: [ { - name: 'Active (on-duty, active task)', + name: 'Active (On-Duty, Active Task)', value: 2, }, { - name: 'Idle (on-duty, no active task)', + name: 'Idle (On-Duty, No Active Task)', value: 1, }, { - name: 'Off-duty', + name: 'Off-Duty', value: 0, }, ], @@ -245,7 +245,7 @@ const filterField = { value: 'onDuty', }, { - name: 'organization', + name: 'Organization', value: 'organization', }, { @@ -296,7 +296,7 @@ const longitudeFilterField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The longitude component of the coordinate pair', } as INodeProperties; @@ -307,7 +307,7 @@ const latitudeFilterField = { typeOptions: { numberPrecision: 14, }, - default: '', + default: 0, description: 'The latitude component of the coordinate pair', } as INodeProperties; @@ -320,7 +320,7 @@ const radiusFilterField = { minValue: 0, }, default: 1000, - description: 'The length in meters of the radius of the spherical area in which to look for workers. Defaults to 1000 if missing. Maximum value is 10000', + description: 'The length in meters of the radius of the spherical area in which to look for workers. Defaults to 1000 if missing. Maximum value is 10000.', } as INodeProperties; const scheduleDateField = { @@ -358,7 +358,7 @@ const scheduleEndField = { description: 'End time', } as INodeProperties; -export const workerFields = [ +export const workerFields: INodeProperties[] = [ { ...byLocationField, required: true, @@ -625,7 +625,7 @@ export const workerFields = [ type: 'boolean', default: true, required: false, - description: 'A more detailed response, includes basic worker duty event, traveled distance (meters) and time analytics', + description: 'Whether a more detailed response is needed, includes basic worker duty event, traveled distance (meters) and time analytics', }, ], }, @@ -689,4 +689,4 @@ export const workerFields = [ }, ], }, -] as INodeProperties[]; +]; From 78842f8cf63fe59a75ec53016c7e455fb6d4d445 Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz Date: Wed, 2 Feb 2022 08:42:23 -0500 Subject: [PATCH 11/12] fix: typos and better descriptions --- .../nodes-base/nodes/Onfleet/GenericFunctions.ts | 2 +- packages/nodes-base/nodes/Onfleet/Onfleet.node.ts | 4 ++-- .../Onfleet/descriptions/DestinationDescription.ts | 2 +- .../descriptions/OrganizationDescription.ts | 2 +- .../Onfleet/descriptions/RecipientDescription.ts | 2 +- .../nodes/Onfleet/descriptions/TaskDescription.ts | 4 ++-- .../nodes/Onfleet/descriptions/TeamDescription.ts | 14 +++++++------- .../Onfleet/descriptions/WorkerDescription.ts | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts index b5f540516d5c4..f4c2f99f829bd 100644 --- a/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Onfleet/GenericFunctions.ts @@ -42,7 +42,7 @@ export async function onfleetApiRequest( //@ts-ignore return await this.helpers.request(options); } catch (error) { - throw new NodeApiError(this.getNode(), error as JsonObject); // TODO: Check error + throw new NodeApiError(this.getNode(), error as JsonObject); } } diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index e945ab9410868..47b30a24a6c54 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -171,7 +171,7 @@ export class Onfleet implements INodeType { } catch (error) { return { status: 'Error', - message: `Settings are not valid: ${error}`, + message: `Auth settings are not valid: ${error}`, }; } }, @@ -377,7 +377,7 @@ export class Onfleet implements INodeType { const { vehicleProperties: vehicle } = this.getNodeParameter('vehicle', item) as IDataObject; const workerData: OnfleetWorker = { name, phone, teams }; - // Addding vehicule fields + // Adding vehicle fields if (Object.keys((vehicle as IDataObject)).length > 0) { const { type, additionalFields: additionalVehicleFields } = vehicle as IDataObject; Object.assign(workerData, { vehicle: { type, ...(additionalVehicleFields as IDataObject) } }); diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index 9bd9904430f9b..c2ba968e9c285 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -33,7 +33,7 @@ const unparsedField = { displayName: 'Unparsed Address', name: 'unparsed', type: 'boolean', - description: 'Whether the address is specified in a single', + description: 'Whether or not the address is specified in a single unparsed string', default: false, } as INodeProperties; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts index 3f67a225f11d2..a62ce16925494 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/OrganizationDescription.ts @@ -31,7 +31,7 @@ export const organizationOperations: INodeProperties[] = [ export const organizationFields: INodeProperties[] = [ { - displayName: 'Organiation ID', + displayName: 'Organization ID', name: 'id', type: 'string', displayOptions: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index 8ce5926d27e67..5e822fef774f3 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -263,7 +263,7 @@ export const recipientFields: INodeProperties[] = [ displayName: 'Update Fields', name: 'updateFields', type: 'collection', - placeholder: 'Update fields', + placeholder: 'Update Fields', default: {}, displayOptions: { show: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 2e0a59b804bcf..333f9ea2730dc 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -424,14 +424,14 @@ export const taskFields: INodeProperties[] = [ name: 'recipientSkipSMSNotifications', type: 'boolean', default: false, - description: 'Whether override the recipient notification settings for this task only or not', + description: 'Whether to override the recipient notification settings for this task', }, { displayName: 'Use Merchant For Proxy Override', name: 'useMerchantForProxy', type: 'boolean', default: false, - description: 'Whether override the organization ID to use the merchant orgID when set to true for this task only', + description: 'Whether to override the organization ID with the merchant\'s org ID for this task', }, ], }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index ad98463cea76e..8bb45721f507e 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -16,7 +16,7 @@ export const teamOperations: INodeProperties[] = [ { name: 'Auto-Dispatch', value: 'autoDispatch', - description: 'Dynamically dispatching tasks on the fly', + description: 'Automatically dispatch tasks assigned to a team to on-duty drivers', }, { name: 'Create', @@ -36,12 +36,12 @@ export const teamOperations: INodeProperties[] = [ { name: 'Get All', value: 'getAll', - description: 'List all Onfleet teams', + description: 'Get all Onfleet teams', }, { name: 'Get Time Estimates', value: 'getTimeEstimates', - description: 'The Driver Time Estimates endpoint allows an API user to get estimated times for tasks that haven\'t been created yet', + description: 'Get estimated times for upcoming tasks for a team, returns a selected driver', }, { name: 'Update', @@ -99,7 +99,7 @@ const enableSelfAssignmentField = { name: 'enableSelfAssignment', type: 'boolean', default: false, - description: 'Whether allows Drivers to Self Assign Tasks that are in the Team unassigned container or not', + description: 'Whether or not to allow drivers to self-assign tasks that are in the Team\'s unassigned container', } as INodeProperties; const maxTasksPerRouteField = { @@ -116,7 +116,7 @@ const maxTasksPerRouteField = { const serviceTimeField = { displayName: 'Service Time', - name: 'serviceTIme', + name: 'serviceTime', type: 'number', default: 2, typeOptions: { @@ -193,7 +193,7 @@ const pickupTimeField = { name: 'pickupTime', type: 'dateTime', default: '', - description: 'If the request includes pickupLocation pickupTime must be present if the time is fewer than 3 hours in the future', + description: 'If the request includes pickupLocation, pickupTime must be present if the time is fewer than 3 hours in the future', } as INodeProperties; const restrictedVehicleTypesField = { @@ -224,7 +224,7 @@ const restrictedVehicleTypesField = { const serviceTimeEstimateField = { displayName: 'Service Time', - name: 'serviceTIme', + name: 'serviceTime', type: 'number', default: 120, typeOptions: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index 6ee153712f1e6..6bd313e8f381c 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -116,7 +116,7 @@ const vehicleTypeField = { }, ], default: '', - description: 'Whether the worker has vehicle or not', + description: 'Whether the worker has vehicle or not. If it\'s not provided, this worker will be treated as if on foot.', } as INodeProperties; const vehicleDescriptionField = { @@ -286,7 +286,7 @@ const filterField = { }, ], default: '', - description: 'A list of fields to return, if all are not desired', + description: 'A list of fields to show in the response, if all are not desired', } as INodeProperties; const longitudeFilterField = { From 007ed0b04c9f30162c4c0a84f9803be71f1f2fbb Mon Sep 17 00:00:00 2001 From: Santiago Botero Ruiz <39206812+YokySantiago@users.noreply.github.com> Date: Mon, 14 Feb 2022 17:07:28 -0500 Subject: [PATCH 12/12] [INT-510] n8n: Address additional problems from n8n code review (#5) * Fixed some error creating a worker, moving some fields under additional fields collection * Fixed returned values for delete operations, making some changes for style code * Added operational error since required property is not working for dateTime fields --- .../nodes-base/nodes/Onfleet/Onfleet.node.ts | 318 ++++++++++-------- .../nodes/Onfleet/OnfleetTrigger.node.ts | 16 +- .../descriptions/ContainerDescription.ts | 2 +- .../descriptions/DestinationDescription.ts | 38 +-- .../Onfleet/descriptions/HubDescription.ts | 9 +- .../descriptions/RecipientDescription.ts | 12 +- .../Onfleet/descriptions/TaskDescription.ts | 112 ++---- .../Onfleet/descriptions/TeamDescription.ts | 153 +++++---- .../Onfleet/descriptions/WorkerDescription.ts | 4 +- 9 files changed, 320 insertions(+), 344 deletions(-) diff --git a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts index 47b30a24a6c54..13369ad4419b6 100644 --- a/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts +++ b/packages/nodes-base/nodes/Onfleet/Onfleet.node.ts @@ -25,6 +25,7 @@ import { OnfleetTaskUpdate, OnfleetTeamAutoDispatch, OnfleetTeams, + OnfleetVehicle, OnfleetWebhook, OnfleetWorker, OnfleetWorkerEstimates, @@ -35,16 +36,46 @@ import { import { taskFields, taskOperations } from './descriptions/TaskDescription'; import { IExecuteFunctions } from 'n8n-core'; -import { destinationFields, destinationOperations } from './descriptions/DestinationDescription'; -import { onfleetApiRequest, resourceLoaders } from './GenericFunctions'; -import { recipientFields, recipientOperations } from './descriptions/RecipientDescription'; -import { organizationFields, organizationOperations } from './descriptions/OrganizationDescription'; -import { adminFields, adminOperations } from './descriptions/AdministratorDescription'; -import { hubFields, hubOperations } from './descriptions/HubDescription'; -import { workerFields, workerOperations } from './descriptions/WorkerDescription'; -import { webhookFields, webhookOperations } from './descriptions/WebhookDescription'; -import { containerFields, containerOperations } from './descriptions/ContainerDescription'; -import { teamFields, teamOperations } from './descriptions/TeamDescription'; +import { + destinationFields, + destinationOperations, +} from './descriptions/DestinationDescription'; +import { + onfleetApiRequest, + resourceLoaders, +} from './GenericFunctions'; +import { + recipientFields, + recipientOperations, +} from './descriptions/RecipientDescription'; +import { + organizationFields, + organizationOperations, +} from './descriptions/OrganizationDescription'; +import { + adminFields, + adminOperations, +} from './descriptions/AdministratorDescription'; +import { + hubFields, + hubOperations, +} from './descriptions/HubDescription'; +import { + workerFields, + workerOperations, +} from './descriptions/WorkerDescription'; +import { + webhookFields, + webhookOperations, +} from './descriptions/WebhookDescription'; +import { + containerFields, + containerOperations, +} from './descriptions/ContainerDescription'; +import { + teamFields, + teamOperations, +} from './descriptions/TeamDescription'; import { OptionsWithUri } from 'request'; export class Onfleet implements INodeType { @@ -180,7 +211,7 @@ export class Onfleet implements INodeType { }; /** - * Returns a valid formated destination object + * Returns a valid formatted destination object * @param unparsed Whether the address is parsed or not * @param address Destination address * @param addressNumber Destination number @@ -234,27 +265,34 @@ export class Onfleet implements INodeType { /** * Gets the properties of a destination according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current destination opration + * @param operation Current destination operation + * @param shared Whether the collection is in other resource or not * @returns {OnfleetDestination} Destination information */ static getDestinationFields( - this: IExecuteFunctions, item: number, operation: string, shared = false, + this: IExecuteFunctions, item: number, operation: string, shared: { parent: string } | boolean = false, ): OnfleetDestination | OnfleetDestination[] | null { - if (['create', 'createBatch', 'update'].includes(operation)) { + if (['create', 'update'].includes(operation)) { /* -------------------------------------------------------------------------- */ - /* Get fields for create, createBatch and update task */ + /* Get fields for create and update a destination */ /* -------------------------------------------------------------------------- */ - if (shared) { - const { destinationProperties: destination } = this.getNodeParameter('destination', item) as IDataObject; + if (shared !== false) { + let destination; + if (typeof shared === 'boolean' && shared) { + const { destinationProperties = {} } = this.getNodeParameter('destination', item) as IDataObject; + destination = destinationProperties; + } else if (typeof shared !== 'boolean') { + const { destination: destinationCollection = {} } = this.getNodeParameter(shared.parent, item) as IDataObject; + destination = (destinationCollection as IDataObject).destinationProperties; + } if (!destination || Object.keys((destination) as IDataObject).length === 0) { return []; } const { - unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, additionalFields, + unparsed, address, addressNumber, addressStreet, addressCity, addressCountry, ...additionalFields } = destination as IDataObject; return Onfleet.formatAddress( unparsed as boolean, @@ -288,10 +326,9 @@ export class Onfleet implements INodeType { } /** - * Gets the properties of a administrator according to the operation chose - * @param this Current node execution function + * Gets the properties of an administrator according to the operation chose * @param item Current execution data - * @param operation Current administrator opration + * @param operation Current administrator operation * @returns {OnfleetAdmins} Administrator information */ static getAdminFields(this: IExecuteFunctions, item: number, operation: string): OnfleetAdmins | null { @@ -323,10 +360,9 @@ export class Onfleet implements INodeType { /** * Gets the properties of a hub according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current hub opration - * @returns {OnfleetHub} Hub information + * @param operation Current hub operation + * @returns {OnfleetHubs|null} Hub information */ static getHubFields(this: IExecuteFunctions, item: number, operation: string): OnfleetHubs | null { if (operation === 'create') { @@ -348,7 +384,7 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields for update hub */ /* -------------------------------------------------------------------------- */ - const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination; + const destination = Onfleet.getDestinationFields.call(this, item, operation, { parent: 'updateFields' }) as OnfleetDestination; const hubData: OnfleetHubs = { ...destination }; // Adding additional fields @@ -361,12 +397,11 @@ export class Onfleet implements INodeType { /** * Gets the properties of a worker according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current worker opration - * @returns {OnfleetWorker|OnfleetWorkerFilter|OnfleetWorkerSchedule} Worker information + * @param operation Current worker operation + * @returns {OnfleetWorker|OnfleetWorkerFilter|OnfleetWorkerSchedule|null} Worker information */ - static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | OnfleetWorkerSchedule | null { + static getWorkerFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWorker | OnfleetWorkerFilter | OnfleetWorkerSchedule | null { if (operation === 'create') { /* -------------------------------------------------------------------------- */ /* Get fields for create worker */ @@ -374,12 +409,12 @@ export class Onfleet implements INodeType { const name = this.getNodeParameter('name', item) as string; const phone = this.getNodeParameter('phone', item) as string; const teams = this.getNodeParameter('teams', item) as string[]; - const { vehicleProperties: vehicle } = this.getNodeParameter('vehicle', item) as IDataObject; + const { vehicleProperties: vehicle = {} } = this.getNodeParameter('vehicle', item) as IDataObject; const workerData: OnfleetWorker = { name, phone, teams }; // Adding vehicle fields if (Object.keys((vehicle as IDataObject)).length > 0) { - const { type, additionalFields: additionalVehicleFields } = vehicle as IDataObject; + const { type, additionalFields: additionalVehicleFields = {} } = vehicle as IDataObject; Object.assign(workerData, { vehicle: { type, ...(additionalVehicleFields as IDataObject) } }); } @@ -393,8 +428,8 @@ export class Onfleet implements INodeType { /* Get fields for update worker */ /* -------------------------------------------------------------------------- */ const {vehicleProperties} = this.getNodeParameter('vehicle', item) as IDataObject; - const { additionalFields: vehicle } = vehicleProperties as IDataObject; - const workerData: OnfleetWorker = { vehicle: (vehicle as IDataObject) }; + const { additionalFields: vehicle = {} } = vehicleProperties as IDataObject; + const workerData: OnfleetWorker = { vehicle: (vehicle as OnfleetVehicle) }; // Adding additional fields const updateFields = this.getNodeParameter('updateFields', item) as IDataObject; @@ -452,9 +487,8 @@ export class Onfleet implements INodeType { /** * Gets the properties of a webhooks according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current webhooks opration + * @param operation Current webhooks operation * @returns {OnfleetWebhook} Webhooks information */ static getWebhookFields(this: IExecuteFunctions, item: number, operation: string): OnfleetWebhook | null { @@ -477,7 +511,7 @@ export class Onfleet implements INodeType { } /** - * Returns a valid formated recipient object + * Returns a valid formatted recipient object * @param name Recipient name * @param phone Recipient phone * @param additionalFields Recipient additional fields @@ -504,44 +538,30 @@ export class Onfleet implements INodeType { /** * Gets the properties of a recipient according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current recipient opration + * @param operation Current recipient operation + * @param shared Whether the collection is in other resource or not * @returns {OnfleetRecipient} Recipient information */ static getRecipientFields( - this: IExecuteFunctions, item: number, operation: string, shared = false, multiple = false, + this: IExecuteFunctions, item: number, operation: string, shared = false, ): OnfleetRecipient | OnfleetRecipient[] | null { - if (['create', 'createBatch'].includes(operation)) { + if (operation === 'create') { /* -------------------------------------------------------------------------- */ /* Get fields to create recipient */ /* -------------------------------------------------------------------------- */ if (shared) { - if (multiple) { - const { recipientProperties: recipients } = this.getNodeParameter('recipient', item) as IDataObject; - if (!recipients || Object.keys(recipients).length === 0) { - return []; - } - return (recipients as IDataObject[]).map(recipient => { - const { recipientName: name, recipientPhone: phone, additionalFields } = recipient as IDataObject; - return Onfleet.formatRecipient( - name as string, - phone as string, - additionalFields as IDataObject, - ); - }); - } else { - const { recipientProperties: recipient } = this.getNodeParameter('recipient', item) as IDataObject; - if (!recipient || Object.keys(recipient).length === 0) { - return null; - } - const { recipientName: name, recipientPhone: phone, additionalFields } = recipient as IDataObject; - return Onfleet.formatRecipient( - name as string, - phone as string, - additionalFields as IDataObject, - ); + const { recipient: recipientData = {} } = this.getNodeParameter('additionalFields', item) as IDataObject; + const { recipientProperties: recipient = {} } = recipientData as IDataObject; + if (!recipient || Object.keys(recipient).length === 0) { + return null; } + const { recipientName: name, recipientPhone: phone, ...additionalFields } = recipient as IDataObject; + return Onfleet.formatRecipient( + name as string, + phone as string, + additionalFields as IDataObject, + ); } else { const name = this.getNodeParameter('recipientName', item) as string; const phone = this.getNodeParameter('recipientPhone', item) as string; @@ -573,22 +593,21 @@ export class Onfleet implements INodeType { /** * Gets the properties of a task according to the operation chose - * @param this Current node execution function - * @param items Current execution data + * @param item Current execution data * @param operation Current task operation * @returns {OnfleetListTaskFilters | OnfleetTask } Task information */ static getTaskFields(this: IExecuteFunctions, item: number, operation: string): OnfleetListTaskFilters | OnfleetTask | OnfleetCloneTask | OnfleetTaskComplete | OnfleetTaskUpdate | null { - if (['create', 'createBatch'].includes(operation)) { + if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Get fields to create and createBatch tasks */ + /* Get fields to create a task */ /* -------------------------------------------------------------------------- */ const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; const destination = Onfleet.getDestinationFields.call(this, item, operation, true) as OnfleetDestination; // Adding recipients information - const recipient = Onfleet.getRecipientFields.call(this, item, operation, true, false) as OnfleetRecipient; + const recipient = Onfleet.getRecipientFields.call(this, item, operation, true) as OnfleetRecipient; const taskData: OnfleetTask = { destination, recipients: [ recipient ] }; const { completeAfter = null, completeBefore = null, ...extraFields } = additionalFields; @@ -612,27 +631,26 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields to clone task */ /* -------------------------------------------------------------------------- */ - const { overrides, ...optionFields } = this.getNodeParameter('options', item) as IDataObject; - const { overrideProperties } = overrides as IDataObject; + const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; const options: OnfleetCloneTaskOptions = {}; - if (optionFields.includeMetadata) options.includeMetadata = optionFields.includeMetadata as boolean; - if (optionFields.includeBarcodes) options.includeBarcodes = optionFields.includeBarcodes as boolean; - if (optionFields.includeDependencies) options.includeDependencies = optionFields.includeDependencies as boolean; + if (additionalFields.includeMetadata) options.includeMetadata = additionalFields.includeMetadata as boolean; + if (additionalFields.includeBarcodes) options.includeBarcodes = additionalFields.includeBarcodes as boolean; + if (additionalFields.includeDependencies) options.includeDependencies = additionalFields.includeDependencies as boolean; // Adding overrides data - if (overrideProperties && Object.keys(overrideProperties).length > 0) { - const { - notes, pickupTask, serviceTime, completeAfter, completeBefore, - } = overrideProperties as IDataObject; - const overridesData = {} as OnfleetCloneOverrideTaskOptions; + const { + notes, pickupTask, serviceTime, completeAfter, completeBefore, + } = additionalFields as IDataObject; + const overridesData = {} as OnfleetCloneOverrideTaskOptions; - if (notes) overridesData.notes = notes as string; - if (typeof pickupTask !== 'undefined') overridesData.pickupTask = pickupTask as boolean; - if (serviceTime) overridesData.serviceTime = serviceTime as number; - if (completeAfter) overridesData.completeAfter = new Date(completeAfter as Date).getTime(); - if (completeBefore) overridesData.completeBefore = new Date(completeBefore as Date).getTime(); + if (notes) overridesData.notes = notes as string; + if (typeof pickupTask !== 'undefined') overridesData.pickupTask = pickupTask as boolean; + if (serviceTime) overridesData.serviceTime = serviceTime as number; + if (completeAfter) overridesData.completeAfter = new Date(completeAfter as Date).getTime(); + if (completeBefore) overridesData.completeBefore = new Date(completeBefore as Date).getTime(); + if (overridesData && Object.keys(overridesData).length > 0) { options.overrides = overridesData; } @@ -641,20 +659,22 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get fields to list tasks */ /* -------------------------------------------------------------------------- */ - const filterFields = this.getNodeParameter('filterFields', item) as IDataObject; - const listTaskData: OnfleetListTaskFilters = { - from: new Date(this.getNodeParameter('from', 0) as Date).getTime(), - }; + const filters = this.getNodeParameter('filters', item) as IDataObject; + const from = this.getNodeParameter('from', 0); + if (!from) { + throw new NodeOperationError(this.getNode(), 'From is required'); + } + const listTaskData: OnfleetListTaskFilters = { from: new Date(from as Date).getTime() }; // Adding extra fields to search tasks - if (filterFields.to) { - listTaskData.to = new Date(filterFields.to as Date).getTime(); + if (filters.to) { + listTaskData.to = new Date(filters.to as Date).getTime(); } - if (filterFields.state) { - listTaskData.state = (filterFields.state as number[]).join(','); + if (filters.state) { + listTaskData.state = (filters.state as number[]).join(','); } - if (filterFields.lastId) { - listTaskData.lastId = filterFields.lastId as string; + if (filters.lastId) { + listTaskData.lastId = filters.lastId as string; } return listTaskData; @@ -673,9 +693,8 @@ export class Onfleet implements INodeType { /** * Gets the properties of a team according to the operation chose - * @param this Current node execution function * @param item Current execution data - * @param operation Current team opration + * @param operation Current team operation * @returns {OnfleetTeams} Team information */ static getTeamFields(this: IExecuteFunctions, item: number, operation: string): OnfleetTeams | OnfleetWorkerEstimates | OnfleetTeamAutoDispatch | null { @@ -706,36 +725,33 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ /* Get driver time estimates for tasks that haven't been created yet */ /* -------------------------------------------------------------------------- */ - const { dropoffProperties } = this.getNodeParameter('dropoff', item) as IDataObject; - const { pickUpProperties } = this.getNodeParameter('pickUp', item) as IDataObject; - const dropoff = dropoffProperties as IDataObject; - const pickup = pickUpProperties as IDataObject; - const hasPickUp = pickup && Object.keys(pickup).length > 0; - const hasDropoff = dropoff && Object.keys(dropoff).length > 0; - - if (!hasPickUp && !hasDropoff) { + const { dropOff = {}, pickUp = {}, ...additionalFields } = this.getNodeParameter('additionalFields', item) as IDataObject; + const { dropOffProperties = {} }= dropOff as IDataObject; + const { pickUpProperties = {} }= pickUp as IDataObject; + const hasPickUp = pickUp && Object.keys(pickUpProperties as IDataObject).length > 0; + const hasDropOff = dropOffProperties && Object.keys(dropOffProperties as IDataObject).length > 0; + + if (!hasPickUp && !hasDropOff) { throw new NodeOperationError( - this.getNode(), 'At least 1 of dropoffLocation or pickupLocation must be selected', + this.getNode(), 'At least 1 of Drop-Off location or Pick-Up location must be selected', ); } const workerTimeEstimates = {} as OnfleetWorkerEstimates; if (hasPickUp) { const { - pickupLongitude: longitude, pickupLatitude: latitude, additionalFields, - } = pickup; - const { pickupTime } = additionalFields as IDataObject; + pickupLongitude: longitude, pickupLatitude: latitude, pickupTime, + } = pickUpProperties as IDataObject; workerTimeEstimates.pickupLocation = `${longitude},${latitude}`; if (pickupTime) { workerTimeEstimates.pickupTime = moment(new Date(pickupTime as Date)).local().unix(); } } - if(hasDropoff) { - const {dropoffLongitude: longitude, dropoffLatitude: latitude} = dropoff; + if(hasDropOff) { + const { dropOffLongitude: longitude, dropOffLatitude: latitude} = dropOffProperties as IDataObject; workerTimeEstimates.dropoffLocation = `${longitude},${latitude}`; } - const additionalFields = this.getNodeParameter('additionalFields', item) as IDataObject; Object.assign(workerTimeEstimates, additionalFields); return workerTimeEstimates; } else if (operation === 'autoDispatch') { @@ -744,10 +760,11 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const teamAutoDispatch = {} as OnfleetTeamAutoDispatch; const { - scheduleTimeWindow, taskTimeWindow, ...additionalFields + scheduleTimeWindow = {}, taskTimeWindow = {}, endingRoute = {}, ...additionalFields } = this.getNodeParameter('additionalFields', item) as IDataObject; - const { scheduleTimeWindowProperties } = scheduleTimeWindow as IDataObject; - const { taskTimeWindowProperties } = taskTimeWindow as IDataObject; + const { endingRouteProperties = {} } = endingRoute as IDataObject; + const { scheduleTimeWindowProperties = {} } = scheduleTimeWindow as IDataObject; + const { taskTimeWindowProperties = {} } = taskTimeWindow as IDataObject; if (scheduleTimeWindowProperties && Object.keys((scheduleTimeWindowProperties as IDataObject)).length > 0) { const { startTime, endTime } = scheduleTimeWindowProperties as IDataObject; @@ -756,6 +773,16 @@ export class Onfleet implements INodeType { ]; } + if (endingRouteProperties && Object.keys((endingRouteProperties as IDataObject)).length > 0) { + const { routeEnd, hub } = endingRouteProperties as IDataObject; + teamAutoDispatch.routeEnd = ({ + 'anywhere': null, + 'hub': `hub://${hub}`, + 'team_hub': 'teams://DEFAULT', + 'worker_routing_address': 'workers://ROUTING_ADDRESS', + })[routeEnd as string] as string; + } + if (taskTimeWindowProperties && Object.keys((taskTimeWindowProperties as IDataObject)).length > 0) { const { startTime, endTime } = taskTimeWindowProperties as IDataObject; teamAutoDispatch.taskTimeWindow = [ @@ -771,7 +798,6 @@ export class Onfleet implements INodeType { /** * Execute the task operations - * @param this Execute function * @param resource Resource to be executed (Task) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -785,7 +811,7 @@ export class Onfleet implements INodeType { items: INodeExecutionData[], encodedApiKey: string, ): Promise { - if (operation === 'createBatch') { + if (operation === 'create' && Object.keys(items).length > 1) { /* -------------------------------------------------------------------------- */ /* Create multiple tasks by batch */ /* -------------------------------------------------------------------------- */ @@ -811,7 +837,7 @@ export class Onfleet implements INodeType { /* Get a single task */ /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; - const shortId = this.getNodeParameter('shortId', index) as boolean; + const shortId = String(id).length <= 8; const path = `${resource}${(shortId ? '/shortId' : '')}/${id}`; responseData.push(await onfleetApiRequest.call(this, 'GET', encodedApiKey, path)); } else if (operation === 'clone') { @@ -829,7 +855,8 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; - responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path); + responseData.push({ success: true }); } else if (operation === 'getAll') { /* -------------------------------------------------------------------------- */ /* Get all tasks */ @@ -848,7 +875,8 @@ export class Onfleet implements INodeType { const taskData = Onfleet.getTaskFields.call(this, index, operation); if (!taskData) { continue; } const path = `${resource}/${id}/complete`; - responseData.push(await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, taskData)); + await onfleetApiRequest.call(this, 'POST', encodedApiKey, path, taskData); + responseData.push({ success: true }); } else if (operation === 'update') { /* -------------------------------------------------------------------------- */ /* Update a task */ @@ -863,15 +891,16 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } + if (['delete', 'complete'].includes(operation)) { + return { success: true }; + } return responseData; } /** * Execute the destination operations - * @param this Execute function * @param resource Resource to be executed (Destination) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -891,7 +920,7 @@ export class Onfleet implements INodeType { try { if (operation === 'create') { /* -------------------------------------------------------------------------- */ - /* Create destiantion */ + /* Create destination */ /* -------------------------------------------------------------------------- */ const destinationData = Onfleet.getDestinationFields.call(this, index, operation); if (!destinationData) { continue; } @@ -908,7 +937,6 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } @@ -917,7 +945,6 @@ export class Onfleet implements INodeType { /** * Execute the organization operations - * @param this Execute function * @param resource Resource to be executed (Organization) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -953,7 +980,6 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } @@ -962,7 +988,6 @@ export class Onfleet implements INodeType { /** * Execute the recipient operations - * @param this Execute function * @param resource Resource to be executed (Recipient) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1008,7 +1033,6 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } @@ -1017,7 +1041,6 @@ export class Onfleet implements INodeType { /** * Execute the administrator operations - * @param this Execute function * @param resource Resource to be executed (Administrator) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1060,22 +1083,24 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; - responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path); + responseData.push({ success: true }); } } catch (error) { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } + if (operation === 'delete') { + return { success: true }; + } return responseData; } /** * Execute the hub operations - * @param this Execute function * @param resource Resource to be executed (Hub) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1118,7 +1143,6 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } @@ -1127,7 +1151,6 @@ export class Onfleet implements INodeType { /** * Execute the worker operations - * @param this Execute function * @param resource Resource to be executed (Worker) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1194,7 +1217,8 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; - responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path); + responseData.push({ success: true }); } else if (operation === 'getSchedule') { /* -------------------------------------------------------------------------- */ /* Get worker schedule */ @@ -1215,16 +1239,17 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } + if (operation === 'delete') { + return { success: true }; + } return responseData; } /** * Execute the webhook operations - * @param this Execute function * @param resource Resource to be executed (Webhook) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1259,27 +1284,29 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; - responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path) + responseData.push({ success: true }); } } catch (error) { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } + if (operation === 'delete') { + return { success: true }; + } return responseData; } /** * Execute the containers operations - * @param this Execute function * @param resource Resource to be executed (Container) * @param operation Operation to be executed * @param items Number of items to process by the node * @param encodedApiKey API KEY for the current organization - * @returns Contianer information + * @returns Container information */ static async executeContainerOperations( this: IExecuteFunctions, @@ -1328,7 +1355,6 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } @@ -1337,7 +1363,6 @@ export class Onfleet implements INodeType { /** * Execute the team operations - * @param this Execute function * @param resource Resource to be executed (Team) * @param operation Operation to be executed * @param items Number of items to process by the node @@ -1387,7 +1412,8 @@ export class Onfleet implements INodeType { /* -------------------------------------------------------------------------- */ const id = this.getNodeParameter('id', index) as string; const path = `${resource}/${id}`; - responseData.push(await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path)); + await onfleetApiRequest.call(this, 'DELETE', encodedApiKey, path); + responseData.push({ success: true }); } else if (operation === 'getTimeEstimates') { /* -------------------------------------------------------------------------- */ /* Get driver time estimates for tasks that haven't been created yet */ @@ -1409,9 +1435,11 @@ export class Onfleet implements INodeType { if (this.continueOnFail()) { responseData.push({ error: (error as IDataObject).toString() }); } - continue; } } + if (operation === 'delete') { + return { success: true }; + } return responseData; } diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 59f70924c7564..0be93880d169e 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -8,14 +8,17 @@ import { IWebhookResponseData, NodeApiError, NodeCredentialTestResult, - NodeOperationError, + NodeOperationError } from 'n8n-workflow'; import { IHookFunctions, IWebhookFunctions, } from 'n8n-core'; -import { eventDisplay, eventNameField } from './descriptions/OnfleetWebhookDescription'; +import { + eventDisplay, + eventNameField, +} from './descriptions/OnfleetWebhookDescription'; import { onfleetApiRequest } from './GenericFunctions'; import { webhookMapping } from './WebhookMapping'; import { OptionsWithUri } from 'request'; @@ -143,7 +146,7 @@ export class OnfleetTrigger implements INodeType { return false; } - // Some error occured + // Some error occurred throw error; } @@ -153,7 +156,6 @@ export class OnfleetTrigger implements INodeType { const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; const encodedApiKey = Buffer.from(`${credentials.apiKey}:`).toString('base64'); const event = this.getNodeParameter('event', 0) as string; - const webhookData = this.getWorkflowStaticData('node'); const webhookUrl = this.getNodeWebhookUrl('default') as string; if (webhookUrl.includes('//localhost')) { @@ -210,8 +212,7 @@ export class OnfleetTrigger implements INodeType { }; /** - * Triggered function when a Onfleet webhook is executed - * @param this Webhook functions + * Triggered function when an Onfleet webhook is executed * @returns {Promise} Response data */ async webhook(this: IWebhookFunctions): Promise { @@ -225,8 +226,7 @@ export class OnfleetTrigger implements INodeType { return { noWebhookResponse: true }; } - const bodyData = this.getBodyData(); - const returnData: IDataObject = bodyData; + const returnData: IDataObject = this.getBodyData(); return { workflowData: [ diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts index c58cf1ef1d3c9..0dd65f01cf32b 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/ContainerDescription.ts @@ -94,7 +94,7 @@ const indexField = { } as INodeProperties; const tasksField = { - displayName: 'Tasks', + displayName: 'Task IDs', name: 'tasks', type: 'string', typeOptions: { diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts index c2ba968e9c285..dca95f201a3ab 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/DestinationDescription.ts @@ -170,39 +170,25 @@ export const destinationExternalField = { required: true, }, { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, - displayOptions: { - show: { - unparsed: [ true ], - }, - }, - options: [ - addressNameField, - addressApartmentField, - addressNoteField, - ], + ...addressNameField, + required: false, + }, + { + ...addressApartmentField, + required: false, + }, + { + ...addressNoteField, + required: false, }, { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, displayOptions: { show: { unparsed: [ false ], }, }, - options: [ - addressNameField, - addressApartmentField, - addressNoteField, - addressPostalCodeField, - ], + ...addressPostalCodeField, + required: false, }, ], }, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts index 7fd67d6742bc2..082790fb009ef 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/HubDescription.ts @@ -83,10 +83,7 @@ export const hubFields: INodeProperties[] = [ displayOptions: { show: { resource: [ 'hub' ], - operation: [ - 'create', - 'update', - ], + operation: [ 'create' ], }, }, }, @@ -127,6 +124,10 @@ export const hubFields: INodeProperties[] = [ ...teamsField, required: false, }, + { + ...destinationExternalField, + required: false, + }, ], }, ]; diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts index 5e822fef774f3..f38be161c6525 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/RecipientDescription.ts @@ -40,6 +40,7 @@ const additionalRecipientFields: INodeProperties[] = [ type: 'string', default: '', description: 'Notes for this recipient: these are global notes that should not be task- or destination-specific', + required: false, }, { displayName: 'Skip Recipient SMS Notifications', @@ -47,6 +48,7 @@ const additionalRecipientFields: INodeProperties[] = [ type: 'boolean', default: false, description: 'Whether this recipient has requested to skip SMS notifications', + required: false, }, { displayName: 'Skip Recipient Phone Number Validation', @@ -54,6 +56,7 @@ const additionalRecipientFields: INodeProperties[] = [ type: 'boolean', default: false, description: 'Whether to skip validation for this recipient\'s phone number', + required: false, }, ]; @@ -124,14 +127,7 @@ export const recipientExternalField = { ...recipientPhone, required: true, }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - default: {}, - options: additionalRecipientFields, - }, + ...additionalRecipientFields, ], }, ], diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts index 333f9ea2730dc..c55f9f844e62c 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TaskDescription.ts @@ -20,11 +20,6 @@ export const taskOperations: INodeProperties[] = [ value: 'create', description: 'Create a new Onfleet task', }, - { - name: 'Create Multiple Tasks', - value: 'createBatch', - description: 'Creating multiple tasks in batch', - }, { name: 'Clone', value: 'clone', @@ -137,7 +132,6 @@ export const taskFields: INodeProperties[] = [ hide: { operation: [ 'create', - 'createBatch', 'getAll', ], }, @@ -151,40 +145,11 @@ export const taskFields: INodeProperties[] = [ displayOptions: { show: { resource: [ 'task' ], - operation: [ - 'create', - 'createBatch', - ], + operation: [ 'create' ], }, }, default: {}, - }, - { - ...recipientExternalField, - displayOptions: { - show: { - resource: [ 'task' ], - operation: [ - 'create', - 'createBatch', - ], - }, - }, - default: {}, - }, - { - displayName: 'Short ID', - name: 'shortId', - type: 'boolean', - displayOptions: { - show: { - resource: [ 'task' ], - operation: [ 'get' ], - }, - }, required: true, - description: 'Whether the task short ID is used for lookup', - default: false, }, { displayName: 'From', @@ -198,7 +163,7 @@ export const taskFields: INodeProperties[] = [ }, description: 'The starting time of the range. Tasks created or completed at or after this time will be included.', required: true, - default: null, + default: '', }, { displayName: 'Success', @@ -215,10 +180,10 @@ export const taskFields: INodeProperties[] = [ default: true, }, { - displayName: 'Filter Fields', - name: 'filterFields', + displayName: 'Filters', + name: 'filters', type: 'collection', - placeholder: 'Add Field', + placeholder: 'Add Filter', default: {}, displayOptions: { show: { @@ -256,7 +221,7 @@ export const taskFields: INodeProperties[] = [ value: 0, }, ], - default: '', + default: [], description: 'The state of the tasks', }, { @@ -269,10 +234,10 @@ export const taskFields: INodeProperties[] = [ ], }, { - displayName: 'Options', - name: 'options', + displayName: 'Additional Fields', + name: 'additionalFields', type: 'collection', - placeholder: 'Add options', + placeholder: 'Add Field', default: {}, displayOptions: { show: { @@ -300,39 +265,24 @@ export const taskFields: INodeProperties[] = [ default: false, }, { - displayName: 'Overrides', - name: 'overrides', - type: 'fixedCollection', - default: {}, - options: [ - { - displayName: 'Override Properties', - name: 'overrideProperties', - default: {}, - values: [ - { - ...notesField, - required: false, - }, - { - ...pickupTaskField, - required: false, - }, - { - ...serviceTimeField, - required: false, - }, - { - ...completeAfterField, - required: false, - }, - { - ...completeBeforeField, - required: false, - }, - ], - }, - ], + ...notesField, + required: false, + }, + { + ...pickupTaskField, + required: false, + }, + { + ...serviceTimeField, + required: false, + }, + { + ...completeAfterField, + required: false, + }, + { + ...completeBeforeField, + required: false, }, ], }, @@ -382,7 +332,7 @@ export const taskFields: INodeProperties[] = [ ], }, { - displayName: 'Additional Task Fields', + displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', @@ -390,13 +340,11 @@ export const taskFields: INodeProperties[] = [ displayOptions: { show: { resource: [ 'task' ], - operation: [ - 'create', - 'createBatch', - ], + operation: [ 'create' ], }, }, options: [ + recipientExternalField, merchantIdField, executorIdField, completeAfterField, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts index 8bb45721f507e..12d35d0813ff1 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/TeamDescription.ts @@ -128,7 +128,13 @@ const serviceTimeField = { const routeEndField = { displayName: 'Route End', name: 'routeEnd', - type: 'string', + type: 'options', + options: [ + { name: 'Team’s Hub', value: 'team_hub' }, + { name: 'Worker Routing Address', value: 'worker_routing_address' }, + { name: 'Hub', value: 'hub' }, + { name: 'End Anywhere', value: 'anywhere' }, + ], default: '', description: 'Where the route will end', } as INodeProperties; @@ -144,26 +150,26 @@ const maxAllowedDelayField = { }, } as INodeProperties; -const longitudeDropoffField = { - displayName: 'Dropoff Longitude', - name: 'dropoffLongitude', +const longitudeDropOffField = { + displayName: 'Drop Off Longitude', + name: 'dropOffLongitude', type: 'number', typeOptions: { numberPrecision: 14, }, default: 0, - description: 'The longitude for dropoff location', + description: 'The longitude for drop off location', } as INodeProperties; -const latitudeDropoffField = { - displayName: 'Dropoff Latitude', - name: 'dropoffLatitude', +const latitudeDropOffField = { + displayName: 'Drop Off Latitude', + name: 'dropOffLatitude', type: 'number', typeOptions: { numberPrecision: 14, }, default: 0, - description: 'The latitude for dropoff location', + description: 'The latitude for drop off location', } as INodeProperties; const longitudePickupField = { @@ -336,7 +342,35 @@ export const teamFields: INodeProperties[] = [ options: [ maxAllowedDelayField, maxTasksPerRouteField, - routeEndField, + { + displayName: 'Ending Route', + name: 'endingRoute', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Ending Route Properties', + name: 'endingRouteProperties', + type: 'fixedCollection', + default: {}, + values: [ + { + ...routeEndField, + required: true, + }, + { + ...hubField, + displayOptions: { + show: { + routeEnd: [ 'hub' ], + }, + }, + required: false, + }, + ], + }, + ], + }, { displayName: 'Schedule Time Window', name: 'scheduleTimeWindow', @@ -397,64 +431,62 @@ export const teamFields: INodeProperties[] = [ ], }, { - displayName: 'Dropoff', - name: 'dropoff', - type: 'fixedCollection', + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Fields', + default: {}, displayOptions: { show: { resource: [ 'team' ], operation: [ 'getTimeEstimates' ], }, }, - default: {}, options: [ { - displayName: 'Dropoff Properties', - name: 'dropoffProperties', - values: [ - { - ...longitudeDropoffField, - required: true, - }, + displayName: 'Drop Off', + name: 'dropOff', + type: 'fixedCollection', + default: {}, + options: [ { - ...latitudeDropoffField, - required: true, + displayName: 'DropOff Properties', + name: 'dropOffProperties', + type: 'fixedCollection', + default: {}, + values: [ + { + ...longitudeDropOffField, + required: true, + }, + { + ...latitudeDropOffField, + required: true, + }, + ], }, ], }, - ], - }, - { - displayName: 'Pick Up', - name: 'pickUp', - type: 'fixedCollection', - displayOptions: { - show: { - resource: [ 'team' ], - operation: [ 'getTimeEstimates' ], - }, - }, - default: {}, - options: [ { - displayName: 'Pick Up Properties', - name: 'pickUpProperties', - values: [ - { - ...longitudePickupField, - required: true, - }, - { - ...latitudePickupField, - required: true, - }, + displayName: 'Pick Up', + name: 'pickUp', + type: 'fixedCollection', + default: {}, + options: [ { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', + displayName: 'Pick Up Properties', + name: 'pickUpProperties', + type: 'fixedCollection', default: {}, - options: [ + values: [ + { + ...longitudePickupField, + required: true, + }, + { + ...latitudePickupField, + required: true, + }, { ...pickupTimeField, required: false, @@ -463,21 +495,6 @@ export const teamFields: INodeProperties[] = [ }, ], }, - ], - }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add fields', - default: {}, - displayOptions: { - show: { - resource: [ 'team' ], - operation: [ 'getTimeEstimates' ], - }, - }, - options: [ { ...restrictedVehicleTypesField, required: false, diff --git a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts index 6bd313e8f381c..d7de0a8a02190 100644 --- a/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts +++ b/packages/nodes-base/nodes/Onfleet/descriptions/WorkerDescription.ts @@ -183,7 +183,7 @@ const statesFilterField = { value: 0, }, ], - default: '', + default: [], description: 'List of worker states', } as INodeProperties; @@ -285,7 +285,7 @@ const filterField = { value: 'id', }, ], - default: '', + default: [], description: 'A list of fields to show in the response, if all are not desired', } as INodeProperties;