forked from n8n-io/n8n
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add Onfleet Node & Trigger (n8n-io#2845)
* feat: added Onfleet nodes Added Onfleet nodes for working with different endpoints like: organizations, administrators, workers, hubs, teams, destinations, recipients, containers and webhooks. * style: fixed typos, arrays uniformity, unnecesary files * refactor: changed add to create in comments and labels * feat: added name field to onfleet trigger node * feat: added team endpoints to onfleet node Added team auto-dispatch and driver time estimate endpoints to Onfleet node * style: remove dots in descriptions and fixed some typos * 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 * fix: fixed recipient and destination cretion * docs: added docstrings for format some functions added docstrings for new functions addded for formatting the destination and recipient objects * style: formatting the code according to n8n nodelinter * fix: typos and better descriptions * [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 * ⚡ Improvements to n8n-io#2593 * ⚡ Improvements * 🐛 Fix issue with wrong interface * ⚡ Improvements * ⚡ Improvements * ⚡ Minor improvement Co-authored-by: Santiago Botero Ruiz <[email protected]> Co-authored-by: ilsemaj <[email protected]> Co-authored-by: Santiago Botero Ruiz <[email protected]> Co-authored-by: Jan Oberhauser <[email protected]>
- Loading branch information
1 parent
2ec4ed6
commit 401e626
Showing
21 changed files
with
5,593 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: '', | ||
}, | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { | ||
ICredentialDataDecryptedObject, | ||
IDataObject, | ||
IExecuteFunctions, | ||
IHookFunctions, | ||
ILoadOptionsFunctions, | ||
INodePropertyOptions, | ||
IWebhookFunctions, | ||
JsonObject, | ||
NodeApiError | ||
} from 'n8n-workflow'; | ||
|
||
import { | ||
OptionsWithUri, | ||
} from 'request'; | ||
|
||
import * as moment from 'moment-timezone'; | ||
|
||
export async function onfleetApiRequest( | ||
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, | ||
method: string, | ||
resource: string, | ||
body: any = {}, // tslint:disable-line:no-any | ||
qs?: any, // tslint:disable-line:no-any | ||
uri?: string): Promise<any> { // tslint:disable-line:no-any | ||
|
||
const credentials = await this.getCredentials('onfleetApi') as ICredentialDataDecryptedObject; | ||
|
||
const options: OptionsWithUri = { | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'User-Agent': 'n8n-onfleet', | ||
}, | ||
auth: { | ||
user: credentials.apiKey as string, | ||
pass: '', | ||
}, | ||
method, | ||
body, | ||
qs, | ||
uri: uri || `https://onfleet.com/api/v2/${resource}`, | ||
json: true, | ||
}; | ||
try { | ||
//@ts-ignore | ||
return await this.helpers.request(options); | ||
} catch (error) { | ||
throw new NodeApiError(this.getNode(), error as JsonObject); | ||
} | ||
} | ||
|
||
export async function onfleetApiRequestAllItems( | ||
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, | ||
propertyName: string, | ||
method: string, | ||
endpoint: string, | ||
// tslint:disable-next-line: no-any | ||
body: any = {}, | ||
query: IDataObject = {}, | ||
): Promise<any> { // tslint:disable-line:no-any | ||
|
||
const returnData: IDataObject[] = []; | ||
|
||
let responseData; | ||
|
||
do { | ||
responseData = await onfleetApiRequest.call(this, method, endpoint, body, query); | ||
query.lastId = responseData['lastId']; | ||
returnData.push.apply(returnData, responseData[propertyName]); | ||
} while ( | ||
responseData['lastId'] !== undefined | ||
); | ||
|
||
return returnData; | ||
} | ||
export const resourceLoaders = { | ||
async getTeams(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { | ||
try { | ||
const teams = await onfleetApiRequest.call(this, 'GET', 'teams') as IDataObject[]; | ||
return teams.map(({ name = '', id: value = '' }) => ({ name, value })) as INodePropertyOptions[]; | ||
} catch (error) { | ||
return []; | ||
} | ||
}, | ||
|
||
async getWorkers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { | ||
try { | ||
const workers = await onfleetApiRequest.call(this, 'GET', 'workers') as IDataObject[]; | ||
return workers.map(({ name = '', id: value = '' }) => ({ name, value })) as INodePropertyOptions[]; | ||
} catch (error) { | ||
return []; | ||
} | ||
}, | ||
|
||
async getAdmins(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { | ||
try { | ||
const admins = await onfleetApiRequest.call(this, 'GET', 'admins') as IDataObject[]; | ||
return admins.map(({ name = '', id: value = '' }) => ({ name, value })) as INodePropertyOptions[]; | ||
} catch (error) { | ||
return []; | ||
} | ||
}, | ||
|
||
async getHubs(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { | ||
try { | ||
const hubs = await onfleetApiRequest.call(this, 'GET', 'hubs') as IDataObject[]; | ||
return hubs.map(({ name = '', id: value = '' }) => ({ name, value })) as INodePropertyOptions[]; | ||
} catch (error) { | ||
return []; | ||
} | ||
}, | ||
|
||
async getTimezones(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { | ||
const returnData = [] as INodePropertyOptions[]; | ||
for (const timezone of moment.tz.names()) { | ||
returnData.push({ | ||
name: timezone, | ||
value: timezone, | ||
}); | ||
} | ||
return returnData; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
import { | ||
ICredentialsDecrypted, | ||
ICredentialTestFunctions, | ||
IDataObject, | ||
INodeCredentialTestResult, | ||
INodeExecutionData, | ||
INodeType, | ||
INodeTypeDescription, | ||
} from 'n8n-workflow'; | ||
|
||
import { | ||
taskFields, | ||
taskOperations, | ||
} from './descriptions/TaskDescription'; | ||
|
||
import { | ||
IExecuteFunctions, | ||
} from 'n8n-core'; | ||
|
||
import { | ||
destinationFields, | ||
destinationOperations, | ||
} from './descriptions/DestinationDescription'; | ||
|
||
import { | ||
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'; | ||
|
||
import { Onfleet as OnfleetMethods } from './Onfleet'; | ||
export class Onfleet implements INodeType { | ||
description: INodeTypeDescription = { | ||
displayName: 'Onfleet', | ||
name: 'onfleet', | ||
icon: 'file:Onfleet.svg', | ||
group: ['input'], | ||
version: 1, | ||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', | ||
description: 'Consume Onfleet API', | ||
defaults: { | ||
color: '#AA81F3', | ||
name: 'Onfleet', | ||
}, | ||
inputs: ['main'], | ||
outputs: ['main'], | ||
credentials: [ | ||
{ | ||
name: 'onfleetApi', | ||
required: true, | ||
testedBy: 'onfleetApiTest', | ||
}, | ||
], | ||
properties: [ | ||
// List of option resources | ||
{ | ||
displayName: 'Resource', | ||
name: 'resource', | ||
type: 'options', | ||
options: [ | ||
{ | ||
name: 'Admin', | ||
value: 'admin', | ||
}, | ||
{ | ||
name: 'Container', | ||
value: 'container', | ||
}, | ||
{ | ||
name: 'Destination', | ||
value: 'destination', | ||
}, | ||
{ | ||
name: 'Hub', | ||
value: 'hub', | ||
}, | ||
{ | ||
name: 'Organization', | ||
value: 'organization', | ||
}, | ||
{ | ||
name: 'Recipient', | ||
value: 'recipient', | ||
}, | ||
{ | ||
name: 'Task', | ||
value: 'task', | ||
}, | ||
{ | ||
name: 'Team', | ||
value: 'team', | ||
}, | ||
// { | ||
// name: 'Webhook', | ||
// value: 'webhook', | ||
// }, | ||
{ | ||
name: 'Worker', | ||
value: 'worker', | ||
}, | ||
], | ||
default: 'task', | ||
description: 'The resource to perform operations on', | ||
}, | ||
// Operations & fields | ||
...adminOperations, | ||
...adminFields, | ||
...containerOperations, | ||
...containerFields, | ||
...destinationOperations, | ||
...destinationFields, | ||
...hubOperations, | ||
...hubFields, | ||
...organizationOperations, | ||
...organizationFields, | ||
...recipientOperations, | ||
...recipientFields, | ||
...taskOperations, | ||
...taskFields, | ||
...teamOperations, | ||
...teamFields, | ||
// ...webhookOperations, | ||
// ...webhookFields, | ||
...workerOperations, | ||
...workerFields, | ||
], | ||
}; | ||
|
||
methods = { | ||
credentialTest: { | ||
async onfleetApiTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult> { | ||
const credentials = credential.data as IDataObject; | ||
|
||
const options: OptionsWithUri = { | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'User-Agent': 'n8n-onfleet', | ||
}, | ||
auth: { | ||
user: credentials.apiKey as string, | ||
pass: '', | ||
}, | ||
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: `Auth settings are not valid: ${error}`, | ||
}; | ||
} | ||
}, | ||
}, | ||
loadOptions: resourceLoaders, | ||
}; | ||
|
||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { | ||
const resource = this.getNodeParameter('resource', 0) as string; | ||
const operation = this.getNodeParameter('operation', 0) as string; | ||
const items = this.getInputData(); | ||
|
||
const operations: { [key: string]: Function } = { | ||
task: OnfleetMethods.executeTaskOperations, | ||
destination: OnfleetMethods.executeDestinationOperations, | ||
organization: OnfleetMethods.executeOrganizationOperations, | ||
admin: OnfleetMethods.executeAdministratorOperations, | ||
recipient: OnfleetMethods.executeRecipientOperations, | ||
hub: OnfleetMethods.executeHubOperations, | ||
worker: OnfleetMethods.executeWorkerOperations, | ||
webhook: OnfleetMethods.executeWebhookOperations, | ||
container: OnfleetMethods.executeContainerOperations, | ||
team: OnfleetMethods.executeTeamOperations, | ||
}; | ||
|
||
const responseData = await operations[resource].call(this, `${resource}s`, operation, items); | ||
|
||
// Map data to n8n data | ||
return [this.helpers.returnJsonArray(responseData)]; | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.