mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-31 12:47:58 +00:00 
			
		
		
		
	7203 support emails links phones in zapier inputs 2 (#7562)
## Done - add `EMAILS`, `PHONES`, `LINKS`, `RICH_TEXT`, `POSITION`, and `ARRAY` field support in Twenty zapier integration - fix `twenty-zapier` package tests and requirements ## Emails <img width="791" alt="image" src="https://github.com/user-attachments/assets/7987a1a2-6076-4715-9221-d4a1898b7634"> ## Links <img width="797" alt="image" src="https://github.com/user-attachments/assets/b94ce972-fae2-4953-b9e8-79c0478f5f60"> ## Phones <img width="789" alt="image" src="https://github.com/user-attachments/assets/7234eaaf-40b8-4772-8880-c58ba47618c5"> ## Array <img width="834" alt="image" src="https://github.com/user-attachments/assets/99cb6795-e428-40ea-9c3a-d52561c2c6e1">
This commit is contained in:
		
							
								
								
									
										9
									
								
								packages/twenty-zapier/jest.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								packages/twenty-zapier/jest.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | module.exports = { | ||||||
|  |   preset: 'ts-jest', | ||||||
|  |   testEnvironment: 'node', | ||||||
|  |   transform: { | ||||||
|  |     '^.+\\.ts?$': 'ts-jest', | ||||||
|  |   }, | ||||||
|  |   moduleFileExtensions: ['ts', 'js'], | ||||||
|  |   transformIgnorePatterns: ['/node_modules/'], | ||||||
|  | }; | ||||||
| @@ -25,6 +25,7 @@ | |||||||
|     "convertedByCLIVersion": "15.4.1" |     "convertedByCLIVersion": "15.4.1" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "dotenv": "^16.4.5", | ||||||
|     "zapier-platform-core": "15.5.1" |     "zapier-platform-core": "15.5.1" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { computeInputFields } from '../../utils/computeInputFields'; | import { computeInputFields } from '../../utils/computeInputFields'; | ||||||
| import { InputField } from '../../utils/data.types'; | import { FieldMetadataType, InputField } from '../../utils/data.types'; | ||||||
|  |  | ||||||
| describe('computeInputFields', () => { | describe('computeInputFields', () => { | ||||||
|   test('should create Person input fields properly', () => { |   test('should create Person input fields properly', () => { | ||||||
| @@ -11,7 +11,7 @@ describe('computeInputFields', () => { | |||||||
|         edges: [ |         edges: [ | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'RELATION', |               type: FieldMetadataType.RELATION, | ||||||
|               name: 'favorites', |               name: 'favorites', | ||||||
|               label: 'Favorites', |               label: 'Favorites', | ||||||
|               description: 'Favorites linked to the contact', |               description: 'Favorites linked to the contact', | ||||||
| @@ -21,7 +21,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'CURRENCY', |               type: FieldMetadataType.CURRENCY, | ||||||
|               name: 'annualSalary', |               name: 'annualSalary', | ||||||
|               label: 'Annual Salary', |               label: 'Annual Salary', | ||||||
|               description: 'Annual Salary of the Person', |               description: 'Annual Salary of the Person', | ||||||
| @@ -31,7 +31,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'TEXT', |               type: FieldMetadataType.TEXT, | ||||||
|               name: 'jobTitle', |               name: 'jobTitle', | ||||||
|               label: 'Job Title', |               label: 'Job Title', | ||||||
|               description: 'Contact’s job title', |               description: 'Contact’s job title', | ||||||
| @@ -43,7 +43,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'DATE_TIME', |               type: FieldMetadataType.DATE_TIME, | ||||||
|               name: 'updatedAt', |               name: 'updatedAt', | ||||||
|               label: 'Update date', |               label: 'Update date', | ||||||
|               description: null, |               description: null, | ||||||
| @@ -55,7 +55,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'FULL_NAME', |               type: FieldMetadataType.FULL_NAME, | ||||||
|               name: 'name', |               name: 'name', | ||||||
|               label: 'Name', |               label: 'Name', | ||||||
|               description: 'Contact’s name', |               description: 'Contact’s name', | ||||||
| @@ -68,7 +68,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'UUID', |               type: FieldMetadataType.UUID, | ||||||
|               name: 'id', |               name: 'id', | ||||||
|               label: 'Id', |               label: 'Id', | ||||||
|               description: null, |               description: null, | ||||||
| @@ -81,7 +81,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'NUMBER', |               type: FieldMetadataType.NUMBER, | ||||||
|               name: 'recordPosition', |               name: 'recordPosition', | ||||||
|               label: 'RecordPosition', |               label: 'RecordPosition', | ||||||
|               description: 'Record Position', |               description: 'Record Position', | ||||||
| @@ -91,7 +91,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'LINK', |               type: FieldMetadataType.LINK, | ||||||
|               name: 'xLink', |               name: 'xLink', | ||||||
|               label: 'X', |               label: 'X', | ||||||
|               description: 'Contact’s X/Twitter account', |               description: 'Contact’s X/Twitter account', | ||||||
| @@ -101,7 +101,17 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'EMAIL', |               type: FieldMetadataType.LINKS, | ||||||
|  |               name: 'whatsapp', | ||||||
|  |               label: 'Whatsapp', | ||||||
|  |               description: 'Contact’s Whatsapp account', | ||||||
|  |               isNullable: true, | ||||||
|  |               defaultValue: null, | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             node: { | ||||||
|  |               type: FieldMetadataType.EMAIL, | ||||||
|               name: 'email', |               name: 'email', | ||||||
|               label: 'Email', |               label: 'Email', | ||||||
|               description: 'Contact’s Email', |               description: 'Contact’s Email', | ||||||
| @@ -113,7 +123,7 @@ describe('computeInputFields', () => { | |||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             node: { |             node: { | ||||||
|               type: 'UUID', |               type: FieldMetadataType.UUID, | ||||||
|               name: 'companyId', |               name: 'companyId', | ||||||
|               label: 'Company id (foreign key)', |               label: 'Company id (foreign key)', | ||||||
|               description: 'Contact’s company id foreign key', |               description: 'Contact’s company id foreign key', | ||||||
| @@ -190,6 +200,27 @@ describe('computeInputFields', () => { | |||||||
|         helpText: 'Contact’s X/Twitter account: Link Label', |         helpText: 'Contact’s X/Twitter account: Link Label', | ||||||
|         required: false, |         required: false, | ||||||
|       }, |       }, | ||||||
|  |       { | ||||||
|  |         key: 'whatsapp__url', | ||||||
|  |         label: 'Whatsapp: Url', | ||||||
|  |         type: 'string', | ||||||
|  |         helpText: 'Contact’s Whatsapp account: Link Url', | ||||||
|  |         required: false, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         key: 'whatsapp__label', | ||||||
|  |         label: 'Whatsapp: Label', | ||||||
|  |         type: 'string', | ||||||
|  |         helpText: 'Contact’s Whatsapp account: Link Label', | ||||||
|  |         required: false, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         key: 'whatsapp__secondaryLinks', | ||||||
|  |         label: 'Whatsapp: Secondary Lings', | ||||||
|  |         type: 'string', | ||||||
|  |         helpText: 'Contact’s Whatsapp account: Link Label', | ||||||
|  |         required: false, | ||||||
|  |       }, | ||||||
|       { |       { | ||||||
|         key: 'email', |         key: 'email', | ||||||
|         label: 'Email', |         label: 'Email', | ||||||
|   | |||||||
| @@ -14,6 +14,20 @@ describe('utils.handleQueryParams', () => { | |||||||
|       domainName: 'Company Domain Name', |       domainName: 'Company Domain Name', | ||||||
|       linkedinUrl__url: '/linkedin_url', |       linkedinUrl__url: '/linkedin_url', | ||||||
|       linkedinUrl__label: 'Test linkedinUrl', |       linkedinUrl__label: 'Test linkedinUrl', | ||||||
|  |       whatsapp__primaryLinkUrl: '/whatsapp_url', | ||||||
|  |       whatsapp__primaryLinkLabel: 'Whatsapp Link', | ||||||
|  |       whatsapp__secondaryLinks: [ | ||||||
|  |         "{url: '/secondary_whatsapp_url',label: 'Secondary Whatsapp Link'}", | ||||||
|  |       ], | ||||||
|  |       emails: { | ||||||
|  |         primaryEmail: 'primary@email.com', | ||||||
|  |         additionalEmails: ['secondary@email.com'], | ||||||
|  |       }, | ||||||
|  |       phones: { | ||||||
|  |         primaryPhoneNumber: '322110011', | ||||||
|  |         primaryPhoneCountryCode: '+33', | ||||||
|  |         additionalPhones: ["{ phoneNumber: '322110012', countryCode: '+33' }"], | ||||||
|  |       }, | ||||||
|       xUrl__url: '/x_url', |       xUrl__url: '/x_url', | ||||||
|       xUrl__label: 'Test xUrl', |       xUrl__label: 'Test xUrl', | ||||||
|       annualRecurringRevenue: 100000, |       annualRecurringRevenue: 100000, | ||||||
| @@ -26,6 +40,9 @@ describe('utils.handleQueryParams', () => { | |||||||
|       'address: {addressCity: "Paris"}, ' + |       'address: {addressCity: "Paris"}, ' + | ||||||
|       'domainName: "Company Domain Name", ' + |       'domainName: "Company Domain Name", ' + | ||||||
|       'linkedinUrl: {url: "/linkedin_url", label: "Test linkedinUrl"}, ' + |       'linkedinUrl: {url: "/linkedin_url", label: "Test linkedinUrl"}, ' + | ||||||
|  |       'whatsapp: {primaryLinkUrl: "/whatsapp_url", primaryLinkLabel: "Whatsapp Link", secondaryLinks: [{url: \'/secondary_whatsapp_url\',label: \'Secondary Whatsapp Link\'}]}, ' + | ||||||
|  |       'emails: {primaryEmail: "primary@email.com", additionalEmails: ["secondary@email.com"]}, ' + | ||||||
|  |       'phones: {primaryPhoneNumber: "322110011", primaryPhoneCountryCode: "+33", additionalPhones: [{ phoneNumber: \'322110012\', countryCode: \'+33\' }]}, ' + | ||||||
|       'xUrl: {url: "/x_url", label: "Test xUrl"}, ' + |       'xUrl: {url: "/x_url", label: "Test xUrl"}, ' + | ||||||
|       'annualRecurringRevenue: 100000, ' + |       'annualRecurringRevenue: 100000, ' + | ||||||
|       'idealCustomerProfile: true, ' + |       'idealCustomerProfile: true, ' + | ||||||
|   | |||||||
| @@ -5,15 +5,21 @@ import { | |||||||
|   NodeField, |   NodeField, | ||||||
| } from '../utils/data.types'; | } from '../utils/data.types'; | ||||||
|  |  | ||||||
|  | const getListFromFieldMetadataType = (fieldMetadataType: FieldMetadataType) => { | ||||||
|  |   return fieldMetadataType === FieldMetadataType.ARRAY; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const getTypeFromFieldMetadataType = ( | const getTypeFromFieldMetadataType = ( | ||||||
|   fieldMetadataType: string, |   fieldMetadataType: FieldMetadataType, | ||||||
| ): string | undefined => { | ): string | undefined => { | ||||||
|   switch (fieldMetadataType) { |   switch (fieldMetadataType) { | ||||||
|     case FieldMetadataType.UUID: |     case FieldMetadataType.UUID: | ||||||
|     case FieldMetadataType.TEXT: |     case FieldMetadataType.TEXT: | ||||||
|  |     case FieldMetadataType.RICH_TEXT: | ||||||
|     case FieldMetadataType.PHONE: |     case FieldMetadataType.PHONE: | ||||||
|     case FieldMetadataType.EMAIL: |     case FieldMetadataType.EMAIL: | ||||||
|     case FieldMetadataType.LINK: |     case FieldMetadataType.LINK: | ||||||
|  |     case FieldMetadataType.ARRAY: | ||||||
|     case FieldMetadataType.RATING: |     case FieldMetadataType.RATING: | ||||||
|       return 'string'; |       return 'string'; | ||||||
|     case FieldMetadataType.DATE_TIME: |     case FieldMetadataType.DATE_TIME: | ||||||
| @@ -23,6 +29,7 @@ const getTypeFromFieldMetadataType = ( | |||||||
|     case FieldMetadataType.BOOLEAN: |     case FieldMetadataType.BOOLEAN: | ||||||
|       return 'boolean'; |       return 'boolean'; | ||||||
|     case FieldMetadataType.NUMBER: |     case FieldMetadataType.NUMBER: | ||||||
|  |     case FieldMetadataType.POSITION: | ||||||
|       return 'integer'; |       return 'integer'; | ||||||
|     case FieldMetadataType.NUMERIC: |     case FieldMetadataType.NUMERIC: | ||||||
|       return 'number'; |       return 'number'; | ||||||
| @@ -35,7 +42,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|   switch (nodeField.type) { |   switch (nodeField.type) { | ||||||
|     case FieldMetadataType.FULL_NAME: { |     case FieldMetadataType.FULL_NAME: { | ||||||
|       const firstName: NodeField = { |       const firstName: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'firstName', |         name: 'firstName', | ||||||
|         label: 'First Name', |         label: 'First Name', | ||||||
|         description: 'First Name', |         description: 'First Name', | ||||||
| @@ -43,7 +50,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const lastName: NodeField = { |       const lastName: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'lastName', |         name: 'lastName', | ||||||
|         label: 'Last Name', |         label: 'Last Name', | ||||||
|         description: 'Last Name', |         description: 'Last Name', | ||||||
| @@ -54,7 +61,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|     } |     } | ||||||
|     case FieldMetadataType.LINK: { |     case FieldMetadataType.LINK: { | ||||||
|       const url: NodeField = { |       const url: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'url', |         name: 'url', | ||||||
|         label: 'Url', |         label: 'Url', | ||||||
|         description: 'Link Url', |         description: 'Link Url', | ||||||
| @@ -62,7 +69,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const label: NodeField = { |       const label: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'label', |         name: 'label', | ||||||
|         label: 'Label', |         label: 'Label', | ||||||
|         description: 'Link Label', |         description: 'Link Label', | ||||||
| @@ -73,7 +80,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|     } |     } | ||||||
|     case FieldMetadataType.CURRENCY: { |     case FieldMetadataType.CURRENCY: { | ||||||
|       const amountMicros: NodeField = { |       const amountMicros: NodeField = { | ||||||
|         type: 'NUMBER', |         type: FieldMetadataType.NUMBER, | ||||||
|         name: 'amountMicros', |         name: 'amountMicros', | ||||||
|         label: 'Amount Micros', |         label: 'Amount Micros', | ||||||
|         description: 'Amount Micros. eg: set 3210000 for 3.21$', |         description: 'Amount Micros. eg: set 3210000 for 3.21$', | ||||||
| @@ -81,7 +88,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const currencyCode: NodeField = { |       const currencyCode: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'currencyCode', |         name: 'currencyCode', | ||||||
|         label: 'Currency Code', |         label: 'Currency Code', | ||||||
|         description: 'Currency Code. eg: USD, EUR, etc...', |         description: 'Currency Code. eg: USD, EUR, etc...', | ||||||
| @@ -92,7 +99,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|     } |     } | ||||||
|     case FieldMetadataType.ADDRESS: { |     case FieldMetadataType.ADDRESS: { | ||||||
|       const address1: NodeField = { |       const address1: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressStreet1', |         name: 'addressStreet1', | ||||||
|         label: 'Address', |         label: 'Address', | ||||||
|         description: 'Address', |         description: 'Address', | ||||||
| @@ -100,7 +107,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const address2: NodeField = { |       const address2: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressStreet2', |         name: 'addressStreet2', | ||||||
|         label: 'Address 2', |         label: 'Address 2', | ||||||
|         description: 'Address 2', |         description: 'Address 2', | ||||||
| @@ -108,7 +115,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const city: NodeField = { |       const city: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressCity', |         name: 'addressCity', | ||||||
|         label: 'City', |         label: 'City', | ||||||
|         description: 'City', |         description: 'City', | ||||||
| @@ -116,7 +123,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const state: NodeField = { |       const state: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressState', |         name: 'addressState', | ||||||
|         label: 'State', |         label: 'State', | ||||||
|         description: 'State', |         description: 'State', | ||||||
| @@ -124,7 +131,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const postalCode: NodeField = { |       const postalCode: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressPostalCode', |         name: 'addressPostalCode', | ||||||
|         label: 'Postal Code', |         label: 'Postal Code', | ||||||
|         description: 'Postal Code', |         description: 'Postal Code', | ||||||
| @@ -132,7 +139,7 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|         defaultValue: null, |         defaultValue: null, | ||||||
|       }; |       }; | ||||||
|       const country: NodeField = { |       const country: NodeField = { | ||||||
|         type: 'TEXT', |         type: FieldMetadataType.TEXT, | ||||||
|         name: 'addressCountry', |         name: 'addressCountry', | ||||||
|         label: 'Country', |         label: 'Country', | ||||||
|         description: 'Country', |         description: 'Country', | ||||||
| @@ -141,6 +148,84 @@ const get_subfieldsFromField = (nodeField: NodeField): NodeField[] => { | |||||||
|       }; |       }; | ||||||
|       return [address1, address2, city, state, postalCode, country]; |       return [address1, address2, city, state, postalCode, country]; | ||||||
|     } |     } | ||||||
|  |     case FieldMetadataType.PHONES: { | ||||||
|  |       const primaryPhoneNumber: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'primaryPhoneNumber', | ||||||
|  |         label: 'Primary Phone Number', | ||||||
|  |         description: 'Primary Phone Number. 600112233', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       const primaryPhoneCountryCode: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'primaryPhoneCountryCode', | ||||||
|  |         label: 'Primary Phone Country Code', | ||||||
|  |         description: 'Primary Phone Country Code. eg: +33', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       const additionalPhones: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'additionalPhones', | ||||||
|  |         label: 'Additional Phones', | ||||||
|  |         description: 'Additional Phones', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |         placeholder: '{ number: "", countryCode: "" }', | ||||||
|  |         list: true, | ||||||
|  |       }; | ||||||
|  |       return [primaryPhoneNumber, primaryPhoneCountryCode, additionalPhones]; | ||||||
|  |     } | ||||||
|  |     case FieldMetadataType.EMAILS: { | ||||||
|  |       const primaryEmail: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'primaryEmail', | ||||||
|  |         label: 'Primary Email', | ||||||
|  |         description: 'Primary Email', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       const additionalEmails: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'additionalEmails', | ||||||
|  |         label: 'Additional Emails', | ||||||
|  |         description: 'Additional Emails', | ||||||
|  |         list: true, | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       return [primaryEmail, additionalEmails]; | ||||||
|  |     } | ||||||
|  |     case FieldMetadataType.LINKS: { | ||||||
|  |       const primaryLinkLabel: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'primaryLinkLabel', | ||||||
|  |         label: 'Primary Link Label', | ||||||
|  |         description: 'Primary Link Label', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       const primaryLinkUrl: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'primaryLinkUrl', | ||||||
|  |         label: 'Primary Link Url', | ||||||
|  |         description: 'Primary Link Url', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |       }; | ||||||
|  |       const secondaryLinks: NodeField = { | ||||||
|  |         type: FieldMetadataType.TEXT, | ||||||
|  |         name: 'secondaryLinks', | ||||||
|  |         label: 'Secondary Links', | ||||||
|  |         description: 'Secondary Links', | ||||||
|  |         isNullable: true, | ||||||
|  |         defaultValue: null, | ||||||
|  |         placeholder: '{ url: "", label: "" }', | ||||||
|  |         list: true, | ||||||
|  |       }; | ||||||
|  |       return [primaryLinkLabel, primaryLinkUrl, secondaryLinks]; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|       throw new Error(`Unknown nodeField type: ${nodeField.type}`); |       throw new Error(`Unknown nodeField type: ${nodeField.type}`); | ||||||
|   } |   } | ||||||
| @@ -161,6 +246,9 @@ export const computeInputFields = ( | |||||||
|       case FieldMetadataType.FULL_NAME: |       case FieldMetadataType.FULL_NAME: | ||||||
|       case FieldMetadataType.LINK: |       case FieldMetadataType.LINK: | ||||||
|       case FieldMetadataType.CURRENCY: |       case FieldMetadataType.CURRENCY: | ||||||
|  |       case FieldMetadataType.PHONES: | ||||||
|  |       case FieldMetadataType.EMAILS: | ||||||
|  |       case FieldMetadataType.LINKS: | ||||||
|       case FieldMetadataType.ADDRESS: |       case FieldMetadataType.ADDRESS: | ||||||
|         for (const subNodeField of get_subfieldsFromField(nodeField)) { |         for (const subNodeField of get_subfieldsFromField(nodeField)) { | ||||||
|           const field = { |           const field = { | ||||||
| @@ -169,12 +257,15 @@ export const computeInputFields = ( | |||||||
|             type: getTypeFromFieldMetadataType(subNodeField.type), |             type: getTypeFromFieldMetadataType(subNodeField.type), | ||||||
|             helpText: `${nodeField.description}: ${subNodeField.description}`, |             helpText: `${nodeField.description}: ${subNodeField.description}`, | ||||||
|             required: isFieldRequired(subNodeField), |             required: isFieldRequired(subNodeField), | ||||||
|  |             list: !!subNodeField.list, | ||||||
|  |             placeholder: subNodeField.placeholder, | ||||||
|           } as InputField; |           } as InputField; | ||||||
|           result.push(field); |           result.push(field); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|       case FieldMetadataType.UUID: |       case FieldMetadataType.UUID: | ||||||
|       case FieldMetadataType.TEXT: |       case FieldMetadataType.TEXT: | ||||||
|  |       case FieldMetadataType.RICH_TEXT: | ||||||
|       case FieldMetadataType.PHONE: |       case FieldMetadataType.PHONE: | ||||||
|       case FieldMetadataType.EMAIL: |       case FieldMetadataType.EMAIL: | ||||||
|       case FieldMetadataType.DATE_TIME: |       case FieldMetadataType.DATE_TIME: | ||||||
| @@ -182,6 +273,8 @@ export const computeInputFields = ( | |||||||
|       case FieldMetadataType.BOOLEAN: |       case FieldMetadataType.BOOLEAN: | ||||||
|       case FieldMetadataType.NUMBER: |       case FieldMetadataType.NUMBER: | ||||||
|       case FieldMetadataType.NUMERIC: |       case FieldMetadataType.NUMERIC: | ||||||
|  |       case FieldMetadataType.POSITION: | ||||||
|  |       case FieldMetadataType.ARRAY: | ||||||
|       case FieldMetadataType.RATING: { |       case FieldMetadataType.RATING: { | ||||||
|         const nodeFieldType = getTypeFromFieldMetadataType(nodeField.type); |         const nodeFieldType = getTypeFromFieldMetadataType(nodeField.type); | ||||||
|         if (!nodeFieldType) { |         if (!nodeFieldType) { | ||||||
| @@ -196,6 +289,7 @@ export const computeInputFields = ( | |||||||
|           type: nodeFieldType, |           type: nodeFieldType, | ||||||
|           helpText: nodeField.description, |           helpText: nodeField.description, | ||||||
|           required, |           required, | ||||||
|  |           list: getListFromFieldMetadataType(nodeField.type), | ||||||
|         }; |         }; | ||||||
|         result.push(field); |         result.push(field); | ||||||
|         break; |         break; | ||||||
|   | |||||||
| @@ -3,12 +3,14 @@ export type InputData = { [x: string]: any }; | |||||||
| export type ObjectData = { id: string } | { [x: string]: any }; | export type ObjectData = { id: string } | { [x: string]: any }; | ||||||
|  |  | ||||||
| export type NodeField = { | export type NodeField = { | ||||||
|   type: string; |   type: FieldMetadataType; | ||||||
|   name: string; |   name: string; | ||||||
|   label: string; |   label: string; | ||||||
|   description: string | null; |   description: string | null; | ||||||
|   isNullable: boolean; |   isNullable: boolean; | ||||||
|   defaultValue: object | null; |   defaultValue: object | null; | ||||||
|  |   list?: boolean; | ||||||
|  |   placeholder?: string; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export type Node = { | export type Node = { | ||||||
| @@ -28,26 +30,39 @@ export type InputField = { | |||||||
|   type: string; |   type: string; | ||||||
|   helpText: string | null; |   helpText: string | null; | ||||||
|   required: boolean; |   required: boolean; | ||||||
|  |   list?: boolean; | ||||||
|  |   placeholder?: string; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export enum FieldMetadataType { | export enum FieldMetadataType { | ||||||
|   UUID = 'UUID', |   UUID = 'UUID', | ||||||
|   TEXT = 'TEXT', |   TEXT = 'TEXT', | ||||||
|   PHONE = 'PHONE', |   PHONE = 'PHONE', | ||||||
|  |   PHONES = 'PHONES', | ||||||
|   EMAIL = 'EMAIL', |   EMAIL = 'EMAIL', | ||||||
|  |   EMAILS = 'EMAILS', | ||||||
|   DATE_TIME = 'DATE_TIME', |   DATE_TIME = 'DATE_TIME', | ||||||
|   DATE = 'DATE', |   DATE = 'DATE', | ||||||
|   BOOLEAN = 'BOOLEAN', |   BOOLEAN = 'BOOLEAN', | ||||||
|   NUMBER = 'NUMBER', |   NUMBER = 'NUMBER', | ||||||
|   NUMERIC = 'NUMERIC', |   NUMERIC = 'NUMERIC', | ||||||
|   LINK = 'LINK', |   LINK = 'LINK', | ||||||
|  |   LINKS = 'LINKS', | ||||||
|   CURRENCY = 'CURRENCY', |   CURRENCY = 'CURRENCY', | ||||||
|   FULL_NAME = 'FULL_NAME', |   FULL_NAME = 'FULL_NAME', | ||||||
|   RATING = 'RATING', |   RATING = 'RATING', | ||||||
|   SELECT = 'SELECT', |   SELECT = 'SELECT', | ||||||
|   MULTI_SELECT = 'MULTI_SELECT', |   MULTI_SELECT = 'MULTI_SELECT', | ||||||
|   RELATION = 'RELATION', |   POSITION = 'POSITION', | ||||||
|   ADDRESS = 'ADDRESS', |   ADDRESS = 'ADDRESS', | ||||||
|  |   RICH_TEXT = 'RICH_TEXT', | ||||||
|  |   ARRAY = 'ARRAY', | ||||||
|  |  | ||||||
|  |   // Ignored fieldTypes | ||||||
|  |   RELATION = 'RELATION', | ||||||
|  |   RAW_JSON = 'RAW_JSON', | ||||||
|  |   ACTOR = 'ACTOR', | ||||||
|  |   TS_VECTOR = 'TS_VECTOR', | ||||||
| } | } | ||||||
|  |  | ||||||
| export type Schema = { | export type Schema = { | ||||||
|   | |||||||
| @@ -1,5 +1,17 @@ | |||||||
| import { InputData } from '../utils/data.types'; | import { InputData } from '../utils/data.types'; | ||||||
|  |  | ||||||
|  | const OBJECT_SUBFIELD_NAMES = ['secondaryLinks', 'additionalPhones']; | ||||||
|  |  | ||||||
|  | const formatArrayInputData = ( | ||||||
|  |   key: string, | ||||||
|  |   arrayInputData: InputData, | ||||||
|  | ): string => { | ||||||
|  |   if (OBJECT_SUBFIELD_NAMES.includes(key)) { | ||||||
|  |     return `${arrayInputData[key].join('","')}`; | ||||||
|  |   } | ||||||
|  |   return `"${arrayInputData[key].join('","')}"`; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const handleQueryParams = (inputData: InputData): string => { | const handleQueryParams = (inputData: InputData): string => { | ||||||
|   const formattedInputData: InputData = {}; |   const formattedInputData: InputData = {}; | ||||||
|   Object.keys(inputData).forEach((key) => { |   Object.keys(inputData).forEach((key) => { | ||||||
| @@ -17,7 +29,11 @@ const handleQueryParams = (inputData: InputData): string => { | |||||||
|   let result = ''; |   let result = ''; | ||||||
|   Object.keys(formattedInputData).forEach((key) => { |   Object.keys(formattedInputData).forEach((key) => { | ||||||
|     let quote = ''; |     let quote = ''; | ||||||
|     if (typeof formattedInputData[key] === 'object') { |     if (Array.isArray(formattedInputData[key])) { | ||||||
|  |       result = result.concat( | ||||||
|  |         `${key}: [${formatArrayInputData(key, formattedInputData)}], `, | ||||||
|  |       ); | ||||||
|  |     } else if (typeof formattedInputData[key] === 'object') { | ||||||
|       result = result.concat( |       result = result.concat( | ||||||
|         `${key}: {${handleQueryParams(formattedInputData[key])}}, `, |         `${key}: {${handleQueryParams(formattedInputData[key])}}, `, | ||||||
|       ); |       ); | ||||||
|   | |||||||
| @@ -9,5 +9,12 @@ | |||||||
|     "strict": true, |     "strict": true, | ||||||
|     "esModuleInterop": true, |     "esModuleInterop": true, | ||||||
|     "skipLibCheck": true |     "skipLibCheck": true | ||||||
|   } |   }, | ||||||
|  |   "exclude": [ | ||||||
|  |     "**/*.spec.ts", | ||||||
|  |     "**/*.test.ts", | ||||||
|  |     "**/*.spec.tsx", | ||||||
|  |     "**/*.test.tsx", | ||||||
|  |     "jest.config.ts" | ||||||
|  |   ] | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24321,7 +24321,7 @@ __metadata: | |||||||
|   languageName: node |   languageName: node | ||||||
|   linkType: hard |   linkType: hard | ||||||
| 
 | 
 | ||||||
| "dotenv@npm:^16.0.0, dotenv@npm:^16.0.3, dotenv@npm:^16.3.0": | "dotenv@npm:^16.0.0, dotenv@npm:^16.0.3, dotenv@npm:^16.3.0, dotenv@npm:^16.4.5": | ||||||
|   version: 16.4.5 |   version: 16.4.5 | ||||||
|   resolution: "dotenv@npm:16.4.5" |   resolution: "dotenv@npm:16.4.5" | ||||||
|   checksum: 10c0/48d92870076832af0418b13acd6e5a5a3e83bb00df690d9812e94b24aff62b88ade955ac99a05501305b8dc8f1b0ee7638b18493deb6fe93d680e5220936292f |   checksum: 10c0/48d92870076832af0418b13acd6e5a5a3e83bb00df690d9812e94b24aff62b88ade955ac99a05501305b8dc8f1b0ee7638b18493deb6fe93d680e5220936292f | ||||||
| @@ -43852,6 +43852,7 @@ __metadata: | |||||||
|   version: 0.0.0-use.local |   version: 0.0.0-use.local | ||||||
|   resolution: "twenty-zapier@workspace:packages/twenty-zapier" |   resolution: "twenty-zapier@workspace:packages/twenty-zapier" | ||||||
|   dependencies: |   dependencies: | ||||||
|  |     dotenv: "npm:^16.4.5" | ||||||
|     jest: "npm:29.7.0" |     jest: "npm:29.7.0" | ||||||
|     rimraf: "npm:^3.0.2" |     rimraf: "npm:^3.0.2" | ||||||
|     zapier-platform-cli: "npm:^15.4.1" |     zapier-platform-cli: "npm:^15.4.1" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 martmull
					martmull