From 1cc58171dd0d305e4f68d990f10d3c05167e4593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Sun, 5 Sep 2021 15:13:25 +0200 Subject: [PATCH] :sparkles: Add Organization resource to Zendesk node (#2152) * Added Organization options. Create, Update, Get, GetAll, Delete, Count and Related * Fixed Zendesk Node user alias typo * Updated Zendesk documentation links for future maintainers * Added Related for Users in Zendesk Node * Added fetching organizations for users * :hammer: Refactor Zendesk expansion * :zap: Improvements Co-authored-by: Jonathan Co-authored-by: ricardo --- .../nodes/Zendesk/GenericFunctions.ts | 2 - .../nodes/Zendesk/OrganizationDescription.ts | 378 ++++++++++++++++++ .../nodes/Zendesk/UserDescription.ts | 73 +++- .../nodes-base/nodes/Zendesk/Zendesk.node.ts | 161 +++++++- .../nodes/Zendesk/ZendeskTrigger.node.ts | 2 +- packages/nodes-base/nodes/Zendesk/zendesk.png | Bin 930 -> 0 bytes packages/nodes-base/nodes/Zendesk/zendesk.svg | 4 + 7 files changed, 597 insertions(+), 23 deletions(-) create mode 100644 packages/nodes-base/nodes/Zendesk/OrganizationDescription.ts delete mode 100644 packages/nodes-base/nodes/Zendesk/zendesk.png create mode 100644 packages/nodes-base/nodes/Zendesk/zendesk.svg diff --git a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts index b03f1c6ebd..f3320f5184 100644 --- a/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Zendesk/GenericFunctions.ts @@ -33,7 +33,6 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions if (Object.keys(options.body).length === 0) { delete options.body; } - try { if (authenticationMethod === 'apiToken') { const credentials = await this.getCredentials('zendeskApi'); @@ -45,7 +44,6 @@ export async function zendeskApiRequest(this: IHookFunctions | IExecuteFunctions const base64Key = Buffer.from(`${credentials.email}/token:${credentials.apiToken}`).toString('base64'); options.uri = `https://${credentials.subdomain}.zendesk.com/api/v2${resource}.json`; options.headers!['Authorization'] = `Basic ${base64Key}`; - return await this.helpers.request!(options); } else { const credentials = await this.getCredentials('zendeskOAuth2Api'); diff --git a/packages/nodes-base/nodes/Zendesk/OrganizationDescription.ts b/packages/nodes-base/nodes/Zendesk/OrganizationDescription.ts new file mode 100644 index 0000000000..023ff678a9 --- /dev/null +++ b/packages/nodes-base/nodes/Zendesk/OrganizationDescription.ts @@ -0,0 +1,378 @@ +import { + INodeProperties, + } from 'n8n-workflow'; + +export const organizationOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'organization', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an organization', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an organization', + }, + { + name: 'Count', + value: 'count', + description: 'Count organizations', + }, + { + name: 'Get', + value: 'get', + description: 'Get an organization', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all organizations', + }, + { + name: 'Get Related Data', + value: 'getRelatedData', + description: 'Get data related to the organization', + }, + { + name: 'Update', + value: 'update', + description: 'Update a organization', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const organizationFields = [ + +/* -------------------------------------------------------------------------- */ +/* organization:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'create', + ], + }, + }, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'create', + ], + }, + }, + options: [ + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Details obout the organization, such as the address', + }, + { + displayName: 'Domain Names', + name: 'domain_names', + type: 'string', + default: '', + description: 'Comma-separated domain names associated with this organization', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + }, + { + displayName: 'Organization Fields', + name: 'organizationFieldsUi', + placeholder: 'Add Organization Field', + description: 'Values of custom fields in the organization\'s profile', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'organizationFieldValues', + displayName: 'Field', + values: [ + { + displayName: 'Field', + name: 'field', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationFields', + }, + default: '', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + }, + ], + }, + ], + }, + { + displayName: 'Tags', + name: 'tags', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getTags', + }, + default: [], + description: 'IDs of tags applied to this organization', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* organization:update */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Organization ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'update', + ], + }, + }, + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'update', + ], + }, + }, + options: [ + { + displayName: 'Details', + name: 'details', + type: 'string', + default: '', + description: 'Details obout the organization, such as the address', + }, + { + displayName: 'Domain Names', + name: 'domain_names', + type: 'string', + default: '', + description: 'Comma-separated domain names associated with this organization', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + }, + { + displayName: 'Notes', + name: 'notes', + type: 'string', + default: '', + }, + { + displayName: 'Organization Fields', + name: 'organizationFieldsUi', + placeholder: 'Add Organization Field', + description: 'Values of custom fields in the organization\'s profile', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'organizationFieldValues', + displayName: 'Field', + values: [ + { + displayName: 'Field', + name: 'field', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getOrganizationFields', + }, + default: '', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + }, + ], + }, + ], + }, + { + displayName: 'Tags', + name: 'tags', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getTags', + }, + default: [], + description: 'IDs of tags applied to this organization', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* organization:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Organization ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'get', + ], + }, + }, + description: 'Organization ID', + }, +/* -------------------------------------------------------------------------- */ +/* organization:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'organization', + ], + 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: [ + 'organization', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 100, + description: 'How many results to return', + }, +/* -------------------------------------------------------------------------- */ +/* organization:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Organization ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'delete', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* organization:getRelatedData */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Organization ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'organization', + ], + operation: [ + 'getRelatedData', + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Zendesk/UserDescription.ts b/packages/nodes-base/nodes/Zendesk/UserDescription.ts index 6e606a5c22..eb7a1c706f 100644 --- a/packages/nodes-base/nodes/Zendesk/UserDescription.ts +++ b/packages/nodes-base/nodes/Zendesk/UserDescription.ts @@ -35,6 +35,16 @@ export const userOperations = [ value: 'getAll', description: 'Get all users', }, + { + name: 'Get Organizations', + value: 'getOrganizations', + description: 'Get a user\'s organizations', + }, + { + name: 'Get Related Data', + value: 'getRelatedData', + description: 'Get data related to the user', + }, { name: 'Search', value: 'search', @@ -47,7 +57,6 @@ export const userOperations = [ }, ], default: 'create', - description: 'The operation to perform.', }, ] as INodeProperties[]; @@ -93,7 +102,7 @@ export const userFields = [ options: [ { displayName: 'Alias', - name: 'alis', + name: 'alias', type: 'string', default: '', description: `An alias displayed to end users`, @@ -159,9 +168,12 @@ export const userFields = [ }, { displayName: 'Organization ID', - name: 'organizationId', - type: 'number', - default: 0, + name: 'organization_id', + typeOptions: { + loadOptionsMethod: 'getOrganizations', + }, + type: 'options', + default: '', description: `The id of the user's organization. If the user has more than one organization memberships, the id of the user's default organization`, }, { @@ -347,7 +359,7 @@ export const userFields = [ options: [ { displayName: 'Alias', - name: 'alis', + name: 'alias', type: 'string', default: '', description: `An alias displayed to end users`, @@ -420,9 +432,12 @@ export const userFields = [ }, { displayName: 'Organization ID', - name: 'organizationId', - type: 'number', - default: 0, + name: 'organization_id', + typeOptions: { + loadOptionsMethod: 'getOrganizations', + }, + type: 'options', + default: '', description: `The id of the user's organization. If the user has more than one organization memberships, the id of the user's default organization`, }, { @@ -768,4 +783,44 @@ export const userFields = [ }, description: 'User ID', }, +/* -------------------------------------------------------------------------- */ +/* user:getRelatedData */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'User ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'user', + ], + operation: [ + 'getRelatedData', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* user:getOrganizations */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'User ID', + name: 'id', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'user', + ], + operation: [ + 'getOrganizations', + ], + }, + }, + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts b/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts index 8340876bf3..b2af1df0bd 100644 --- a/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts +++ b/packages/nodes-base/nodes/Zendesk/Zendesk.node.ts @@ -34,6 +34,11 @@ import { userOperations } from './UserDescription'; +import { + organizationFields, + organizationOperations +} from './OrganizationDescription'; + import { IComment, ITicket, @@ -43,7 +48,7 @@ export class Zendesk implements INodeType { description: INodeTypeDescription = { displayName: 'Zendesk', name: 'zendesk', - icon: 'file:zendesk.png', + icon: 'file:zendesk.svg', group: ['output'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', @@ -116,6 +121,11 @@ export class Zendesk implements INodeType { value: 'user', description: 'Manage users', }, + { + name: 'Organization', + value: 'organization', + description: 'Manage organizations', + }, ], default: 'ticket', description: 'Resource to consume.', @@ -129,6 +139,9 @@ export class Zendesk implements INodeType { // USER ...userOperations, ...userFields, + // ORGANIZATION + ...organizationOperations, + ...organizationFields, ], }; @@ -223,6 +236,33 @@ export class Zendesk implements INodeType { } return returnData; }, + + // Get all the organization fields to display them to the user for easy selection + async getOrganizationFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const fields = await zendeskApiRequestAllItems.call(this, 'organization_fields', 'GET', '/organization_fields'); + for (const field of fields) { + const fieldName = field.title; + const fieldId = field.key; + returnData.push({ + name: fieldName, + value: fieldId, + }); + } + return returnData; + }, + + async getOrganizations(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const fields = await zendeskApiRequestAllItems.call(this, 'organizations', 'GET', `/organizations`, {}, {}); + for (const field of fields) { + returnData.push({ + name: field.name, + value: field.id, + }); + } + return returnData; + }, }, }; @@ -236,7 +276,7 @@ export class Zendesk implements INodeType { try { const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; - //https://developer.zendesk.com/rest_api/docs/support/introduction + //https://developer.zendesk.com/api-reference/ticketing/introduction/ if (resource === 'ticket') { //https://developer.zendesk.com/rest_api/docs/support/tickets if (operation === 'create') { @@ -385,7 +425,7 @@ export class Zendesk implements INodeType { } } } - //https://developer.zendesk.com/rest_api/docs/support/ticket_fields + //https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_fields/ if (resource === 'ticketField') { //https://developer.zendesk.com/rest_api/docs/support/tickets#show-ticket if (operation === 'get') { @@ -406,9 +446,9 @@ export class Zendesk implements INodeType { } } } - //https://developer.zendesk.com/rest_api/docs/support/users + //https://developer.zendesk.com/api-reference/ticketing/users/users/ if (resource === 'user') { - //https://developer.zendesk.com/rest_api/docs/support/users#create-user + //https://developer.zendesk.com/api-reference/ticketing/users/users/#create-user if (operation === 'create') { const name = this.getNodeParameter('name', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -430,11 +470,10 @@ export class Zendesk implements INodeType { delete body.userFieldsUi; } } - responseData = await zendeskApiRequest.call(this, 'POST', '/users', { user: body }); responseData = responseData.user; } - //https://developer.zendesk.com/rest_api/docs/support/tickets#update-ticket + //https://developer.zendesk.com/api-reference/ticketing/users/users/#update-user if (operation === 'update') { const userId = this.getNodeParameter('id', i) as string; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; @@ -458,13 +497,13 @@ export class Zendesk implements INodeType { responseData = await zendeskApiRequest.call(this, 'PUT', `/users/${userId}`, { user: body }); responseData = responseData.user; } - //https://developer.zendesk.com/rest_api/docs/support/users#show-user + //https://developer.zendesk.com/api-reference/ticketing/users/users/#show-user if (operation === 'get') { const userId = this.getNodeParameter('id', i) as string; responseData = await zendeskApiRequest.call(this, 'GET', `/users/${userId}`, {}); responseData = responseData.user; } - //https://developer.zendesk.com/rest_api/docs/support/users#list-users + //https://developer.zendesk.com/api-reference/ticketing/users/users/#list-users if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; const options = this.getNodeParameter('filters', i) as IDataObject; @@ -480,7 +519,13 @@ export class Zendesk implements INodeType { responseData = responseData.users; } } - //https://developer.zendesk.com/rest_api/docs/support/users#search-users + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#list-organizations + if (operation === 'getOrganizations') { + const userId = this.getNodeParameter('id', i) as string; + responseData = await zendeskApiRequest.call(this, 'GET', `/users/${userId}/organizations`, {}); + responseData = responseData.organizations; + } + //https://developer.zendesk.com/api-reference/ticketing/users/users/#search-users if (operation === 'search') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; const options = this.getNodeParameter('filters', i) as IDataObject; @@ -496,12 +541,106 @@ export class Zendesk implements INodeType { responseData = responseData.users; } } - //https://developer.zendesk.com/rest_api/docs/support/users#delete-user + //https://developer.zendesk.com/api-reference/ticketing/users/users/#delete-user if (operation === 'delete') { const userId = this.getNodeParameter('id', i) as string; responseData = await zendeskApiRequest.call(this, 'DELETE', `/users/${userId}`, {}); responseData = responseData.user; } + //https://developer.zendesk.com/api-reference/ticketing/users/users/#show-user-related-information + if (operation === 'getRelatedData') { + const userId = this.getNodeParameter('id', i) as string; + responseData = await zendeskApiRequest.call(this, 'GET', `/users/${userId}/related`, {}); + responseData = responseData.user_related; + } + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/ + if (resource === 'organization') { + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#create-organization + if (operation === 'create') { + const name = this.getNodeParameter('name', i) as string; + + const body: IDataObject & { name: string; organization_fields?: { [key: string]: object | string } } = { + name, + }; + + const { organizationFieldsUi, ...rest } = this.getNodeParameter('additionalFields', i) as IDataObject & { organizationFieldsUi?: { organizationFieldValues: Array<{ field: string; value: string; }> } }; + + Object.assign(body, rest); + + if (organizationFieldsUi?.organizationFieldValues.length) { + const organizationFields = organizationFieldsUi.organizationFieldValues; + if (organizationFields.length) { + body.organization_fields = {}; + for (const organizationField of organizationFields) { + body.organization_fields[organizationField.field] = organizationField.value; + } + } + } + + responseData = await zendeskApiRequest.call(this, 'POST', '/organizations', { organization: body }); + responseData = responseData.organization; + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#delete-organization + if (operation === 'delete') { + const organizationId = this.getNodeParameter('id', i) as string; + await zendeskApiRequest.call(this, 'DELETE', `/organizations/${organizationId}`, {}); + responseData = { success: true }; + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#count-organizations + if (operation === 'count') { + responseData = await zendeskApiRequest.call(this, 'GET', `/organizations/count`, {}); + responseData = responseData.count; + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#show-organization + if (operation === 'get') { + const organizationId = this.getNodeParameter('id', i) as string; + responseData = await zendeskApiRequest.call(this, 'GET', `/organizations/${organizationId}`, {}); + responseData = responseData.organization; + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#list-organizations + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + if (returnAll) { + responseData = await zendeskApiRequestAllItems.call(this, 'organizations', 'GET', `/organizations`, {}, qs); + } else { + const limit = this.getNodeParameter('limit', i) as number; + qs.per_page = limit; + responseData = await zendeskApiRequest.call(this, 'GET', `/organizations`, {}, qs); + responseData = responseData.organizations; + } + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#show-organizations-related-information + if (operation === 'getRelatedData') { + const organizationId = this.getNodeParameter('id', i) as string; + responseData = await zendeskApiRequest.call(this, 'GET', `/organizations/${organizationId}/related`, {}); + responseData = responseData.organization_related; + } + //https://developer.zendesk.com/api-reference/ticketing/organizations/organizations/#update-organization + if (operation === 'update') { + const organizationId = this.getNodeParameter('id', i) as string; + + const body: IDataObject & { organization_fields?: { [key: string]: object | string } } = {}; + + const { organizationFieldsUi, ...rest } = this.getNodeParameter('updateFields', i) as IDataObject & { organizationFieldsUi?: { organizationFieldValues: Array<{ field: string; value: string; }> } }; + + Object.assign(body, rest); + + if (organizationFieldsUi?.organizationFieldValues.length) { + const organizationFields = organizationFieldsUi.organizationFieldValues; + if (organizationFields.length) { + body.organization_fields = {}; + for (const organizationField of organizationFields) { + body.organization_fields[organizationField.field] = organizationField.value; + } + } + } + + responseData = await zendeskApiRequest.call(this, 'PUT', `/organizations/${organizationId}`, { organization: body }); + responseData = responseData.organization; + } + } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); diff --git a/packages/nodes-base/nodes/Zendesk/ZendeskTrigger.node.ts b/packages/nodes-base/nodes/Zendesk/ZendeskTrigger.node.ts index dc8c256207..93bcf9da35 100644 --- a/packages/nodes-base/nodes/Zendesk/ZendeskTrigger.node.ts +++ b/packages/nodes-base/nodes/Zendesk/ZendeskTrigger.node.ts @@ -33,7 +33,7 @@ export class ZendeskTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Zendesk Trigger', name: 'zendeskTrigger', - icon: 'file:zendesk.png', + icon: 'file:zendesk.svg', group: ['trigger'], version: 1, description: 'Handle Zendesk events via webhooks', diff --git a/packages/nodes-base/nodes/Zendesk/zendesk.png b/packages/nodes-base/nodes/Zendesk/zendesk.png deleted file mode 100644 index c48208c7746c27920123104a69f708751fada33e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 930 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2Jl0X`wFK$^kIirLH-h#1Umn9V^9 zFtTH?vSqLUNii6~1wjlJGh0?5X=(#xFq_!{Ng!eXB5P}AGaDwTc3Wmspg2&C4N#E5 z!X8M17^ap$D}d_R%x&0!T#y!97Aq%ab9-h>$KAQ6zku%1E(!7rW?=dGn|=Pm+iwMg zzH@!PKlRm7<7*whXC38um*+g)wz0M}S~)R9YBLG=IXxwE1xebEtRy?`sT~?Z#j)6pS{?eqP|JF?#q3Tx~2PP zO#D+9wNb9uJ$c>5vOIVH?zqhsGSU`8`+0?m1fN~&``YaJ-CA*NPSo$&em;wK9C#zW z`N{!Z1Mb(BZ#`eiJ-jnb)L!zPhE3Gz>whot&z{;olhb0G=>2e=*V1=&)?Pm_r?f9z zrA{$Jt|(W@f@fLH*EQj@f`wXADmJjS>#k1kUn63iJE`GpGF$b5!Rw2PZL%vn52`o#gMGsQMJhvb*0N8i}` zf5Xuzr56iwtawwl_vJqP;ko;pywStQy}8ErkH3Ap*8T0?>A2po*owv3*B73%==I->_&8hg)Hfz)4ExjuYE;8!GPJPYg zsmj2m5ZH2cX8r6bU66DM?T@M-lheqI>-`#iJd{l2Ozbw|Et#`xr?*84Nt n#mtNf`SAMk-$%bL?tjf+_F#37(#0xHP-gRV^>bP0l+XkKjDv!G diff --git a/packages/nodes-base/nodes/Zendesk/zendesk.svg b/packages/nodes-base/nodes/Zendesk/zendesk.svg new file mode 100644 index 0000000000..dc3d0ec9b3 --- /dev/null +++ b/packages/nodes-base/nodes/Zendesk/zendesk.svg @@ -0,0 +1,4 @@ + + + +