mirror of
https://github.com/lingble/twenty.git
synced 2025-10-29 20:02:29 +00:00
Fix create trigger called twice (#3243)
* Fix create trigger called twice * Add Zapier update action * Add Zapier delete action * Update description * Add dropDown for ids
This commit is contained in:
@@ -156,12 +156,6 @@ export class WorkspaceQueryRunnerService {
|
||||
): Promise<Record | undefined> {
|
||||
const results = await this.createMany({ data: [args.data] }, options);
|
||||
|
||||
await this.triggerWebhooks<Record>(
|
||||
results,
|
||||
CallWebhookJobsJobOperation.create,
|
||||
options,
|
||||
);
|
||||
|
||||
return results?.[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
import requestDb, { requestSchema } from '../utils/requestDb';
|
||||
import handleQueryParams from '../utils/handleQueryParams';
|
||||
import { capitalize } from '../utils/capitalize';
|
||||
import { computeInputFields } from '../utils/computeInputFields';
|
||||
|
||||
import { findObjectNamesSingularKey } from '../triggers/find_object_names_singular';
|
||||
|
||||
const recordInputFields = async (z: ZObject, bundle: Bundle) => {
|
||||
const schema = await requestSchema(z, bundle);
|
||||
const infos = schema.components.schemas[bundle.inputData.nameSingular];
|
||||
|
||||
return computeInputFields(infos);
|
||||
};
|
||||
import { capitalize } from '../utils/capitalize';
|
||||
import { recordInputFields } from '../utils/creates/creates.utils';
|
||||
import handleQueryParams from '../utils/handleQueryParams';
|
||||
import requestDb from '../utils/requestDb';
|
||||
|
||||
const perform = async (z: ZObject, bundle: Bundle) => {
|
||||
const data = bundle.inputData;
|
||||
@@ -30,9 +24,9 @@ export const createRecordKey = 'create_record';
|
||||
|
||||
export default {
|
||||
display: {
|
||||
description: 'Creates a new Record in Twenty',
|
||||
description: 'Create a Record in Twenty.',
|
||||
hidden: false,
|
||||
label: 'Create New Record',
|
||||
label: 'Create Record',
|
||||
},
|
||||
key: createRecordKey,
|
||||
noun: 'Record',
|
||||
|
||||
56
packages/twenty-zapier/src/creates/delete_record.ts
Normal file
56
packages/twenty-zapier/src/creates/delete_record.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { findObjectNamesPluralKey } from '../triggers/find_object_names_plural';
|
||||
import { listRecordIdsKey } from '../triggers/list_record_ids';
|
||||
import { capitalize } from '../utils/capitalize';
|
||||
import requestDb from '../utils/requestDb';
|
||||
|
||||
export const deleteRecordKey = 'delete_record';
|
||||
|
||||
const perform = async (z: ZObject, bundle: Bundle) => {
|
||||
const data = bundle.inputData;
|
||||
const nameSingular = data.nameSingular;
|
||||
const id = data.id;
|
||||
delete data.nameSingular;
|
||||
delete data.id;
|
||||
const query = `
|
||||
mutation delete${capitalize(nameSingular)} {
|
||||
delete${capitalize(nameSingular)}(
|
||||
id: "${id}"
|
||||
)
|
||||
{id}
|
||||
}`;
|
||||
return await requestDb(z, bundle, query);
|
||||
};
|
||||
|
||||
export default {
|
||||
display: {
|
||||
description: 'Delete a Record in Twenty.',
|
||||
hidden: false,
|
||||
label: 'Delete Record',
|
||||
},
|
||||
key: deleteRecordKey,
|
||||
noun: 'Record',
|
||||
operation: {
|
||||
inputFields: [
|
||||
{
|
||||
key: 'namePlural',
|
||||
label: 'Record Name',
|
||||
dynamic: `${findObjectNamesPluralKey}.namePlural`,
|
||||
required: true,
|
||||
altersDynamicFields: true,
|
||||
},
|
||||
{
|
||||
key: 'id',
|
||||
label: 'Id',
|
||||
type: 'string',
|
||||
dynamic: `${listRecordIdsKey}.id`,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
sample: {
|
||||
id: '179ed459-79cf-41d9-ab85-96397fa8e936',
|
||||
},
|
||||
perform,
|
||||
},
|
||||
};
|
||||
56
packages/twenty-zapier/src/creates/update_record.ts
Normal file
56
packages/twenty-zapier/src/creates/update_record.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { findObjectNamesSingularKey } from '../triggers/find_object_names_singular';
|
||||
import { capitalize } from '../utils/capitalize';
|
||||
import { recordInputFields } from '../utils/creates/creates.utils';
|
||||
import handleQueryParams from '../utils/handleQueryParams';
|
||||
import requestDb from '../utils/requestDb';
|
||||
|
||||
export const updateRecordKey = 'update_record';
|
||||
|
||||
const perform = async (z: ZObject, bundle: Bundle) => {
|
||||
const data = bundle.inputData;
|
||||
const nameSingular = data.nameSingular;
|
||||
const id = data.id;
|
||||
delete data.nameSingular;
|
||||
delete data.id;
|
||||
const query = `
|
||||
mutation update${capitalize(nameSingular)} {
|
||||
update${capitalize(nameSingular)}(
|
||||
data:{${handleQueryParams(data)}},
|
||||
id: "${id}"
|
||||
)
|
||||
{id}
|
||||
}`;
|
||||
return await requestDb(z, bundle, query);
|
||||
};
|
||||
|
||||
const updateRecordInputFields = async (z: ZObject, bundle: Bundle) => {
|
||||
return recordInputFields(z, bundle, true);
|
||||
};
|
||||
|
||||
export default {
|
||||
display: {
|
||||
description: 'Update a Record in Twenty.',
|
||||
hidden: false,
|
||||
label: 'Update Record',
|
||||
},
|
||||
key: updateRecordKey,
|
||||
noun: 'Record',
|
||||
operation: {
|
||||
inputFields: [
|
||||
{
|
||||
key: 'nameSingular',
|
||||
required: true,
|
||||
label: 'Record Name',
|
||||
dynamic: `${findObjectNamesSingularKey}.nameSingular`,
|
||||
altersDynamicFields: true,
|
||||
},
|
||||
updateRecordInputFields,
|
||||
],
|
||||
sample: {
|
||||
id: '179ed459-79cf-41d9-ab85-96397fa8e936',
|
||||
},
|
||||
perform,
|
||||
},
|
||||
};
|
||||
@@ -1,13 +1,19 @@
|
||||
import { version as platformVersion } from 'zapier-platform-core';
|
||||
|
||||
import 'dotenv/config';
|
||||
|
||||
const { version } = require('../package.json');
|
||||
|
||||
import createRecord, { createRecordKey } from './creates/create_record';
|
||||
import deleteRecord, { deleteRecordKey } from './creates/delete_record';
|
||||
import updateRecord, { updateRecordKey } from './creates/update_record';
|
||||
import findObjectNamesPlural, {
|
||||
findObjectNamesPluralKey,
|
||||
} from './triggers/find_object_names_plural';
|
||||
|
||||
const { version } = require('../package.json');
|
||||
import { version as platformVersion } from 'zapier-platform-core';
|
||||
import createRecord, { createRecordKey } from './creates/create_record';
|
||||
import findObjectNamesSingular, {
|
||||
findObjectNamesSingularKey,
|
||||
} from './triggers/find_object_names_singular';
|
||||
import listRecordIds, { listRecordIdsKey } from './triggers/list_record_ids';
|
||||
import triggerRecordCreated, {
|
||||
triggerRecordCreatedKey,
|
||||
} from './triggers/trigger_record_created';
|
||||
@@ -18,7 +24,6 @@ import triggerRecordUpdated, {
|
||||
triggerRecordUpdatedKey,
|
||||
} from './triggers/trigger_record_updated';
|
||||
import authentication from './authentication';
|
||||
import 'dotenv/config';
|
||||
|
||||
export default {
|
||||
version,
|
||||
@@ -27,11 +32,14 @@ export default {
|
||||
triggers: {
|
||||
[findObjectNamesSingularKey]: findObjectNamesSingular,
|
||||
[findObjectNamesPluralKey]: findObjectNamesPlural,
|
||||
[listRecordIdsKey]: listRecordIds,
|
||||
[triggerRecordCreatedKey]: triggerRecordCreated,
|
||||
[triggerRecordUpdatedKey]: triggerRecordUpdated,
|
||||
[triggerRecordDeletedKey]: triggerRecordDeleted,
|
||||
},
|
||||
creates: {
|
||||
[createRecordKey]: createRecord,
|
||||
[updateRecordKey]: updateRecord,
|
||||
[deleteRecordKey]: deleteRecord,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Bundle, createAppTester, tools, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { createRecordKey } from '../../creates/create_record';
|
||||
import App from '../../index';
|
||||
import getBundle from '../../utils/getBundle';
|
||||
import { Bundle, createAppTester, tools, ZObject } from 'zapier-platform-core';
|
||||
import requestDb from '../../utils/requestDb';
|
||||
import { createRecordKey } from '../../creates/create_record';
|
||||
const appTester = createAppTester(App);
|
||||
tools.env.inject();
|
||||
|
||||
describe('creates.[createRecordKey]', () => {
|
||||
describe('creates.create_company', () => {
|
||||
test('should run to create a Company Record', async () => {
|
||||
const bundle = getBundle({
|
||||
nameSingular: 'Company',
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Bundle, createAppTester, tools, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { createRecordKey } from '../../creates/create_record';
|
||||
import { deleteRecordKey } from '../../creates/delete_record';
|
||||
import App from '../../index';
|
||||
import getBundle from '../../utils/getBundle';
|
||||
import requestDb from '../../utils/requestDb';
|
||||
const appTester = createAppTester(App);
|
||||
|
||||
tools.env.inject();
|
||||
describe('creates.delete_company', () => {
|
||||
test('should run to delete a Company record', async () => {
|
||||
const createBundle = getBundle({
|
||||
nameSingular: 'Company',
|
||||
name: 'Delete Company Name',
|
||||
employees: 25,
|
||||
});
|
||||
|
||||
const createResult = await appTester(
|
||||
App.creates[createRecordKey].operation.perform,
|
||||
createBundle,
|
||||
);
|
||||
|
||||
const companyId = createResult.data?.createCompany?.id;
|
||||
|
||||
const deleteBundle = getBundle({
|
||||
nameSingular: 'Company',
|
||||
id: companyId,
|
||||
});
|
||||
|
||||
const deleteResult = await appTester(
|
||||
App.creates[deleteRecordKey].operation.perform,
|
||||
deleteBundle,
|
||||
);
|
||||
|
||||
expect(deleteResult).toBeDefined();
|
||||
expect(deleteResult.data?.deleteCompany?.id).toBeDefined();
|
||||
const checkDbResult = await appTester(
|
||||
(z: ZObject, bundle: Bundle) =>
|
||||
requestDb(
|
||||
z,
|
||||
bundle,
|
||||
`query findCompanies {companies(filter: {id: {eq: "${companyId}"}}){edges{node{id}}}}`,
|
||||
),
|
||||
deleteBundle,
|
||||
);
|
||||
expect(checkDbResult.data.companies.edges.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Bundle, createAppTester, tools, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { createRecordKey } from '../../creates/create_record';
|
||||
import { updateRecordKey } from '../../creates/update_record';
|
||||
import App from '../../index';
|
||||
import getBundle from '../../utils/getBundle';
|
||||
import requestDb from '../../utils/requestDb';
|
||||
const appTester = createAppTester(App);
|
||||
|
||||
tools.env.inject();
|
||||
describe('creates.update_company', () => {
|
||||
test('should run to update a Company record', async () => {
|
||||
const createBundle = getBundle({
|
||||
nameSingular: 'Company',
|
||||
name: 'Company Name',
|
||||
employees: 25,
|
||||
});
|
||||
|
||||
const createResult = await appTester(
|
||||
App.creates[createRecordKey].operation.perform,
|
||||
createBundle,
|
||||
);
|
||||
|
||||
const companyId = createResult.data?.createCompany?.id;
|
||||
|
||||
const updateBundle = getBundle({
|
||||
nameSingular: 'Company',
|
||||
id: companyId,
|
||||
name: 'Updated Company Name',
|
||||
});
|
||||
|
||||
const updateResult = await appTester(
|
||||
App.creates[updateRecordKey].operation.perform,
|
||||
updateBundle,
|
||||
);
|
||||
|
||||
expect(updateResult).toBeDefined();
|
||||
expect(updateResult.data?.updateCompany?.id).toBeDefined();
|
||||
const checkDbResult = await appTester(
|
||||
(z: ZObject, bundle: Bundle) =>
|
||||
requestDb(
|
||||
z,
|
||||
bundle,
|
||||
`query findCompany {company(filter: {id: {eq: "${companyId}"}}){id name}}`,
|
||||
),
|
||||
updateBundle,
|
||||
);
|
||||
expect(checkDbResult.data.company.name).toEqual('Updated Company Name');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createAppTester, tools } from 'zapier-platform-core';
|
||||
|
||||
import App from '../../index';
|
||||
import { listRecordIdsKey } from '../../triggers/list_record_ids';
|
||||
import getBundle from '../../utils/getBundle';
|
||||
tools.env.inject();
|
||||
|
||||
const appTester = createAppTester(App);
|
||||
describe('triggers.list_record_ids', () => {
|
||||
test('should run', async () => {
|
||||
const bundle = getBundle({ namePlural: 'companies' });
|
||||
const result = await appTester(
|
||||
App.triggers[listRecordIdsKey].operation.perform,
|
||||
bundle,
|
||||
);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBeGreaterThan(1);
|
||||
expect(result[0].id).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,9 @@ describe('computeInputFields', () => {
|
||||
const personInfos = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
},
|
||||
@@ -33,6 +36,7 @@ describe('computeInputFields', () => {
|
||||
required: ['avatarUrl'],
|
||||
};
|
||||
expect(computeInputFields(personInfos)).toEqual([
|
||||
{ key: 'id', label: 'Id', required: false, type: 'string' },
|
||||
{ key: 'email', label: 'Email', required: false, type: 'string' },
|
||||
{
|
||||
key: 'xLink__url',
|
||||
@@ -48,5 +52,27 @@ describe('computeInputFields', () => {
|
||||
},
|
||||
{ key: 'avatarUrl', label: 'Avatar Url', required: true, type: 'string' },
|
||||
]);
|
||||
expect(computeInputFields(personInfos, true)).toEqual([
|
||||
{ key: 'id', label: 'Id', required: true, type: 'string' },
|
||||
{ key: 'email', label: 'Email', required: false, type: 'string' },
|
||||
{
|
||||
key: 'xLink__url',
|
||||
label: 'X Link: Url',
|
||||
required: false,
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
key: 'xLink__label',
|
||||
label: 'X Link: Label',
|
||||
required: false,
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
key: 'avatarUrl',
|
||||
label: 'Avatar Url',
|
||||
required: false,
|
||||
type: 'string',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
37
packages/twenty-zapier/src/triggers/list_record_ids.ts
Normal file
37
packages/twenty-zapier/src/triggers/list_record_ids.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { capitalize } from '../utils/capitalize';
|
||||
import requestDb from '../utils/requestDb';
|
||||
|
||||
const listRecordIdsRequest = async (
|
||||
z: ZObject,
|
||||
bundle: Bundle,
|
||||
): Promise<{ id: string }[]> => {
|
||||
const data = bundle.inputData;
|
||||
const namePlural = data.namePlural;
|
||||
const query = `
|
||||
query List${capitalize(namePlural)}Ids {
|
||||
${namePlural}{edges{node{id}}}
|
||||
}`;
|
||||
const result = await requestDb(z, bundle, query);
|
||||
return result.data[namePlural]['edges'].map((edge: any) => {
|
||||
return {
|
||||
id: edge.node.id,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const listRecordIdsKey = 'list_record_ids';
|
||||
|
||||
export default {
|
||||
display: {
|
||||
description: 'List Record Ids of an object.',
|
||||
label: 'List Record Ids.',
|
||||
hidden: true,
|
||||
},
|
||||
key: listRecordIdsKey,
|
||||
noun: 'Object',
|
||||
operation: {
|
||||
perform: listRecordIdsRequest,
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { findObjectNamesPluralKey } from '../triggers/find_object_names_plural';
|
||||
import {
|
||||
listSample,
|
||||
@@ -5,8 +7,7 @@ import {
|
||||
perform,
|
||||
performUnsubscribe,
|
||||
subscribe,
|
||||
} from '../utils/triggers.utils';
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
} from '../utils/triggers/triggers.utils';
|
||||
|
||||
export const triggerRecordCreatedKey = 'trigger_record_created';
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { findObjectNamesPluralKey } from '../triggers/find_object_names_plural';
|
||||
import {
|
||||
perform,
|
||||
listSample,
|
||||
subscribe,
|
||||
performUnsubscribe,
|
||||
Operation,
|
||||
} from '../utils/triggers.utils';
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
perform,
|
||||
performUnsubscribe,
|
||||
subscribe,
|
||||
} from '../utils/triggers/triggers.utils';
|
||||
|
||||
export const triggerRecordDeletedKey = 'trigger_record_deleted';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { findObjectNamesPluralKey } from '../triggers/find_object_names_plural';
|
||||
import {
|
||||
listSample,
|
||||
@@ -5,8 +7,7 @@ import {
|
||||
perform,
|
||||
performUnsubscribe,
|
||||
subscribe,
|
||||
} from '../utils/triggers.utils';
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
} from '../utils/triggers/triggers.utils';
|
||||
|
||||
export const triggerRecordUpdatedKey = 'trigger_record_updated';
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ type Infos = {
|
||||
required: string[];
|
||||
};
|
||||
|
||||
export const computeInputFields = (infos: Infos): object[] => {
|
||||
export const computeInputFields = (
|
||||
infos: Infos,
|
||||
idRequired = false,
|
||||
): object[] => {
|
||||
const result = [];
|
||||
|
||||
for (const fieldName of Object.keys(infos.properties)) {
|
||||
@@ -38,17 +41,21 @@ export const computeInputFields = (infos: Infos): object[] => {
|
||||
result.push(field);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
const field = {
|
||||
key: fieldName,
|
||||
label: labelling(fieldName),
|
||||
type: infos.properties[fieldName].type,
|
||||
required: false,
|
||||
};
|
||||
if (infos.required?.includes(fieldName)) {
|
||||
if (
|
||||
(idRequired && fieldName === 'id') ||
|
||||
(!idRequired && infos.required?.includes(fieldName))
|
||||
) {
|
||||
field.required = true;
|
||||
}
|
||||
result.push(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
packages/twenty-zapier/src/utils/creates/creates.utils.ts
Normal file
15
packages/twenty-zapier/src/utils/creates/creates.utils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
|
||||
import { computeInputFields } from '../../utils/computeInputFields';
|
||||
import { requestSchema } from '../../utils/requestDb';
|
||||
|
||||
export const recordInputFields = async (
|
||||
z: ZObject,
|
||||
bundle: Bundle,
|
||||
idRequired = false,
|
||||
) => {
|
||||
const schema = await requestSchema(z, bundle);
|
||||
const infos = schema.components.schemas[bundle.inputData.nameSingular];
|
||||
|
||||
return computeInputFields(infos, idRequired);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Bundle, ZObject } from 'zapier-platform-core';
|
||||
import requestDb, { requestDbViaRestApi } from '../utils/requestDb';
|
||||
import handleQueryParams from '../utils/handleQueryParams';
|
||||
|
||||
import handleQueryParams from '../../utils/handleQueryParams';
|
||||
import requestDb, { requestDbViaRestApi } from '../../utils/requestDb';
|
||||
|
||||
export enum Operation {
|
||||
create = 'create',
|
||||
Reference in New Issue
Block a user