diff --git a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts
index f098f97358..ffe371e160 100644
--- a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts
+++ b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts
@@ -62,6 +62,9 @@ export async function zendeskApiRequestAllItems(this: IHookFunctions | IExecuteF
responseData = await zendeskApiRequest.call(this, method, resource, body, query, uri);
uri = responseData.next_page;
returnData.push.apply(returnData, responseData[propertyName]);
+ if (query.limit && query.limit <= returnData.length) {
+ return returnData;
+ }
} while (
responseData.next_page !== undefined &&
responseData.next_page !== null
@@ -69,3 +72,13 @@ export async function zendeskApiRequestAllItems(this: IHookFunctions | IExecuteF
return returnData;
}
+
+export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
+ let result;
+ try {
+ result = JSON.parse(json!);
+ } catch (exception) {
+ result = undefined;
+ }
+ return result;
+}
diff --git a/packages/nodes-base/nodes/Zendesk/TicketDescription.ts b/packages/nodes-base/nodes/Zendesk/TicketDescription.ts
index 7642248e7e..f5daab6535 100644
--- a/packages/nodes-base/nodes/Zendesk/TicketDescription.ts
+++ b/packages/nodes-base/nodes/Zendesk/TicketDescription.ts
@@ -21,9 +21,9 @@ export const ticketOperations = [
description: 'Create a ticket',
},
{
- name: 'Update',
- value: 'update',
- description: 'Update a ticket',
+ name: 'Delete',
+ value: 'delete',
+ description: 'Delete a ticket',
},
{
name: 'Get',
@@ -36,9 +36,9 @@ export const ticketOperations = [
description: 'Get all tickets',
},
{
- name: 'Delete',
- value: 'delete',
- description: 'Delete a ticket',
+ name: 'Update',
+ value: 'update',
+ description: 'Update a ticket',
},
],
default: 'create',
@@ -81,7 +81,7 @@ export const ticketFields = [
displayOptions: {
show: {
resource: [
- 'ticket'
+ 'ticket',
],
operation: [
'create',
@@ -103,6 +103,9 @@ export const ticketFields = [
operation: [
'create',
],
+ jsonParameters: [
+ false,
+ ],
},
},
options: [
@@ -114,11 +117,14 @@ export const ticketFields = [
description: 'An id you can use to link Zendesk Support tickets to local records',
},
{
- displayName: 'Subject',
- name: 'subject',
- type: 'string',
+ displayName: 'Group',
+ name: 'group',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getGroups',
+ },
default: '',
- description: 'The value of the subject field for this ticket',
+ description: 'The group this ticket is assigned to',
},
{
displayName: 'Recipient',
@@ -128,14 +134,40 @@ export const ticketFields = [
description: 'The original recipient e-mail address of the ticket',
},
{
- displayName: 'Group',
- name: 'group',
+ displayName: 'Status',
+ name: 'status',
type: 'options',
- typeOptions: {
- loadOptionsMethod: 'getGroups',
- },
+ options: [
+ {
+ name: 'Open',
+ value: 'open',
+ },
+ {
+ name: 'New',
+ value: 'new',
+ },
+ {
+ name: 'Pending',
+ value: 'pending',
+ },
+ {
+ name: 'Solved',
+ value: 'solved',
+ },
+ {
+ name: 'Closed',
+ value: 'closed',
+ },
+ ],
default: '',
- description: 'The group this ticket is assigned to',
+ description: 'The state of the ticket',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'string',
+ default: '',
+ description: 'The value of the subject field for this ticket',
},
{
displayName: 'Tags',
@@ -172,37 +204,78 @@ export const ticketFields = [
default: '',
description: 'The type of this ticket',
},
+ ],
+ },
+ {
+ displayName: 'Custom Fields',
+ name: 'customFieldsUi',
+ placeholder: 'Add Custom Field',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticket',
+ ],
+ operation: [
+ 'create',
+ ],
+ jsonParameters: [
+ false,
+ ],
+ },
+ },
+ default: {},
+ options: [
{
- displayName: 'Status',
- name: 'status',
- type: 'options',
- options: [
+ displayName: 'Custom Field',
+ name: 'customFieldsValues',
+ values: [
{
- name: 'Open',
- value: 'open',
+ displayName: 'ID',
+ name: 'id',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCustomFields',
+ },
+ default: '',
+ description: 'Custom field ID',
},
{
- name: 'New',
- value: 'new',
- },
- {
- name: 'Pending',
- value: 'pending',
- },
- {
- name: 'Solved',
- value: 'solved',
- },
- {
- name: 'Closed',
- value: 'closed',
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Custom field Value.',
},
],
- default: '',
- description: 'The state of the ticket',
- }
+ },
],
},
+ {
+ displayName: ' Additional Fields',
+ name: 'additionalFieldsJson',
+ type: 'json',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticket',
+ ],
+ operation: [
+ 'create',
+ ],
+ jsonParameters: [
+ true,
+ ],
+ },
+ },
+ },
{
displayName: ' Custom Fields',
name: 'customFieldsJson',
@@ -224,14 +297,13 @@ export const ticketFields = [
],
},
},
- required: true,
description: `Array of customs fields Details`,
},
/* -------------------------------------------------------------------------- */
/* ticket:update */
/* -------------------------------------------------------------------------- */
{
- displayName: 'ID',
+ displayName: 'Ticket ID',
name: 'id',
type: 'string',
default: '',
@@ -279,6 +351,9 @@ export const ticketFields = [
operation: [
'update',
],
+ jsonParameters: [
+ false,
+ ],
},
},
options: [
@@ -290,11 +365,14 @@ export const ticketFields = [
description: 'An id you can use to link Zendesk Support tickets to local records',
},
{
- displayName: 'Subject',
- name: 'subject',
- type: 'string',
+ displayName: 'Group',
+ name: 'group',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getGroups',
+ },
default: '',
- description: 'The value of the subject field for this ticket',
+ description: 'The group this ticket is assigned to',
},
{
displayName: 'Recipient',
@@ -304,14 +382,40 @@ export const ticketFields = [
description: 'The original recipient e-mail address of the ticket',
},
{
- displayName: 'Group',
- name: 'group',
+ displayName: 'Status',
+ name: 'status',
type: 'options',
- typeOptions: {
- loadOptionsMethod: 'getGroups',
- },
+ options: [
+ {
+ name: 'Open',
+ value: 'open',
+ },
+ {
+ name: 'New',
+ value: 'new',
+ },
+ {
+ name: 'Pending',
+ value: 'pending',
+ },
+ {
+ name: 'Solved',
+ value: 'solved',
+ },
+ {
+ name: 'Closed',
+ value: 'closed',
+ },
+ ],
default: '',
- description: 'The group this ticket is assigned to',
+ description: 'The state of the ticket',
+ },
+ {
+ displayName: 'Subject',
+ name: 'subject',
+ type: 'string',
+ default: '',
+ description: 'The value of the subject field for this ticket',
},
{
displayName: 'Tags',
@@ -348,37 +452,78 @@ export const ticketFields = [
default: '',
description: 'The type of this ticket',
},
+ ],
+ },
+ {
+ displayName: 'Custom Fields',
+ name: 'customFieldsUi',
+ placeholder: 'Add Custom Field',
+ type: 'fixedCollection',
+ typeOptions: {
+ multipleValues: true,
+ },
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticket',
+ ],
+ operation: [
+ 'update',
+ ],
+ jsonParameters: [
+ false,
+ ],
+ },
+ },
+ default: {},
+ options: [
{
- displayName: 'Status',
- name: 'status',
- type: 'options',
- options: [
+ displayName: 'Custom Field',
+ name: 'customFieldsValues',
+ values: [
{
- name: 'Open',
- value: 'open',
+ displayName: 'ID',
+ name: 'id',
+ type: 'options',
+ typeOptions: {
+ loadOptionsMethod: 'getCustomFields',
+ },
+ default: '',
+ description: 'Custom field ID',
},
{
- name: 'New',
- value: 'new',
- },
- {
- name: 'Pending',
- value: 'pending',
- },
- {
- name: 'Solved',
- value: 'solved',
- },
- {
- name: 'Closed',
- value: 'closed',
+ displayName: 'Value',
+ name: 'value',
+ type: 'string',
+ default: '',
+ description: 'Custom field Value.',
},
],
- default: '',
- description: 'The state of the ticket',
- }
+ },
],
},
+ {
+ displayName: ' Update Fields',
+ name: 'updateFieldsJson',
+ type: 'json',
+ typeOptions: {
+ alwaysOpenEditWindow: true,
+ },
+ default: '',
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticket',
+ ],
+ operation: [
+ 'update',
+ ],
+ jsonParameters: [
+ true,
+ ],
+ },
+ },
+ },
{
displayName: ' Custom Fields',
name: 'customFieldsJson',
@@ -407,7 +552,7 @@ export const ticketFields = [
/* ticket:get */
/* -------------------------------------------------------------------------- */
{
- displayName: 'ID',
+ displayName: 'Ticket ID',
name: 'id',
type: 'string',
default: '',
@@ -485,35 +630,6 @@ export const ticketFields = [
},
},
options: [
- {
- displayName: 'Status',
- name: 'status',
- type: 'options',
- options: [
- {
- name: 'Open',
- value: 'open',
- },
- {
- name: 'New',
- value: 'new',
- },
- {
- name: 'Pending',
- value: 'pending',
- },
- {
- name: 'Solved',
- value: 'solved',
- },
- {
- name: 'Closed',
- value: 'closed',
- },
- ],
- default: '',
- description: 'The state of the ticket',
- },
{
displayName: 'Sort By',
name: 'sortBy',
@@ -559,7 +675,36 @@ export const ticketFields = [
],
default: 'desc',
description: 'Sort order',
- }
+ },
+ {
+ displayName: 'Status',
+ name: 'status',
+ type: 'options',
+ options: [
+ {
+ name: 'Open',
+ value: 'open',
+ },
+ {
+ name: 'New',
+ value: 'new',
+ },
+ {
+ name: 'Pending',
+ value: 'pending',
+ },
+ {
+ name: 'Solved',
+ value: 'solved',
+ },
+ {
+ name: 'Closed',
+ value: 'closed',
+ },
+ ],
+ default: '',
+ description: 'The state of the ticket',
+ },
],
},
@@ -567,7 +712,7 @@ export const ticketFields = [
/* ticket:delete */
/* -------------------------------------------------------------------------- */
{
- displayName: 'ID',
+ displayName: 'Ticket ID',
name: 'id',
type: 'string',
default: '',
diff --git a/packages/nodes-base/nodes/Zendesk/TicketFieldDescription.ts b/packages/nodes-base/nodes/Zendesk/TicketFieldDescription.ts
index 8e061db402..9ba754eef4 100644
--- a/packages/nodes-base/nodes/Zendesk/TicketFieldDescription.ts
+++ b/packages/nodes-base/nodes/Zendesk/TicketFieldDescription.ts
@@ -54,4 +54,49 @@ export const ticketFieldFields = [
},
description: 'ticketField ID',
},
+
+/* -------------------------------------------------------------------------- */
+/* ticketField:getAll */
+/* -------------------------------------------------------------------------- */
+ {
+ displayName: 'Return All',
+ name: 'returnAll',
+ type: 'boolean',
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticketField',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ },
+ },
+ default: false,
+ description: 'If all results should be returned or only up to a given limit.',
+ },
+ {
+ displayName: 'Limit',
+ name: 'limit',
+ type: 'number',
+ displayOptions: {
+ show: {
+ resource: [
+ 'ticketField',
+ ],
+ operation: [
+ 'getAll',
+ ],
+ returnAll: [
+ false,
+ ],
+ },
+ },
+ typeOptions: {
+ minValue: 1,
+ maxValue: 100,
+ },
+ default: 100,
+ description: 'How many results to return.',
+ },
] as INodeProperties[];
diff --git a/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts b/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts
index b66481bcc1..a64feb9ca5 100644
--- a/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts
+++ b/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts
@@ -12,6 +12,7 @@ import {
} from 'n8n-workflow';
import {
+ validateJSON,
zendeskApiRequest,
zendeskApiRequestAllItems,
} from './GenericFunctions';
@@ -30,6 +31,7 @@ import {
ITicket,
IComment,
} from './TicketInterface';
+import { response } from 'express';
export class Zendesk implements INodeType {
description: INodeTypeDescription = {
@@ -83,6 +85,33 @@ export class Zendesk implements INodeType {
methods = {
loadOptions: {
+ // Get all the custom fields to display them to user so that he can
+ // select them easily
+ async getCustomFields(this: ILoadOptionsFunctions): Promise {
+ const returnData: INodePropertyOptions[] = [];
+ const customFields = [
+ 'text',
+ 'textarea',
+ 'date',
+ 'integer',
+ 'decimal',
+ 'regexp',
+ 'multiselect',
+ 'tagger',
+ ];
+ const fields = await zendeskApiRequestAllItems.call(this, 'ticket_fields', 'GET', '/ticket_fields');
+ for (const field of fields) {
+ if (customFields.includes(field.type)) {
+ const fieldName = field.title;
+ const fieldId = field.id;
+ returnData.push({
+ name: fieldName,
+ value: fieldId,
+ });
+ }
+ }
+ return returnData;
+ },
// Get all the groups to display them to user so that he can
// select them easily
async getGroups(this: ILoadOptionsFunctions): Promise {
@@ -131,42 +160,71 @@ export class Zendesk implements INodeType {
if (operation === 'create') {
const description = this.getNodeParameter('description', i) as string;
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
- const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const comment: IComment = {
body: description,
};
const body: ITicket = {
comment,
};
- if (additionalFields.type) {
- body.type = additionalFields.type as string;
- }
- if (additionalFields.externalId) {
- body.external_id = additionalFields.externalId as string;
- }
- if (additionalFields.subject) {
- body.subject = additionalFields.subject as string;
- }
- if (additionalFields.status) {
- body.status = additionalFields.status as string;
- }
- if (additionalFields.recipient) {
- body.recipient = additionalFields.recipient as string;
- }
- if (additionalFields.group) {
- body.group = additionalFields.group as string;
- }
- if (additionalFields.tags) {
- body.tags = additionalFields.tags as string[];
- }
if (jsonParameters) {
+
const customFieldsJson = this.getNodeParameter('customFieldsJson', i) as string;
- try {
- JSON.parse(customFieldsJson);
- } catch(err) {
- throw new Error('Custom fields must be a valid JSON');
+
+ if (customFieldsJson !== '' ) {
+
+ if (validateJSON(customFieldsJson) !== undefined) {
+
+ body.custom_fields = JSON.parse(customFieldsJson);
+
+ } else {
+ throw new Error('Custom fields must be a valid JSON');
+ }
+ }
+
+ const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string;
+
+ if (additionalFieldsJson !== '' ) {
+
+ if (validateJSON(additionalFieldsJson) !== undefined) {
+
+ Object.assign(body, JSON.parse(additionalFieldsJson));
+
+ } else {
+ throw new Error('Additional fields must be a valid JSON');
+ }
+ }
+
+
+ } else {
+
+ const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
+
+ const customFields = (this.getNodeParameter('customFieldsUi', i) as IDataObject).customFieldsValues as IDataObject[];
+
+ if (additionalFields.type) {
+ body.type = additionalFields.type as string;
+ }
+ if (additionalFields.externalId) {
+ body.external_id = additionalFields.externalId as string;
+ }
+ if (additionalFields.subject) {
+ body.subject = additionalFields.subject as string;
+ }
+ if (additionalFields.status) {
+ body.status = additionalFields.status as string;
+ }
+ if (additionalFields.recipient) {
+ body.recipient = additionalFields.recipient as string;
+ }
+ if (additionalFields.group) {
+ body.group = additionalFields.group as string;
+ }
+ if (additionalFields.tags) {
+ body.tags = additionalFields.tags as string[];
+ }
+ if (customFields) {
+ body.custom_fields = customFields;
}
- body.custom_fields = JSON.parse(customFieldsJson);
}
responseData = await zendeskApiRequest.call(this, 'POST', '/tickets', { ticket: body });
responseData = responseData.ticket;
@@ -175,37 +233,66 @@ export class Zendesk implements INodeType {
if (operation === 'update') {
const ticketId = this.getNodeParameter('id', i) as string;
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
- const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
const body: ITicket = {};
- if (updateFields.type) {
- body.type = updateFields.type as string;
- }
- if (updateFields.externalId) {
- body.external_id = updateFields.externalId as string;
- }
- if (updateFields.subject) {
- body.subject = updateFields.subject as string;
- }
- if (updateFields.status) {
- body.status = updateFields.status as string;
- }
- if (updateFields.recipient) {
- body.recipient = updateFields.recipient as string;
- }
- if (updateFields.group) {
- body.group = updateFields.group as string;
- }
- if (updateFields.tags) {
- body.tags = updateFields.tags as string[];
- }
+
if (jsonParameters) {
+
const customFieldsJson = this.getNodeParameter('customFieldsJson', i) as string;
- try {
- JSON.parse(customFieldsJson);
- } catch(err) {
- throw new Error('Custom fields must be a valid JSON');
+
+ if (customFieldsJson !== '' ) {
+
+ if (validateJSON(customFieldsJson) !== undefined) {
+
+ body.custom_fields = JSON.parse(customFieldsJson);
+
+ } else {
+ throw new Error('Custom fields must be a valid JSON');
+ }
+ }
+
+ const updateFieldsJson = this.getNodeParameter('updateFieldsJson', i) as string;
+
+ if (updateFieldsJson !== '' ) {
+
+ if (validateJSON(updateFieldsJson) !== undefined) {
+
+ Object.assign(body, JSON.parse(updateFieldsJson));
+
+ } else {
+ throw new Error('Additional fields must be a valid JSON');
+ }
+ }
+
+ } else {
+
+ const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
+
+ const customFields = (this.getNodeParameter('customFieldsUi', i) as IDataObject).customFieldsValues as IDataObject[];
+
+ if (updateFields.type) {
+ body.type = updateFields.type as string;
+ }
+ if (updateFields.externalId) {
+ body.external_id = updateFields.externalId as string;
+ }
+ if (updateFields.subject) {
+ body.subject = updateFields.subject as string;
+ }
+ if (updateFields.status) {
+ body.status = updateFields.status as string;
+ }
+ if (updateFields.recipient) {
+ body.recipient = updateFields.recipient as string;
+ }
+ if (updateFields.group) {
+ body.group = updateFields.group as string;
+ }
+ if (updateFields.tags) {
+ body.tags = updateFields.tags as string[];
+ }
+ if (customFields) {
+ body.custom_fields = customFields;
}
- body.custom_fields = JSON.parse(customFieldsJson);
}
responseData = await zendeskApiRequest.call(this, 'PUT', `/tickets/${ticketId}`, { ticket: body });
responseData = responseData.ticket;
@@ -259,8 +346,15 @@ export class Zendesk implements INodeType {
}
//https://developer.zendesk.com/rest_api/docs/support/ticket_fields#list-ticket-fields
if (operation === 'getAll') {
- responseData = await zendeskApiRequest.call(this, 'GET', '/ticket_fields', {}, qs);
- responseData = responseData.ticket_fields;
+ const returnAll = this.getNodeParameter('returnAll', i) as boolean;
+ if (returnAll) {
+ responseData = await zendeskApiRequestAllItems.call(this, 'ticket_fields', 'GET', '/ticket_fields', {}, qs);
+ } else {
+ const limit = this.getNodeParameter('limit', i) as number;
+ qs.limit = limit;
+ responseData = await zendeskApiRequestAllItems.call(this, 'ticket_fields', 'GET', '/ticket_fields', {}, qs);
+ responseData = responseData.slice(0, limit);
+ }
}
}
if (Array.isArray(responseData)) {