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:
martmull
2024-01-05 11:44:47 +01:00
committed by GitHub
parent 618d9678b5
commit f35b40c428
17 changed files with 358 additions and 41 deletions

View File

@@ -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];
}

View File

@@ -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',

View 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,
},
};

View 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,
},
};

View File

@@ -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,
},
};

View File

@@ -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',

View File

@@ -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);
});
});

View File

@@ -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');
});
});

View File

@@ -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();
});
});

View File

@@ -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',
},
]);
});
});

View 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,
},
};

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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);
}
}
}

View 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);
};

View File

@@ -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',