diff --git a/packages/nodes-base/credentials/FreshserviceApi.credentials.ts b/packages/nodes-base/credentials/FreshserviceApi.credentials.ts new file mode 100644 index 0000000000..cc5f716097 --- /dev/null +++ b/packages/nodes-base/credentials/FreshserviceApi.credentials.ts @@ -0,0 +1,27 @@ +import { + ICredentialType, + INodeProperties, +} from 'n8n-workflow'; + +export class FreshserviceApi implements ICredentialType { + name = 'freshserviceApi'; + displayName = 'Freshservice API'; + documentationUrl = 'freshservice'; + properties: INodeProperties[] = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string', + default: '', + placeholder: 'atuH3AbeH9HsKvgHuxg', + }, + { + displayName: 'Domain', + name: 'domain', + type: 'string', + default: '', + placeholder: 'n8n', + description: 'Domain in the Freshservice org URL. For example, in https://n8n.freshservice.com, the domain is n8n', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Freshservice/Freshservice.node.ts b/packages/nodes-base/nodes/Freshservice/Freshservice.node.ts new file mode 100644 index 0000000000..1b25eae228 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/Freshservice.node.ts @@ -0,0 +1,1525 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + ILoadOptionsFunctions, + INodeExecutionData, + INodePropertyOptions, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + adjustAddress, + adjustAgentRoles, + formatFilters, + freshserviceApiRequest, + handleListing, + sanitizeAssignmentScopeGroup, + toArray, + toOptions, + toUserOptions, + validateAssignmentScopeGroup, + validateUpdateFields, +} from './GenericFunctions'; + +import { + agentFields, + agentGroupFields, + agentGroupOperations, + agentOperations, + agentRoleFields, + agentRoleOperations, + announcementFields, + announcementOperations, + assetFields, + assetOperations, + assetTypeFields, + assetTypeOperations, + changeFields, + changeOperations, + departmentFields, + departmentOperations, + locationFields, + locationOperations, + problemFields, + problemOperations, + productFields, + productOperations, + releaseFields, + releaseOperations, + requesterFields, + requesterGroupFields, + requesterGroupOperations, + requesterOperations, + softwareFields, + softwareOperations, + ticketFields, + ticketOperations, +} from './descriptions'; + +import { + AddressFixedCollection, + LoadedResource, + LoadedUser, + RolesParameter, +} from './types'; + +import { + tz, +} from 'moment-timezone'; + +export class Freshservice implements INodeType { + description: INodeTypeDescription = { + displayName: 'Freshservice', + name: 'freshservice', + icon: 'file:freshservice.svg', + group: ['transform'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume the Freshservice API', + defaults: { + name: 'Freshservice', + color: '#08c7fb', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'freshserviceApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Agent', + value: 'agent', + }, + { + name: 'Agent Group', + value: 'agentGroup', + }, + { + name: 'Agent Role', + value: 'agentRole', + }, + { + name: 'Announcement', + value: 'announcement', + }, + // { + // name: 'Asset', + // value: 'asset', + // }, + { + name: 'Asset Type', + value: 'assetType', + }, + { + name: 'Change', + value: 'change', + }, + { + name: 'Department', + value: 'department', + }, + { + name: 'Location', + value: 'location', + }, + { + name: 'Problem', + value: 'problem', + }, + { + name: 'Product', + value: 'product', + }, + { + name: 'Release', + value: 'release', + }, + { + name: 'Requester', + value: 'requester', + }, + { + name: 'Requester Group', + value: 'requesterGroup', + }, + { + name: 'Software', + value: 'software', + }, + { + name: 'Ticket', + value: 'ticket', + }, + ], + default: 'agent', + }, + ...agentOperations, + ...agentFields, + ...agentGroupOperations, + ...agentGroupFields, + ...agentRoleOperations, + ...agentRoleFields, + ...announcementOperations, + ...announcementFields, + // ...assetOperations, + // ...assetFields, + ...assetTypeOperations, + ...assetTypeFields, + ...changeOperations, + ...changeFields, + ...departmentOperations, + ...departmentFields, + ...locationOperations, + ...locationFields, + ...problemOperations, + ...problemFields, + ...productOperations, + ...productFields, + ...releaseOperations, + ...releaseFields, + ...requesterOperations, + ...requesterFields, + ...requesterGroupOperations, + ...requesterGroupFields, + ...softwareOperations, + ...softwareFields, + ...ticketOperations, + ...ticketFields, + ], + }; + + methods = { + loadOptions: { + async getAgents(this: ILoadOptionsFunctions): Promise { + const { agents } = await freshserviceApiRequest.call(this, 'GET', '/agents') as { + agents: LoadedUser[]; + }; + return toUserOptions(agents.filter((agent) => agent.active)); + }, + + async getAgentGroups(this: ILoadOptionsFunctions): Promise { + const { groups } = await freshserviceApiRequest.call(this, 'GET', '/groups') as { + groups: LoadedResource[]; + }; + return toOptions(groups); + }, + + async getAgentRoles(this: ILoadOptionsFunctions): Promise { + const { roles } = await freshserviceApiRequest.call(this, 'GET', '/roles') as { + roles: LoadedResource[]; + }; + return toOptions(roles); + }, + + async getAssetTypes(this: ILoadOptionsFunctions): Promise { + const { asset_types } = await freshserviceApiRequest.call(this, 'GET', '/asset_types') as { + asset_types: LoadedResource[]; + }; + return toOptions(asset_types); + }, + + async getAssetTypeFields(this: ILoadOptionsFunctions): Promise { + const assetType = this.getCurrentNodeParameter('assetTypeId'); + const { asset_type_fields } = await freshserviceApiRequest.call(this, 'GET', `/asset_types/${assetType}/fields`) as { + asset_type_fields: [{ fields: LoadedResource[] }]; + }; + // tslint:disable-next-line: no-any + let fields: any[] = []; + fields = fields.concat(...asset_type_fields.map((data) => data.fields)).map(data => ({ name: data.label, id: data.name })); + return toOptions(fields); + }, + + async getDepartments(this: ILoadOptionsFunctions): Promise { + const { departments } = await freshserviceApiRequest.call(this, 'GET', '/departments') as { + departments: LoadedResource[]; + }; + return toOptions(departments); + }, + + async getLocations(this: ILoadOptionsFunctions): Promise { + const { locations } = await freshserviceApiRequest.call(this, 'GET', '/locations') as { + locations: LoadedResource[]; + }; + return toOptions(locations); + }, + + async getRequesters(this: ILoadOptionsFunctions): Promise { + const { requesters } = await freshserviceApiRequest.call(this, 'GET', '/requesters') as { + requesters: LoadedUser[]; + }; + return toUserOptions(requesters); + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + + const defaultTimezone = this.getTimezone(); + + let responseData; + + for (let i = 0; i < items.length; i++) { + + try { + + if (resource === 'agent') { + + // ********************************************************************** + // agent + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // agent: create + // ---------------------------------------- + + const body = { + email: this.getNodeParameter('email', i), + first_name: this.getNodeParameter('firstName', i), + } as IDataObject; + + const roles = this.getNodeParameter('roles', i) as RolesParameter; + + validateAssignmentScopeGroup.call(this, roles); + sanitizeAssignmentScopeGroup.call(this, roles); + + Object.assign(body, adjustAgentRoles(roles)); + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/agents', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // agent: delete + // ---------------------------------------- + + const agentId = this.getNodeParameter('agentId', i); + responseData = await freshserviceApiRequest.call(this, 'DELETE', `/agents/${agentId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // agent: get + // ---------------------------------------- + + const agentId = this.getNodeParameter('agentId', i); + responseData = await freshserviceApiRequest.call(this, 'GET', `/agents/${agentId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // agent: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + } + + responseData = await handleListing.call(this, 'GET', '/agents', {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // agent: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const agentId = this.getNodeParameter('agentId', i); + responseData = await freshserviceApiRequest.call(this, 'PUT', `/agents/${agentId}`, body); + + } + + } else if (resource === 'agentGroup') { + + // ********************************************************************** + // agentGroup + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // agentGroup: create + // ---------------------------------------- + + const body = { + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/groups', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // agentGroup: delete + // ---------------------------------------- + + const agentGroupId = this.getNodeParameter('agentGroupId', i); + const endpoint = `/groups/${agentGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // agentGroup: get + // ---------------------------------------- + + const agentGroupId = this.getNodeParameter('agentGroupId', i); + const endpoint = `/groups/${agentGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // agentGroup: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/groups'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // agentGroup: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const agentGroupId = this.getNodeParameter('agentGroupId', i); + const endpoint = `/groups/${agentGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'agentRole') { + + // ********************************************************************** + // agentRole + // ********************************************************************** + + if (operation === 'get') { + + // ---------------------------------------- + // agentRole: get + // ---------------------------------------- + + const agentRoleId = this.getNodeParameter('agentRoleId', i); + responseData = await freshserviceApiRequest.call(this, 'GET', `/roles/${agentRoleId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // agentRole: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/roles'); + + } + + } else if (resource === 'announcement') { + + // ********************************************************************** + // announcement + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // announcement: create + // ---------------------------------------- + + const visibleFrom = this.getNodeParameter('visibleFrom', i) as string; + + const body = { + title: this.getNodeParameter('title', i), + body_html: this.getNodeParameter('bodyHtml', i), + visibility: this.getNodeParameter('visibility', i), + visible_from: tz(visibleFrom, defaultTimezone), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & { + additional_emails?: string; + visible_till?: string; + }; + + if (Object.keys(additionalFields).length) { + const { visible_till, additional_emails, ...rest } = additionalFields; + + Object.assign(body, { + ...(additional_emails && { additional_emails: toArray(additional_emails) }), + ...(visible_till && { visible_till: tz(visible_till, defaultTimezone) }), + ...rest, + }); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/announcements', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // announcement: delete + // ---------------------------------------- + + const announcementId = this.getNodeParameter('announcementId', i); + const endpoint = `/announcements/${announcementId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // announcement: get + // ---------------------------------------- + + const announcementId = this.getNodeParameter('announcementId', i); + + const endpoint = `/announcements/${announcementId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // announcement: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/announcements'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // announcement: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject & { + additional_emails?: string; + visible_till?: string; + }; + + validateUpdateFields.call(this, updateFields, resource); + + const { visible_till, additional_emails, ...rest } = updateFields; + + Object.assign(body, { + ...(additional_emails && { additional_emails: toArray(additional_emails) }), + ...(visible_till && { visible_till: tz(visible_till, defaultTimezone) }), + ...rest, + }); + + const announcementId = this.getNodeParameter('announcementId', i); + const endpoint = `/announcements/${announcementId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'asset') { + + // ********************************************************************** + // asset + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // asset: create + // ---------------------------------------- + + const body = { + asset_type_id: this.getNodeParameter('assetTypeId', i), + name: this.getNodeParameter('name', i), + } as IDataObject; + + const assetFields = this.getNodeParameter('assetFieldsUi.assetFieldValue', i, []) as IDataObject[]; + + Object.assign(body, { type_fields: assetFields.reduce((obj, value) => Object.assign(obj, { [`${value.name}`]: value.value }), {}) }); + console.log(body); + responseData = await freshserviceApiRequest.call(this, 'POST', '/assets', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // asset: delete + // ---------------------------------------- + + const assetDisplayId = this.getNodeParameter('assetDisplayId', i); + responseData = await freshserviceApiRequest.call(this, 'DELETE', `/assets/${assetDisplayId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // asset: get + // ---------------------------------------- + + const assetDisplayId = this.getNodeParameter('assetDisplayId', i); + responseData = await freshserviceApiRequest.call(this, 'GET', `/assets/${assetDisplayId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // asset: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + } + + responseData = await handleListing.call(this, 'GET', '/assets', {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // asset: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const assetDisplayId = this.getNodeParameter('assetDisplayId', i); + responseData = await freshserviceApiRequest.call(this, 'PUT', `/assets/${assetDisplayId}`, body); + + } + + } else if (resource === 'assetType') { + + // ********************************************************************** + // assetType + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // assetType: create + // ---------------------------------------- + + const body = { + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/asset_types', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // assetType: delete + // ---------------------------------------- + + const assetTypeId = this.getNodeParameter('assetTypeId', i); + + const endpoint = `/asset_types/${assetTypeId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // assetType: get + // ---------------------------------------- + + const assetTypeId = this.getNodeParameter('assetTypeId', i); + const endpoint = `/asset_types/${assetTypeId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // assetType: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/asset_types'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // assetType: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const assetTypeId = this.getNodeParameter('assetTypeId', i); + const endpoint = `/asset_types/${assetTypeId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'change') { + + // ********************************************************************** + // change + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // change: create + // ---------------------------------------- + + const body = { + requester_id: this.getNodeParameter('requesterId', i), + subject: this.getNodeParameter('subject', i), + planned_start_date: this.getNodeParameter('plannedStartDate', i), + planned_end_date: this.getNodeParameter('plannedEndDate', i), + status: 1, + priority: 1, + impact: 1, + risk: 1, + change_type: 1, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/changes', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // change: delete + // ---------------------------------------- + + const changeId = this.getNodeParameter('changeId', i); + responseData = await freshserviceApiRequest.call(this, 'DELETE', `/changes/${changeId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // change: get + // ---------------------------------------- + + const changeId = this.getNodeParameter('changeId', i); + responseData = await freshserviceApiRequest.call(this, 'GET', `/changes/${changeId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // change: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + } + + responseData = await handleListing.call(this, 'GET', '/changes', {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // change: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const changeId = this.getNodeParameter('changeId', i); + responseData = await freshserviceApiRequest.call(this, 'PUT', `/changes/${changeId}`, body); + + } + + } else if (resource === 'department') { + + // ********************************************************************** + // department + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // department: create + // ---------------------------------------- + + const body = { + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & { + domains?: string; + }; + + if (Object.keys(additionalFields).length) { + const { domains, ...rest } = additionalFields; + Object.assign(body, { + ...(domains && { domains: toArray(domains) }), + ...rest, + }); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/departments', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // department: delete + // ---------------------------------------- + + const departmentId = this.getNodeParameter('departmentId', i); + const endpoint = `/departments/${departmentId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // department: get + // ---------------------------------------- + + const departmentId = this.getNodeParameter('departmentId', i); + const endpoint = `/departments/${departmentId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // department: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + } + + responseData = await handleListing.call(this, 'GET', '/departments', {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // department: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject & { + domains?: string; + }; + + validateUpdateFields.call(this, updateFields, resource); + + const { domains, ...rest } = updateFields; + Object.assign(body, { + ...(domains && { domains: toArray(domains) }), + ...rest, + }); + + const departmentId = this.getNodeParameter('departmentId', i); + const endpoint = `/departments/${departmentId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'location') { + + // ********************************************************************** + // location + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // location: create + // ---------------------------------------- + + const body = { + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & AddressFixedCollection; + + if (Object.keys(additionalFields).length) { + Object.assign(body, adjustAddress(additionalFields)); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/locations', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // location: delete + // ---------------------------------------- + + const locationId = this.getNodeParameter('locationId', i); + const endpoint = `/locations/${locationId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // location: get + // ---------------------------------------- + + const locationId = this.getNodeParameter('locationId', i); + const endpoint = `/locations/${locationId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // location: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/locations'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // location: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, adjustAddress(updateFields)); + + const locationId = this.getNodeParameter('locationId', i); + const endpoint = `/locations/${locationId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'problem') { + + // ********************************************************************** + // problem + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // problem: create + // ---------------------------------------- + + const body = { + subject: this.getNodeParameter('subject', i), + requester_id: this.getNodeParameter('requesterId', i), + due_by: this.getNodeParameter('dueBy', i), + status: 1, + priority: 1, + impact: 1, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/problems', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // problem: delete + // ---------------------------------------- + + const problemId = this.getNodeParameter('problemId', i); + const endpoint = `/problems/${problemId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // problem: get + // ---------------------------------------- + + const problemId = this.getNodeParameter('problemId', i); + const endpoint = `/problems/${problemId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // problem: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/problems'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // problem: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const problemId = this.getNodeParameter('problemId', i); + const endpoint = `/problems/${problemId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'product') { + + // ********************************************************************** + // product + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // product: create + // ---------------------------------------- + + const body = { + asset_type_id: this.getNodeParameter('assetTypeId', i), + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/products', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // product: delete + // ---------------------------------------- + + const productId = this.getNodeParameter('productId', i); + + const endpoint = `/products/${productId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // product: get + // ---------------------------------------- + + const productId = this.getNodeParameter('productId', i); + const endpoint = `/products/${productId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // product: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/products'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // product: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + Object.assign(body, updateFields); + + const productId = this.getNodeParameter('productId', i); + const endpoint = `/products/${productId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'release') { + + // ********************************************************************** + // release + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // release: create + // ---------------------------------------- + + const body = { + subject: this.getNodeParameter('subject', i), + release_type: this.getNodeParameter('releaseType', i), + status: this.getNodeParameter('status', i), + priority: this.getNodeParameter('priority', i), + planned_start_date: this.getNodeParameter('plannedStartDate', i), + planned_end_date: this.getNodeParameter('plannedEndDate', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/releases', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // release: delete + // ---------------------------------------- + + const releaseId = this.getNodeParameter('releaseId', i); + const endpoint = `/releases/${releaseId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // release: get + // ---------------------------------------- + + const releaseId = this.getNodeParameter('releaseId', i); + const endpoint = `/releases/${releaseId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // release: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/releases'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // release: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + Object.assign(body, updateFields); + + const releaseId = this.getNodeParameter('releaseId', i); + const endpoint = `/releases/${releaseId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'requester') { + + // ********************************************************************** + // requester + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // requester: create + // ---------------------------------------- + + const body = { + first_name: this.getNodeParameter('firstName', i), + primary_email: this.getNodeParameter('primaryEmail', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & { + secondary_emails?: string; + }; + + if (Object.keys(additionalFields).length) { + const { secondary_emails, ...rest } = additionalFields; + + Object.assign(body, { + ...(secondary_emails && { secondary_emails: toArray(secondary_emails) }), + ...rest, + }); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/requesters', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // requester: delete + // ---------------------------------------- + + const requesterId = this.getNodeParameter('requesterId', i); + const endpoint = `/requesters/${requesterId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // requester: get + // ---------------------------------------- + + const requesterId = this.getNodeParameter('requesterId', i); + const endpoint = `/requesters/${requesterId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // requester: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + } + + responseData = await handleListing.call(this, 'GET', '/requesters', {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // requester: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject & { + secondary_emails?: string; + }; + + validateUpdateFields.call(this, updateFields, resource); + + const { secondary_emails, ...rest } = updateFields; + + Object.assign(body, { + ...(secondary_emails && { secondary_emails: toArray(secondary_emails) }), + ...rest, + }); + + const requesterId = this.getNodeParameter('requesterId', i); + const endpoint = `/requesters/${requesterId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'requesterGroup') { + + // ********************************************************************** + // requesterGroup + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // requesterGroup: create + // ---------------------------------------- + + const body = { + name: this.getNodeParameter('name', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/requester_groups', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // requesterGroup: delete + // ---------------------------------------- + + const requesterGroupId = this.getNodeParameter('requesterGroupId', i); + const endpoint = `/requester_groups/${requesterGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // requesterGroup: get + // ---------------------------------------- + + const requesterGroupId = this.getNodeParameter('requesterGroupId', i); + const endpoint = `/requester_groups/${requesterGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // requesterGroup: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/requester_groups'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // requesterGroup: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const requesterGroupId = this.getNodeParameter('requesterGroupId', i); + const endpoint = `/requester_groups/${requesterGroupId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'software') { + + // ********************************************************************** + // software + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // software: create + // ---------------------------------------- + + const body = { + application: { + application_type: this.getNodeParameter('applicationType', i), + name: this.getNodeParameter('name', i), + }, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (Object.keys(additionalFields).length) { + Object.assign(body.application, additionalFields); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/applications', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // software: delete + // ---------------------------------------- + + const softwareId = this.getNodeParameter('softwareId', i); + const endpoint = `/applications/${softwareId}`; + responseData = await freshserviceApiRequest.call(this, 'DELETE', endpoint); + + } else if (operation === 'get') { + + // ---------------------------------------- + // software: get + // ---------------------------------------- + + const softwareId = this.getNodeParameter('softwareId', i); + const endpoint = `/applications/${softwareId}`; + responseData = await freshserviceApiRequest.call(this, 'GET', endpoint); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // software: getAll + // ---------------------------------------- + + responseData = await handleListing.call(this, 'GET', '/applications'); + + } else if (operation === 'update') { + + // ---------------------------------------- + // software: update + // ---------------------------------------- + + const body = { application: {} } as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body.application, updateFields); + + const softwareId = this.getNodeParameter('softwareId', i); + const endpoint = `/applications/${softwareId}`; + responseData = await freshserviceApiRequest.call(this, 'PUT', endpoint, body); + + } + + } else if (resource === 'ticket') { + + // ********************************************************************** + // ticket + // ********************************************************************** + + if (operation === 'create') { + + // ---------------------------------------- + // ticket: create + // ---------------------------------------- + + const body = { + email: this.getNodeParameter('email', i), + subject: this.getNodeParameter('subject', i), + description: this.getNodeParameter('description', i), + priority: this.getNodeParameter('priority', i), + status: this.getNodeParameter('status', i), + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject & { + cc_emails?: string, + }; + + if (Object.keys(additionalFields).length) { + const { cc_emails, ...rest } = additionalFields; + + Object.assign(body, { + ...(cc_emails && { cc_emails: toArray(cc_emails) }), + ...rest, + }); + } + + responseData = await freshserviceApiRequest.call(this, 'POST', '/tickets', body); + + } else if (operation === 'delete') { + + // ---------------------------------------- + // ticket: delete + // ---------------------------------------- + + const ticketId = this.getNodeParameter('ticketId', i); + responseData = await freshserviceApiRequest.call(this, 'DELETE', `/tickets/${ticketId}`); + + } else if (operation === 'get') { + + // ---------------------------------------- + // ticket: get + // ---------------------------------------- + + const ticketId = this.getNodeParameter('ticketId', i); + responseData = await freshserviceApiRequest.call(this, 'GET', `/tickets/${ticketId}`); + + } else if (operation === 'getAll') { + + // ---------------------------------------- + // ticket: getAll + // ---------------------------------------- + + const qs = {} as IDataObject; + const filters = this.getNodeParameter('filters', i) as IDataObject; + let endpoint = ''; + + if (Object.keys(filters).length) { + Object.assign(qs, formatFilters(filters)); + endpoint = '/tickets/filter'; + } else { + endpoint = '/tickets'; + } + + responseData = await handleListing.call(this, 'GET', endpoint, {}, qs); + + } else if (operation === 'update') { + + // ---------------------------------------- + // ticket: update + // ---------------------------------------- + + const body = {} as IDataObject; + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + + validateUpdateFields.call(this, updateFields, resource); + + Object.assign(body, updateFields); + + const ticketId = this.getNodeParameter('ticketId', i); + responseData = await freshserviceApiRequest.call(this, 'PUT', `/tickets/${ticketId}`, body); + + } + } + + if (operation === 'delete' && !responseData) { + responseData = { success: true }; + } else if (operation !== 'getAll') { + const special: { [key: string]: string } = { + agentGroup: 'group', + agentRole: 'role', + assetType: 'asset_type', + requesterGroup: 'requester_group', + software: 'application', + }; + responseData = responseData[special[resource]] ?? responseData[resource]; + } + + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ error: error.message }); + continue; + } + throw error; + } + + Array.isArray(responseData) + ? returnData.push(...responseData) + : returnData.push(responseData); + + } + + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Freshservice/GenericFunctions.ts b/packages/nodes-base/nodes/Freshservice/GenericFunctions.ts new file mode 100644 index 0000000000..96b94184ae --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/GenericFunctions.ts @@ -0,0 +1,243 @@ +import { + IExecuteFunctions, + IHookFunctions, +} from 'n8n-core'; + +import { + IDataObject, + ILoadOptionsFunctions, + NodeApiError, + NodeOperationError, +} from 'n8n-workflow'; + +import { + AddressFixedCollection, + FreshserviceCredentials, + LoadedUser, + RolesParameter, +} from './types'; + +import { + OptionsWithUri, +} from 'request'; + +import { + omit, +} from 'lodash'; + +export async function freshserviceApiRequest( + this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions, + method: string, + endpoint: string, + body: IDataObject = {}, + qs: IDataObject = {}, +) { + const { apiKey, domain } = await this.getCredentials('freshserviceApi') as FreshserviceCredentials; + const encodedApiKey = Buffer.from(`${apiKey}:X`).toString('base64'); + + const options: OptionsWithUri = { + headers: { + Authorization: `Basic ${encodedApiKey}`, + }, + method, + body, + qs, + uri: `https://${domain}.freshservice.com/api/v2${endpoint}`, + json: true, + }; + + if (!Object.keys(body).length) { + delete options.body; + } + + if (!Object.keys(qs).length) { + delete options.qs; + } + + try { + return await this.helpers.request!(options); + } catch (error) { + if (error.error.description === 'Validation failed') { + + const numberOfErrors = error.error.errors.length; + const message = 'Please check your parameters'; + + if (numberOfErrors === 1) { + const [validationError] = error.error.errors; + throw new NodeApiError(this.getNode(), error, { + message, + description: `For ${validationError.field}: ${validationError.message}`, + }); + + } else if (numberOfErrors > 1) { + throw new NodeApiError(this.getNode(), error, { + message, + description: 'For more information, expand \'details\' below and look at \'cause\' section', + }); + } + } + + throw new NodeApiError(this.getNode(), error); + } +} + +export async function freshserviceApiRequestAllItems( + this: IExecuteFunctions | IHookFunctions, + method: string, + endpoint: string, + body: IDataObject = {}, + qs: IDataObject = {}, +) { + const returnData: IDataObject[] = []; + qs.page = 1; + let items; + + do { + const responseData = await freshserviceApiRequest.call(this, method, endpoint, body, qs); + const key = Object.keys(responseData)[0]; + items = responseData[key]; + if (!items.length) return returnData; + returnData.push(...items); + qs.page++; + } while ( + items.length >= 30 + ); + + return returnData; +} + +export async function handleListing( + this: IExecuteFunctions, + method: string, + endpoint: string, + body: IDataObject = {}, + qs: IDataObject = {}, +) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + + if (returnAll) { + return await freshserviceApiRequestAllItems.call(this, method, endpoint, body, qs); + } + + const responseData = await freshserviceApiRequestAllItems.call(this, method, endpoint, body, qs); + const limit = this.getNodeParameter('limit', 0) as number; + + return responseData.slice(0, limit); +} + +export const toOptions = (loadedResources: LoadedResource[]) => { + return loadedResources + .map(({ id, name }) => ({ value: id, name })) + .sort((a, b) => a.name.localeCompare(b.name)); +}; + +export const toUserOptions = (loadedUsers: LoadedUser[]) => { + return loadedUsers + .map(({ id, last_name, first_name }) => { + return { + value: id, + name: last_name ? `${last_name}, ${first_name}` : `${first_name}`, + }; + }) + .sort((a, b) => a.name.localeCompare(b.name)); +}; + +/** + * Ensure at least one role has been specified. + */ +export function validateAssignmentScopeGroup( + this: IExecuteFunctions, + roles: RolesParameter, +) { + if (!roles.roleProperties?.length) { + throw new NodeOperationError( + this.getNode(), + 'Please specify a role for the agent to create.', + ); + } +} + +export function sanitizeAssignmentScopeGroup( + this: IExecuteFunctions, + roles: RolesParameter, +) { + roles.roleProperties.forEach(roleProperty => { + if (roleProperty.assignment_scope === 'specified_groups' && !roleProperty?.groups?.length) { + throw new NodeOperationError( + this.getNode(), + 'Please specify a group for every role of the agent to create.', + ); + } + + // remove the `groups` param, only needed for scopes other than `specified_groups` + if (roleProperty.assignment_scope !== 'specified_groups' && roleProperty.groups) { + delete roleProperty.groups; + } + }); +} + +/** + * Adjust a roles fixed collection into the format expected by Freshservice API. + */ +export function adjustAgentRoles(roles: RolesParameter) { + return { + roles: roles.roleProperties.map(({ role, assignment_scope, groups }) => { + return { + role_id: role, + assignment_scope, + groups, + }; + }), + }; +} + +export function formatFilters(filters: IDataObject) { + const query = Object.keys(filters).map(key => { + const value = filters[key]; + + if (!isNaN(Number(value))) { + return `${key}:${filters[key]}`; // number + } + + if (typeof value === 'string' && value.endsWith('Z')) { + return `${key}:'${value.split('T')[0]}'`; // date + } + + return `${key}:'${filters[key]}'`; // string + }).join(' AND '); + + return { + query: `"${query}"`, + }; +} + +export function validateUpdateFields( + this: IExecuteFunctions, + updateFields: IDataObject, + resource: string, +) { + if (!Object.keys(updateFields).length) { + const twoWordResources: { [key: string]: string } = { + agentGroup: 'agent group', + agentRole: 'agent role', + assetType: 'asset type', + requesterGroup: 'requester group', + }; + + throw new NodeOperationError( + this.getNode(), + `Please enter at least one field to update for the ${twoWordResources[resource] ?? resource}.`, + ); + } +} + +export const toArray = (str: string) => str.split(',').map(e => e.trim()); + +export function adjustAddress(fixedCollection: IDataObject & AddressFixedCollection) { + if (!fixedCollection.address) return fixedCollection; + + const adjusted = omit(fixedCollection, ['address']); + adjusted.address = fixedCollection.address.addressFields; + + return adjusted; +} diff --git a/packages/nodes-base/nodes/Freshservice/constants.ts b/packages/nodes-base/nodes/Freshservice/constants.ts new file mode 100644 index 0000000000..4223a31eb7 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/constants.ts @@ -0,0 +1,44 @@ +// https://support.freshservice.com/support/solutions/articles/232303-list-of-languages-supported-in-freshservice + +const RAW_LANGUAGES: { [key: string]: string } = { + en: 'English', + ar: 'Arabic', + ca: 'Catalan', + cs: 'Czech', + 'cy-GB': 'Welsh', + da: 'Danish', + de: 'German', + es: 'Spanish', + 'es-LA': 'Spanish (Latin America)', + et: 'Estonian', + fi: 'Finnish', + fr: 'French', + he: 'Hebrew', + hu: 'Hungarian', + id: 'Indonesian', + it: 'Italian', + 'ja-JP': 'Japanese', + ko: 'Korean', + LV: 'Latvian', + 'nb-NO': 'Norwegian', + nl: 'Dutch', + pl: 'Polish', + pt: 'Portuguese', + 'pt-BR': 'Portuguese (Brazil)', + 'pt-PT': 'Portuguese (Portugal)', + 'ru-RU': 'Russian', + sk: 'Slovak', + 'sk-SK': 'Slovak', + sl: 'Slovenian', + 'sv-SE': 'Swedish', + th: 'Thai', + tr: 'Turkish', + UK: 'Ukrainian', + vi: 'Vietnamese', + 'zh-CN': 'Chinese (Simplified)', + 'zh-TW': 'Chinese (Traditional)', +}; + +export const LANGUAGES = Object.keys(RAW_LANGUAGES).map((key) => { + return ({ value: key, name: RAW_LANGUAGES[key] }); +}); diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AgentDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AgentDescription.ts new file mode 100644 index 0000000000..17ea178ffd --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AgentDescription.ts @@ -0,0 +1,697 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + LANGUAGES, +} from '../constants'; + +export const agentOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'agent', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an agent', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an agent', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve an agent', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all agents', + }, + { + name: 'Update', + value: 'update', + description: 'Update an agent', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const agentFields = [ + // ---------------------------------------- + // agent: create + // ---------------------------------------- + { + displayName: 'Email', + name: 'email', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'First Name', + name: 'firstName', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Roles', + name: 'roles', + description: 'Role to assign to the agent', + type: 'fixedCollection', + placeholder: 'Add Role', + typeOptions: { + multipleValues: true, + }, + required: true, + default: {}, + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Role Properties', + name: 'roleProperties', + values: [ + { + displayName: 'Role Name/ID', + name: 'role', + description: 'Name of the role to assign to the agent. Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + typeOptions: { + loadOptionsMethod: [ + 'getAgentRoles', + ], + }, + required: true, + default: '', + }, + { + displayName: 'Scope', + name: 'assignment_scope', + description: 'Scope in which the agent may use the permissions granted by the role', + type: 'options', + options: [ + { + name: 'Entire Helpdesk', + value: 'entire_helpdesk', + }, + { + name: 'Member Groups', + value: 'member_groups', + }, + { + name: 'Specified Groups', + value: 'specified_groups', + }, + { + name: 'Assigned Items', + value: 'assigned_items', + }, + ], + required: true, + default: 'specified_groups', + }, + { + displayName: 'Group Names/IDs', + name: 'groups', + description: 'Groups in which the permissions granted by the role apply. Required only when Scope is Specified Groups - ignored otherwise. Choose from the list or specify an ID using an expression.', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + default: [], + }, + ], + }, + ], + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'address', + type: 'string', + default: '', + }, + { + displayName: 'Background Information', + name: 'background_information', + type: 'string', + default: '', + }, + { + displayName: 'Department Names/IDs', + name: 'department_ids', + type: 'multiOptions', + default: [], + description: 'IDs of the departments to which the agent belongs. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + default: '', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Member of Group Names/IDs', + name: 'member_of', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the groups that the agent is a member of. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Mobile Phone', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Observer of Group Names/IDs', + name: 'observer_of', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the groups that the agent is an observer of. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Scoreboard Level ID', + name: 'scoreboard_level_id', + type: 'options', + description: 'ID of the level of the agent in the Arcade', + default: 1, + options: [ + { + name: 'Beginner', + value: 1, + }, + { + name: 'Intermediate', + value: 2, + }, + { + name: 'Professional', + value: 3, + }, + { + name: 'Expert', + value: 4, + }, + { + name: 'Master', + value: 5, + }, + { + name: 'Guru', + value: 6, + }, + ], + }, + { + displayName: 'Time Format', + name: 'time_format', + type: 'options', + default: '12h', + options: [ + { + name: '12-Hour Format', + value: '12h', + }, + { + name: '24-Hour Format', + value: '24h', + }, + ], + }, + { + displayName: 'Work Phone', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // agent: delete + // ---------------------------------------- + { + displayName: 'Agent ID', + name: 'agentId', + description: 'ID of the agent to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // agent: get + // ---------------------------------------- + { + displayName: 'Agent ID', + name: 'agentId', + description: 'ID of the agent to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // agent: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department to which the agent belongs. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + }, + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + default: '', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Mobile Phone Number', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Work Phone Number', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // agent: update + // ---------------------------------------- + { + displayName: 'Agent ID', + name: 'agentId', + description: 'ID of the agent to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'agent', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'address', + type: 'string', + default: '', + }, + { + displayName: 'Background Information', + name: 'background_information', + type: 'string', + default: '', + }, + { + displayName: 'Department Names/IDs', + name: 'department_ids', + type: 'multiOptions', + default: [], + description: 'IDs of the departments to which the agent belongs. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + }, + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + default: '', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Member of Group Names/IDs', + name: 'member_of', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the groups that the agent is a member of. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Mobile Phone', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Observer of Group Names/IDs', + name: 'observer_of', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the groups that the agent is an observer of. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Scoreboard Level ID', + name: 'scoreboard_level_id', + type: 'options', + description: 'ID of the level of the agent in the Arcade', + default: 1, + options: [ + { + name: 'Beginner', + value: 1, + }, + { + name: 'Intermediate', + value: 2, + }, + { + name: 'Professional', + value: 3, + }, + { + name: 'Expert', + value: 4, + }, + { + name: 'Master', + value: 5, + }, + { + name: 'Guru', + value: 6, + }, + ], + }, + { + displayName: 'Time Format', + name: 'time_format', + type: 'options', + default: '12h', + options: [ + { + name: '12-Hour Format', + value: '12h', + }, + { + name: '24-Hour Format', + value: '24h', + }, + ], + }, + { + displayName: 'Work Phone', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AgentGroupDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AgentGroupDescription.ts new file mode 100644 index 0000000000..fe7616e76e --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AgentGroupDescription.ts @@ -0,0 +1,389 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const agentGroupOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an agent group', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an agent group', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve an agent group', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all agent groups', + }, + { + name: 'Update', + value: 'update', + description: 'Update an agent group', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const agentGroupFields = [ + // ---------------------------------------- + // agentGroup: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Escalate to Agent Name/ID', + name: 'escalate_to', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + description: 'ID of the user to whom an escalation email is sent if a ticket in this group is unassigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + }, + { + displayName: 'Member Names/IDs', + name: 'members', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of agents who are members of this group. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Observer Names/IDs', + name: 'observers', + type: 'multiOptions', + default: [], + description: 'Comma-separated agent IDs who are observers of this group. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Unassigned For', + name: 'unassigned_for', + description: 'Time after which an escalation email is sent if a ticket in the group remains unassigned', + type: 'options', + default: '30m', + options: [ + { + name: '30 Minutes', + value: '30m', + }, + { + name: '1 Hour', + value: '1h', + }, + { + name: '2 Hours', + value: '2h', + }, + { + name: '8 Hours', + value: '8h', + }, + { + name: '12 Hours', + value: '12h', + }, + { + name: '1 Day', + value: '1d', + }, + { + name: '2 Days', + value: '2d', + }, + { + name: '3 Days', + value: '3d', + }, + ], + }, + ], + }, + + // ---------------------------------------- + // agentGroup: delete + // ---------------------------------------- + { + displayName: 'Agent Group ID', + name: 'agentGroupId', + description: 'ID of the agent group to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // agentGroup: get + // ---------------------------------------- + { + displayName: 'Agent Group ID', + name: 'agentGroupId', + description: 'ID of the agent group to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // agentGroup: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // agentGroup: update + // ---------------------------------------- + { + displayName: 'Agent Group ID', + name: 'agentGroupId', + description: 'ID of the agent group to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'agentGroup', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Escalate to Agent Names/IDs', + name: 'escalate_to', + type: 'options', + default: '', + description: 'ID of the agent to whom an escalation email is sent if a ticket in this group is unassigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Member Names/IDs', + name: 'members', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of agents who are members of this group. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Observer Names/IDs', + name: 'observers', + type: 'multiOptions', + default: [], + description: 'Comma-separated agent user IDs who are observers of this group. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Unassigned For', + name: 'unassigned_for', + description: 'Time after which an escalation email is sent if a ticket in the group remains unassigned', + type: 'options', + default: '30m', + options: [ + { + name: '30 Minutes', + value: '30m', + }, + { + name: '1 Hour', + value: '1h', + }, + { + name: '2 Hours', + value: '2h', + }, + { + name: '8 Hours', + value: '8h', + }, + { + name: '12 Hours', + value: '12h', + }, + { + name: '1 Day', + value: '1d', + }, + { + name: '2 Days', + value: '2d', + }, + { + name: '3 Days', + value: '3d', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AgentRoleDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AgentRoleDescription.ts new file mode 100644 index 0000000000..8595fb9926 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AgentRoleDescription.ts @@ -0,0 +1,99 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const agentRoleOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'agentRole', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Retrieve an agent role', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all agent roles', + }, + ], + default: 'get', + }, +] as INodeProperties[]; + +export const agentRoleFields = [ + // ---------------------------------------- + // agentRole: get + // ---------------------------------------- + { + displayName: 'Agent Role ID', + name: 'agentRoleId', + description: 'ID of the agent role to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'agentRole', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // agentRole: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'agentRole', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'agentRole', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AnnouncementDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AnnouncementDescription.ts new file mode 100644 index 0000000000..73c5e433f1 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AnnouncementDescription.ts @@ -0,0 +1,369 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const announcementOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an announcement', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an announcement', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve an announcement', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all announcements', + }, + { + name: 'Update', + value: 'update', + description: 'Update an announcement', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const announcementFields = [ + // ---------------------------------------- + // announcement: create + // ---------------------------------------- + { + displayName: 'Title', + name: 'title', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Body', + name: 'bodyHtml', + description: 'HTML supported', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Visibility', + name: 'visibility', + type: 'options', + required: true, + default: 'everyone', + options: [ + { + name: 'Agents Only', + value: 'agents_only', + }, + { + name: 'Agents and Groups', + value: 'grouped_visibility', + }, + { + name: 'Everyone', + value: 'everyone', + }, + ], + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Visible From', + name: 'visibleFrom', + description: 'Timestamp at which announcement becomes active', + type: 'dateTime', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Additional Emails', + name: 'additional_emails', + type: 'string', + default: '', + description: 'Comma-separated additional email addresses to which the announcement needs to be sent', + }, + { + displayName: 'Department Names/IDs', + name: 'departments', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of departments that may view this announcement. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Visible From', + name: 'visible_from', + description: 'Timestamp at which announcement is active', + type: 'dateTime', + default: '', + }, + { + displayName: 'Visible Until', + name: 'visible_till', + description: 'Timestamp until which announcement is active', + type: 'dateTime', + default: '', + }, + ], + }, + + // ---------------------------------------- + // announcement: delete + // ---------------------------------------- + { + displayName: 'Announcement ID', + name: 'announcementId', + description: 'ID of the announcement to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // announcement: get + // ---------------------------------------- + { + displayName: 'Announcement ID', + name: 'announcementId', + description: 'ID of the announcement to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // announcement: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // announcement: update + // ---------------------------------------- + { + displayName: 'Announcement ID', + name: 'announcementId', + description: 'ID of the announcement to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'announcement', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Additional Emails', + name: 'additional_emails', + type: 'string', + default: '', + description: 'Comma-separated additional email addresses to which the announcement needs to be sent', + }, + { + displayName: 'Body', + name: 'body_html', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Department Names/IDs', + name: 'departments', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of departments that may view this announcement. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + }, + { + displayName: 'Visibility', + name: 'visibility', + type: 'options', + default: 'everyone', + options: [ + { + name: 'Agents Only', + value: 'agents_only', + }, + { + name: 'Agents and Groups', + value: 'grouped_visibility', + }, + { + name: 'Everyone', + value: 'everyone', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AssetDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AssetDescription.ts new file mode 100644 index 0000000000..9d815a793b --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AssetDescription.ts @@ -0,0 +1,378 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const assetOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'asset', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an asset', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an asset', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve an asset', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all assets', + }, + { + name: 'Update', + value: 'update', + description: 'Update an asset', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const assetFields = [ + // ---------------------------------------- + // asset: create + // ---------------------------------------- + { + displayName: 'Asset Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Asset Type Name/ID', + name: 'assetTypeId', + type: 'options', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getAssetTypes', + ], + }, + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Asset Fields', + name: 'assetFieldsUi', + placeholder: 'Add Asset Field', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'create', + ], + }, + }, + default: {}, + options: [ + { + name: 'assetFieldValue', + displayName: 'Asset Field', + values: [ + { + displayName: 'Name/ID', + name: 'name', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'assetTypeId', + ], + loadOptionsMethod: 'getAssetTypeFields', + }, + default: '', + description: 'The ID of the field to add custom field to.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'The value to set on custom field.', + }, + ], + }, + ], + }, + // ---------------------------------------- + // asset: delete + // ---------------------------------------- + { + displayName: 'Asset Display ID', + name: 'assetDisplayId', + description: 'Display ID of the asset to delete. Do not confuse with asset ID.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // asset: get + // ---------------------------------------- + { + displayName: 'Asset Display ID', + name: 'assetDisplayId', + description: 'Display ID of the asset to retrieve. Do not confuse with asset ID.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // asset: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent by whom the asset is managed. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Asset State', + name: 'asset_state', + type: 'string', + default: '', + description: 'Status of the asset to filter by. For example, "In use".', + }, + { + displayName: 'Asset Type Name/ID', + name: 'asset_type_id', + type: 'options', + default: '', + description: 'ID of the asset type to filter by. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAssetTypes', + ], + }, + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department to which the asset belongs. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + default: '', + description: 'ID of the location to filter by. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Display name of the asset to filter by', + }, + ], + }, + + // ---------------------------------------- + // asset: update + // ---------------------------------------- + { + displayName: 'Asset Display ID', + name: 'assetDisplayId', + description: 'Display ID of the asset to update. Do not confuse with asset ID.', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Asset Fields', + name: 'assetFieldsUi', + placeholder: 'Add Asset Field', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + displayOptions: { + show: { + resource: [ + 'asset', + ], + operation: [ + 'update', + ], + }, + }, + default: {}, + options: [ + { + name: 'assetFieldValue', + displayName: 'Asset Field', + values: [ + { + displayName: 'Name/ID', + name: 'name', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'assetTypeId', + ], + loadOptionsMethod: 'getAssetTypeFields', + }, + default: '', + description: 'The ID of the field to add custom field to.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + description: 'The value to set on custom field.', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/AssetTypeDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/AssetTypeDescription.ts new file mode 100644 index 0000000000..7c4af2bc7a --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/AssetTypeDescription.ts @@ -0,0 +1,247 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const assetTypeOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an asset type', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an asset type', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve an asset type', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all asset types', + }, + { + name: 'Update', + value: 'update', + description: 'Update an asset type', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const assetTypeFields = [ + // ---------------------------------------- + // assetType: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Parent Asset Type Name/ID', + name: 'parent_asset_type_id', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getAssetTypes', + ], + }, + }, + ], + }, + + // ---------------------------------------- + // assetType: delete + // ---------------------------------------- + { + displayName: 'Asset Type ID', + name: 'assetTypeId', + description: 'ID of the asset type to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // assetType: get + // ---------------------------------------- + { + displayName: 'Asset Type ID', + name: 'assetTypeId', + description: 'ID of the asset type to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // assetType: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // assetType: update + // ---------------------------------------- + { + displayName: 'Asset Type ID', + name: 'assetTypeId', + description: 'ID of the asset type to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'assetType', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/ChangeDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/ChangeDescription.ts new file mode 100644 index 0000000000..c447678b42 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/ChangeDescription.ts @@ -0,0 +1,702 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const changeOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'change', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a change', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a change', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a change', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all changes', + }, + { + name: 'Update', + value: 'update', + description: 'Update a change', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const changeFields = [ + // ---------------------------------------- + // change: create + // ---------------------------------------- + { + displayName: 'Requester Name/ID', + name: 'requesterId', + description: 'ID of the requester of the change. Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getRequesters', + ], + }, + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Planned Start Date', + name: 'plannedStartDate', + type: 'dateTime', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Planned End Date', + name: 'plannedEndDate', + type: 'dateTime', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent to whom the change is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Change Type', + name: 'change_type', + type: 'options', + default: 1, + options: [ + { + name: 'Minor', + value: 1, + }, + { + name: 'Standard', + value: 2, + }, + { + name: 'Major', + value: 3, + }, + { + name: 'Emergency', + value: 4, + }, + ], + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department requesting the change. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the change is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Risk', + name: 'risk', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Very High', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'Planning', + value: 2, + }, + { + name: 'Approval', + value: 3, + }, + { + name: 'Pending Release', + value: 4, + }, + { + name: 'Pending Review', + value: 5, + }, + { + name: 'Closed', + value: 6, + }, + ], + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // change: delete + // ---------------------------------------- + { + displayName: 'Change ID', + name: 'changeId', + description: 'ID of the change to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // change: get + // ---------------------------------------- + { + displayName: 'Change ID', + name: 'changeId', + description: 'ID of the change to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // change: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Predefined Filters', + name: 'filter', + type: 'options', + default: 'my_open', + options: [ + { + name: 'Closed', + value: 'closed', + }, + { + name: 'My Open', + value: 'my_open', + }, + { + name: 'Release Requested', + value: 'release_requested', + }, + { + name: 'Requester ID', + value: 'requester_id', + }, + { + name: 'Unassigned', + value: 'unassigned', + }, + ], + }, + { + displayName: 'Sort Order', + name: 'sort_by', + type: 'options', + options: [ + { + name: 'Ascending', + value: 'asc', + }, + { + name: 'Descending', + value: 'desc', + }, + ], + default: 'asc', + }, + { + displayName: 'Updated Since', + name: 'updated_since', + type: 'dateTime', + default: '', + }, + ], + }, + + // ---------------------------------------- + // change: update + // ---------------------------------------- + { + displayName: 'Change ID', + name: 'changeId', + description: 'ID of the change to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'change', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent to whom the change is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Change Type', + name: 'change_type', + type: 'options', + default: 1, + options: [ + { + name: 'Minor', + value: 1, + }, + { + name: 'Standard', + value: 2, + }, + { + name: 'Major', + value: 3, + }, + { + name: 'Emergency', + value: 4, + }, + ], + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department requesting the change. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the change is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + description: 'Impact of the change', + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Requester Name/ID', + name: 'requester_id', + type: 'options', + default: '', + description: 'ID of the requester of the change. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getRequesters', + ], + }, + }, + { + displayName: 'Risk', + name: 'risk', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Very High', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'Planning', + value: 2, + }, + { + name: 'Approval', + value: 3, + }, + { + name: 'Pending Release', + value: 4, + }, + { + name: 'Pending Review', + value: 5, + }, + { + name: 'Closed', + value: 6, + }, + ], + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/DepartmentDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/DepartmentDescription.ts new file mode 100644 index 0000000000..7efcca4eff --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/DepartmentDescription.ts @@ -0,0 +1,275 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const departmentOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'department', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a department', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a department', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a department', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all departments', + }, + { + name: 'Update', + value: 'update', + description: 'Update a department', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const departmentFields = [ + // ---------------------------------------- + // department: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Domains', + name: 'domains', + type: 'string', + default: '', + description: 'Comma-separated email domains associated with the department', + }, + ], + }, + + // ---------------------------------------- + // department: delete + // ---------------------------------------- + { + displayName: 'Department ID', + name: 'departmentId', + description: 'ID of the department to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // department: get + // ---------------------------------------- + { + displayName: 'Department ID', + name: 'departmentId', + description: 'ID of the department to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // department: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the department', + }, + ], + }, + + // ---------------------------------------- + // department: update + // ---------------------------------------- + { + displayName: 'Department ID', + name: 'departmentId', + description: 'ID of the department to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'department', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Domains', + name: 'domains', + type: 'string', + default: '', + description: 'Comma-separated email domains associated with the department', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/LocationDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/LocationDescription.ts new file mode 100644 index 0000000000..3fdc2d3ac8 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/LocationDescription.ts @@ -0,0 +1,326 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const locationOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'location', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a location', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a location', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a location', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all locations', + }, + { + name: 'Update', + value: 'update', + description: 'Update a location', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const locationFields = [ + // ---------------------------------------- + // location: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + description: 'Name of the location', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'address', + placeholder: 'Add Address Fields', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Address Details', + name: 'addressFields', + values: [ + { + displayName: 'Line 1', + name: 'line1', + type: 'string', + default: '', + }, + { + displayName: 'Line 2', + name: 'line2', + type: 'string', + default: '', + }, + { + displayName: 'City', + name: 'city', + type: 'string', + default: '', + }, + { + displayName: 'Country', + name: 'country', + type: 'string', + default: '', + }, + { + displayName: 'State', + name: 'state', + type: 'string', + default: '', + }, + { + displayName: 'Zip Code', + name: 'zipcode', + type: 'string', + default: '', + }, + ], + }, + ], + }, + ], + }, + + // ---------------------------------------- + // location: delete + // ---------------------------------------- + { + displayName: 'Location ID', + name: 'locationId', + description: 'ID of the location to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // location: get + // ---------------------------------------- + { + displayName: 'Location ID', + name: 'locationId', + description: 'ID of the location to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // location: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // location: update + // ---------------------------------------- + { + displayName: 'Location ID', + name: 'locationId', + description: 'ID of the location to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'location', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Address', + name: 'address', + placeholder: 'Add Address Fields', + type: 'fixedCollection', + default: {}, + options: [ + { + displayName: 'Address Details', + name: 'addressFields', + values: [ + { + displayName: 'Line 1', + name: 'line1', + type: 'string', + default: '', + }, + { + displayName: 'Line 2', + name: 'line2', + type: 'string', + default: '', + }, + { + displayName: 'City', + name: 'city', + type: 'string', + default: '', + }, + { + displayName: 'Country', + name: 'country', + type: 'string', + default: '', + }, + { + displayName: 'State', + name: 'state', + type: 'string', + default: '', + }, + { + displayName: 'Zip Code', + name: 'zipcode', + type: 'string', + default: '', + }, + ], + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/ProblemDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/ProblemDescription.ts new file mode 100644 index 0000000000..742429a3d5 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/ProblemDescription.ts @@ -0,0 +1,496 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const problemOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'problem', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a problem', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a problem', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a problem', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all problems', + }, + { + name: 'Update', + value: 'update', + description: 'Update a problem', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const problemFields = [ + // ---------------------------------------- + // problem: create + // ---------------------------------------- + { + displayName: 'Subject', + name: 'subject', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Requester Name/ID', + name: 'requesterId', + description: 'ID of the initiator of the problem. Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getRequesters', + ], + }, + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Due By', + name: 'dueBy', + description: 'Date when the problem is due to be solved', + type: 'dateTime', + default: '', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent to whom the problem is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department initiating the problem. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + description: 'HTML supported', + type: 'string', + default: '', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the problem is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'Change Requested', + value: 2, + }, + { + name: 'Closed', + value: 3, + }, + ], + }, + ], + }, + + // ---------------------------------------- + // problem: delete + // ---------------------------------------- + { + displayName: 'Problem ID', + name: 'problemId', + description: 'ID of the problem to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // problem: get + // ---------------------------------------- + { + displayName: 'Problem ID', + name: 'problemId', + description: 'ID of the problem to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // problem: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // problem: update + // ---------------------------------------- + { + displayName: 'Problem ID', + name: 'problemId', + description: 'ID of the problem to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'problem', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent to whom the problem is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department initiating the problem. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Due By', + name: 'due_by', + description: 'Date when the problem is due to be solved', + type: 'dateTime', + default: '', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the problem is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Requester Name/ID', + name: 'requester_id', + type: 'options', + default: '', + description: 'ID of the initiator of the problem. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getRequesters', + ], + }, + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'Change Requested', + value: 2, + }, + { + name: 'Closed', + value: 3, + }, + ], + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/ProductDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/ProductDescription.ts new file mode 100644 index 0000000000..df54737060 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/ProductDescription.ts @@ -0,0 +1,364 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const productOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'product', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a product', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a product', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a product', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all products', + }, + { + name: 'Update', + value: 'update', + description: 'Update a product', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const productFields = [ + // ---------------------------------------- + // product: create + // ---------------------------------------- + { + displayName: 'Asset Type Name/ID', + name: 'assetTypeId', + type: 'options', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getAssetTypes', + ], + }, + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Manufacturer', + name: 'manufacturer', + type: 'string', + default: '', + }, + { + displayName: 'Mode of Procurement', + name: 'mode_of_procurement', + type: 'options', + default: 'Buy', + options: [ + { + name: 'Buy', + value: 'Buy', + }, + { + name: 'Lease', + value: 'Lease', + }, + { + name: 'Both', + value: 'Both', + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'In Production', + options: [ + { + name: 'In Production', + value: 'In Production', + }, + { + name: 'In Pipeline', + value: 'In Pipeline', + }, + { + name: 'Retired', + value: 'Retired', + }, + ], + }, + ], + }, + + // ---------------------------------------- + // product: delete + // ---------------------------------------- + { + displayName: 'Product ID', + name: 'productId', + description: 'ID of the product to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // product: get + // ---------------------------------------- + { + displayName: 'Product ID', + name: 'productId', + description: 'ID of the product to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // product: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // product: update + // ---------------------------------------- + { + displayName: 'Product ID', + name: 'productId', + description: 'ID of the product to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'product', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Asset Type Name/ID', + name: 'asset_type_id', + type: 'options', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getAssetTypes', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Manufacturer', + name: 'manufacturer', + type: 'string', + default: '', + }, + { + displayName: 'Mode of Procurement', + name: 'mode_of_procurement', + type: 'options', + default: 'Buy', + options: [ + { + name: 'Buy', + value: 'Buy', + }, + { + name: 'Lease', + value: 'Lease', + }, + { + name: 'Both', + value: 'Both', + }, + ], + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'In Production', + options: [ + { + name: 'In Production', + value: 'In Production', + }, + { + name: 'In Pipeline', + value: 'In Pipeline', + }, + { + name: 'Retired', + value: 'Retired', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/ReleaseDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/ReleaseDescription.ts new file mode 100644 index 0000000000..bc57e0bb48 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/ReleaseDescription.ts @@ -0,0 +1,501 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const releaseOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'release', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a release', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a release', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a release', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all releases', + }, + { + name: 'Update', + value: 'update', + description: 'Update a release', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const releaseFields = [ + // ---------------------------------------- + // release: create + // ---------------------------------------- + { + displayName: 'Subject', + name: 'subject', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Release Type', + name: 'releaseType', + type: 'options', + default: 1, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + name: 'Minor', + value: 1, + }, + { + name: 'Standard', + value: 2, + }, + { + name: 'Major', + value: 3, + }, + { + name: 'Emergency', + value: 4, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'On Hold', + value: 2, + }, + { + name: 'In Progress', + value: 3, + }, + { + name: 'Incomplete', + value: 4, + }, + { + name: 'Completed', + value: 5, + }, + ], + }, + { + displayName: 'Planned Start Date', + name: 'plannedStartDate', + type: 'dateTime', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Planned End Date', + name: 'plannedEndDate', + type: 'dateTime', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department initiating the release. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + description: 'HTML supported', + type: 'string', + default: '', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the release is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + ], + }, + + // ---------------------------------------- + // release: delete + // ---------------------------------------- + { + displayName: 'Release ID', + name: 'releaseId', + description: 'ID of the release to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // release: get + // ---------------------------------------- + { + displayName: 'Release ID', + name: 'releaseId', + description: 'ID of the release to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // release: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // release: update + // ---------------------------------------- + { + displayName: 'Release ID', + name: 'releaseId', + description: 'ID of the release to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'release', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department initiating the release. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the agent group to which the release is assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Release Type', + name: 'release_type', + type: 'options', + default: 1, + options: [ + { + name: 'Minor', + value: 1, + }, + { + name: 'Standard', + value: 2, + }, + { + name: 'Major', + value: 3, + }, + { + name: 'Emergency', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 1, + options: [ + { + name: 'Open', + value: 1, + }, + { + name: 'On Hold', + value: 2, + }, + { + name: 'In Progress', + value: 3, + }, + { + name: 'Incomplete', + value: 4, + }, + { + name: 'Completed', + value: 5, + }, + ], + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/RequesterDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/RequesterDescription.ts new file mode 100644 index 0000000000..a2a348ec5f --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/RequesterDescription.ts @@ -0,0 +1,512 @@ +import { + INodeProperties, +} from 'n8n-workflow'; +import { LANGUAGES } from '../constants'; + +export const requesterOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'requester', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a requester', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a requester', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a requester', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all requesters', + }, + { + name: 'Update', + value: 'update', + description: 'Update a requester', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const requesterFields = [ + // ---------------------------------------- + // requester: create + // ---------------------------------------- + { + displayName: 'First Name', + name: 'firstName', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Primary Email', + name: 'primaryEmail', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'address', + type: 'string', + default: '', + }, + { + displayName: 'Background Information', + name: 'background_information', + type: 'string', + default: '', + }, + { + displayName: 'Department Names/IDs', + name: 'department_ids', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the departments associated with the requester. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location ID', + name: 'location_id', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Mobile Phone', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Secondary Emails', + name: 'secondary_emails', + type: 'string', + default: '', + description: 'Comma-separated secondary emails associated with the requester', + }, + { + displayName: 'Time Format', + name: 'time_format', + type: 'options', + default: '12h', + options: [ + { + name: '12-Hour Format', + value: '12h', + }, + { + name: '24-Hour Format', + value: '24h', + }, + ], + }, + { + displayName: 'Work Phone', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // requester: delete + // ---------------------------------------- + { + displayName: 'Requester ID', + name: 'requesterId', + description: 'ID of the requester to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // requester: get + // ---------------------------------------- + { + displayName: 'Requester ID', + name: 'requesterId', + description: 'ID of the requester to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // requester: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Department Name/ID', + name: 'department_id', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Mobile Phone Number', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Primary Email', + name: 'primary_email', + type: 'string', + default: '', + }, + { + displayName: 'Work Phone Number', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // requester: update + // ---------------------------------------- + { + displayName: 'Requester ID', + name: 'requesterId', + description: 'ID of the requester to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'requester', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Address', + name: 'address', + type: 'string', + default: '', + }, + { + displayName: 'Background Information', + name: 'background_information', + type: 'string', + default: '', + }, + { + displayName: 'Department Names/IDs', + name: 'department_ids', + type: 'multiOptions', + default: [], + description: 'Comma-separated IDs of the departments associated with the requester. Choose from the list or specify an ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'First Name', + name: 'first_name', + type: 'string', + default: '', + }, + { + displayName: 'Job Title', + name: 'job_title', + type: 'string', + default: '', + }, + { + displayName: 'Language', + name: 'language', + type: 'options', + default: '', + options: LANGUAGES, + }, + { + displayName: 'Last Name', + name: 'last_name', + type: 'string', + default: '', + }, + { + displayName: 'Location Name/ID', + name: 'location_id', + type: 'options', + default: '', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getLocations', + ], + }, + }, + { + displayName: 'Mobile Phone', + name: 'mobile_phone_number', + type: 'string', + default: '', + }, + { + displayName: 'Primary Email', + name: 'primary_email', + type: 'string', + default: '', + }, + { + displayName: 'Secondary Emails', + name: 'secondary_emails', + type: 'string', + default: '', + description: 'Comma-separated secondary emails associated with the requester', + }, + { + displayName: 'Time Format', + name: 'time_format', + type: 'options', + default: '12h', + options: [ + { + name: '12-Hour Format', + value: '12h', + }, + { + name: '24-Hour Format', + value: '24h', + }, + ], + }, + { + displayName: 'Work Phone', + name: 'work_phone_number', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/RequesterGroupDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/RequesterGroupDescription.ts new file mode 100644 index 0000000000..1ed51ee6e4 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/RequesterGroupDescription.ts @@ -0,0 +1,237 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const requesterGroupOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a requester group', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a requester group', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a requester group', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all requester groups', + }, + { + name: 'Update', + value: 'update', + description: 'Update a requester group', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const requesterGroupFields = [ + // ---------------------------------------- + // requesterGroup: create + // ---------------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + ], + }, + + // ---------------------------------------- + // requesterGroup: delete + // ---------------------------------------- + { + displayName: 'Requester Group ID', + name: 'requesterGroupId', + description: 'ID of the requester group to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // requesterGroup: get + // ---------------------------------------- + { + displayName: 'Requester Group ID', + name: 'requesterGroupId', + description: 'ID of the requester group to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // requesterGroup: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // requesterGroup: update + // ---------------------------------------- + { + displayName: 'Requester Group ID', + name: 'requesterGroupId', + description: 'ID of the requester group to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'requesterGroup', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'Description of the requester group', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the requester group', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/SoftwareDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/SoftwareDescription.ts new file mode 100644 index 0000000000..d8a7255a5e --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/SoftwareDescription.ts @@ -0,0 +1,347 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const softwareOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'software', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a software application', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a software application', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a software application', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all software applications', + }, + { + name: 'Update', + value: 'update', + description: 'Update a software application', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const softwareFields = [ + // ---------------------------------------- + // software: create + // ---------------------------------------- + { + displayName: 'Application Type', + name: 'applicationType', + type: 'options', + required: true, + options: [ + { + name: 'Desktop', + value: 'desktop', + }, + { + name: 'Mobile', + value: 'mobile', + }, + { + name: 'SaaS', + value: 'saas', + }, + ], + default: 'desktop', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'managed', + options: [ + { + name: 'Disabled', + value: 'disabled', + }, + { + name: 'Ignored', + value: 'ignored', + }, + { + name: 'Needs Review', + value: 'needs review', + }, + { + name: 'Restricted', + value: 'restricted', + }, + ], + }, + ], + }, + + // ---------------------------------------- + // software: delete + // ---------------------------------------- + { + displayName: 'Software ID', + name: 'softwareId', + description: 'ID of the software application to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // software: get + // ---------------------------------------- + { + displayName: 'Software ID', + name: 'softwareId', + description: 'ID of the software application to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // software: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + + // ---------------------------------------- + // software: update + // ---------------------------------------- + { + displayName: 'Software ID', + name: 'softwareId', + description: 'ID of the software application to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'software', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Application Type', + name: 'application_type', + type: 'options', + default: 'desktop', + description: 'Type of the software', + options: [ + { + name: 'Desktop', + value: 'desktop', + }, + { + name: 'Mobile', + value: 'mobile', + }, + { + name: 'SaaS', + value: 'saas', + }, + ], + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 'managed', + options: [ + { + name: 'Disabled', + value: 'disabled', + }, + { + name: 'Ignored', + value: 'ignored', + }, + { + name: 'Needs Review', + value: 'needs review', + }, + { + name: 'Restricted', + value: 'restricted', + }, + ], + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/TicketDescription.ts b/packages/nodes-base/nodes/Freshservice/descriptions/TicketDescription.ts new file mode 100644 index 0000000000..006e355a79 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/TicketDescription.ts @@ -0,0 +1,640 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const ticketOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a ticket', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a ticket', + }, + { + name: 'Get', + value: 'get', + description: 'Retrieve a ticket', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Retrieve all tickets', + }, + { + name: 'Update', + value: 'update', + description: 'Update a ticket', + }, + ], + default: 'create', + }, +] as INodeProperties[]; + +export const ticketFields = [ + // ---------------------------------------- + // ticket: create + // ---------------------------------------- + { + displayName: 'Email', + name: 'email', + description: 'Email address of the ticket author', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 2, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + name: 'Open', + value: 2, + }, + { + name: 'Pending', + value: 3, + }, + { + name: 'Resolved', + value: 4, + }, + { + name: 'Closed', + value: 5, + }, + ], + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'CC Emails', + name: 'cc_emails', + type: 'string', + default: '', + description: 'Comma-separated email addresses to add in the CC field of the ticket email', + }, + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department to which this ticket belongs. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the group to which the ticket has been assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the ticket author', + }, + { + displayName: 'Requester Name/ID', + name: 'requester_id', + type: 'options', + description: 'Choose from the list or specify an ID. You can also specify the ID using an expression.', + default: '', + typeOptions: { + loadOptionsMethod: [ + 'getRequesters', + ], + }, + }, + ], + }, + + // ---------------------------------------- + // ticket: delete + // ---------------------------------------- + { + displayName: 'Ticket ID', + name: 'ticketId', + description: 'ID of the ticket to delete', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'delete', + ], + }, + }, + }, + + // ---------------------------------------- + // ticket: get + // ---------------------------------------- + { + displayName: 'Ticket ID', + name: 'ticketId', + description: 'ID of the ticket to retrieve', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'get', + ], + }, + }, + }, + + // ---------------------------------------- + // ticket: getAll + // ---------------------------------------- + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + default: false, + description: 'Whether to return all results or only up to a given limit', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 50, + description: 'How many results to return', + typeOptions: { + minValue: 1, + }, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Agent Name/ID', + name: 'agent_id', + type: 'options', + default: '', + description: 'ID of the agent to whom the tickets have been assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgents', + ], + }, + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the group to which the tickets have been assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 2, + options: [ + { + name: 'Open', + value: 2, + }, + { + name: 'Pending', + value: 3, + }, + { + name: 'Resolved', + value: 4, + }, + { + name: 'Closed', + value: 5, + }, + ], + }, + { + displayName: 'Created On', + name: 'created_at', + type: 'dateTime', + default: '', + description: 'Date when the ticket was created', + }, + { + displayName: 'Due By', + name: 'due_by', + description: 'Date when the ticket is due to be resolved', + type: 'dateTime', + default: '', + }, + ], + }, + + // ---------------------------------------- + // ticket: update + // ---------------------------------------- + { + displayName: 'Ticket ID', + name: 'ticketId', + description: 'ID of the ticket to update', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Department Name/ID', + name: 'department_id', + type: 'options', + default: '', + description: 'ID of the department to which this ticket has been assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getDepartments', + ], + }, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'HTML supported', + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + description: 'Email address of the ticket author', + }, + { + displayName: 'Group Name/ID', + name: 'group_id', + type: 'options', + default: '', + description: 'ID of the group to which the ticket has been assigned. Choose from the list or specify an ID. You can also specify the ID using an expression.', + typeOptions: { + loadOptionsMethod: [ + 'getAgentGroups', + ], + }, + }, + { + displayName: 'Impact', + name: 'impact', + type: 'options', + default: 1, + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + ], + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Name of the ticket author', + }, + { + displayName: 'Phone', + name: 'phone', + type: 'string', + default: '', + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + default: 1, + description: 'Priority of the ticket', + options: [ + { + name: 'Low', + value: 1, + }, + { + name: 'Medium', + value: 2, + }, + { + name: 'High', + value: 3, + }, + { + name: 'Urgent', + value: 4, + }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + default: 2, + options: [ + { + name: 'Open', + value: 2, + }, + { + name: 'Pending', + value: 3, + }, + { + name: 'Resolved', + value: 4, + }, + { + name: 'Closed', + value: 5, + }, + ], + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Freshservice/descriptions/index.ts b/packages/nodes-base/nodes/Freshservice/descriptions/index.ts new file mode 100644 index 0000000000..cc2f6a8916 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/descriptions/index.ts @@ -0,0 +1,16 @@ +export * from './AgentDescription'; +export * from './AgentGroupDescription'; +export * from './AgentRoleDescription'; +export * from './AnnouncementDescription'; +export * from './AssetDescription'; +export * from './AssetTypeDescription'; +export * from './ChangeDescription'; +export * from './DepartmentDescription'; +export * from './LocationDescription'; +export * from './ProblemDescription'; +export * from './ProductDescription'; +export * from './ReleaseDescription'; +export * from './RequesterDescription'; +export * from './RequesterGroupDescription'; +export * from './SoftwareDescription'; +export * from './TicketDescription'; diff --git a/packages/nodes-base/nodes/Freshservice/freshservice.svg b/packages/nodes-base/nodes/Freshservice/freshservice.svg new file mode 100644 index 0000000000..f806e022d7 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/freshservice.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/packages/nodes-base/nodes/Freshservice/types.d.ts b/packages/nodes-base/nodes/Freshservice/types.d.ts new file mode 100644 index 0000000000..764a62ea27 --- /dev/null +++ b/packages/nodes-base/nodes/Freshservice/types.d.ts @@ -0,0 +1,32 @@ +import { IDataObject } from 'n8n-workflow'; + +export type FreshserviceCredentials = { + apiKey: string; + domain: string; +}; + +export type LoadedResource = { + id: string; + name: string; +}; + +export type LoadedUser = { + active: boolean; + id: string; + first_name: string; + last_name?: string; +}; + +export type RolesParameter = IDataObject & { + roleProperties: Array<{ + role: number; + assignment_scope: 'entire_helpdesk' | 'member_groups' | 'specified_groups' | 'assigned_items'; + groups?: number[]; + }> +}; + +export type AddressFixedCollection = { + address?: { + addressFields: object + } +} diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 68b11df490..18129f8d3f 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -87,6 +87,7 @@ "dist/credentials/FacebookGraphApi.credentials.js", "dist/credentials/FacebookGraphAppApi.credentials.js", "dist/credentials/FreshdeskApi.credentials.js", + "dist/credentials/FreshserviceApi.credentials.js", "dist/credentials/FreshworksCrmApi.credentials.js", "dist/credentials/FileMaker.credentials.js", "dist/credentials/FlowApi.credentials.js", @@ -383,6 +384,7 @@ "dist/nodes/Facebook/FacebookGraphApi.node.js", "dist/nodes/Facebook/FacebookTrigger.node.js", "dist/nodes/FileMaker/FileMaker.node.js", + "dist/nodes/Freshservice/Freshservice.node.js", "dist/nodes/Ftp.node.js", "dist/nodes/Freshdesk/Freshdesk.node.js", "dist/nodes/FreshworksCrm/FreshworksCrm.node.js",