feat: add create or update workflow trigger (#14708)

### Description

This PR focuses on
https://github.com/twentyhq/core-team-issues/issues/1476

- introduces the handling of upserted events in the workflow trigger
system


## Visual Appearance
<img width="1792" height="1039" alt="Screenshot 2025-09-21 at 11 40
28 PM"
src="https://github.com/user-attachments/assets/d926b566-f7d3-412b-b1ab-ed2064425f3d"
/>

<img width="501" height="1025" alt="Screenshot 2025-09-21 at 11 40
39 PM"
src="https://github.com/user-attachments/assets/13c3031a-0762-4c80-8df1-fa74ca70a540"
/>


### Changes
- Added `UPSERTED` action to the `DatabaseEventAction` enum.
- Updated the `WorkflowEditTriggerDatabaseEventForm` to support upserted
events.

---------

Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
Harshit Singh
2025-10-01 18:47:05 +05:30
committed by GitHub
parent b5e6703f35
commit ae4a93c993
22 changed files with 213 additions and 16 deletions
@@ -2,6 +2,7 @@ import { AuditService } from 'src/engine/core-modules/audit/services/audit.servi
import { OBJECT_RECORD_CREATED_EVENT } from 'src/engine/core-modules/audit/utils/events/object-event/object-record-created';
import { OBJECT_RECORD_DELETED_EVENT } from 'src/engine/core-modules/audit/utils/events/object-event/object-record-delete';
import { OBJECT_RECORD_UPDATED_EVENT } from 'src/engine/core-modules/audit/utils/events/object-event/object-record-updated';
import { OBJECT_RECORD_UPSERTED_EVENT } from 'src/engine/core-modules/audit/utils/events/object-event/object-record-upserted';
import { type ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event';
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
@@ -50,6 +51,12 @@ export class CreateAuditLogFromInternalEvent {
recordId: eventData.recordId,
objectMetadataId: eventData.objectMetadata.id,
});
} else if (workspaceEventBatch.name.endsWith('.upserted')) {
auditService.createObjectEvent(OBJECT_RECORD_UPSERTED_EVENT, {
...eventProperties,
recordId: eventData.recordId,
objectMetadataId: eventData.objectMetadata.id,
});
}
}
}
@@ -10,6 +10,10 @@ import {
type OBJECT_RECORD_UPDATED_EVENT,
type ObjectRecordUpdatedTrackEvent,
} from 'src/engine/core-modules/audit/utils/events/object-event/object-record-updated';
import {
type OBJECT_RECORD_UPSERTED_EVENT,
type ObjectRecordUpsertedTrackEvent,
} from 'src/engine/core-modules/audit/utils/events/object-event/object-record-upserted';
import {
type CUSTOM_DOMAIN_ACTIVATED_EVENT,
type CustomDomainActivatedTrackEvent,
@@ -50,6 +54,7 @@ export type TrackEventName =
| typeof OBJECT_RECORD_CREATED_EVENT
| typeof OBJECT_RECORD_UPDATED_EVENT
| typeof OBJECT_RECORD_DELETED_EVENT
| typeof OBJECT_RECORD_UPSERTED_EVENT
| typeof USER_SIGNUP_EVENT;
// Map event names to their corresponding event types
@@ -64,6 +69,7 @@ export interface TrackEvents {
[OBJECT_RECORD_DELETED_EVENT]: ObjectRecordDeletedTrackEvent;
[OBJECT_RECORD_CREATED_EVENT]: ObjectRecordCreatedTrackEvent;
[OBJECT_RECORD_UPDATED_EVENT]: ObjectRecordUpdatedTrackEvent;
[OBJECT_RECORD_UPSERTED_EVENT]: ObjectRecordUpsertedTrackEvent;
}
export type TrackEventProperties<T extends TrackEventName> =
@@ -0,0 +1,15 @@
import { z } from 'zod';
import { registerEvent } from 'src/engine/core-modules/audit/utils/events/workspace-event/track';
export const OBJECT_RECORD_UPSERTED_EVENT = 'Object Record Upserted' as const;
export const objectRecordUpsertedSchema = z.object({
event: z.literal(OBJECT_RECORD_UPSERTED_EVENT),
properties: z.looseObject({}),
});
export type ObjectRecordUpsertedTrackEvent = z.infer<
typeof objectRecordUpsertedSchema
>;
registerEvent(OBJECT_RECORD_UPSERTED_EVENT, objectRecordUpsertedSchema);
@@ -3,10 +3,12 @@ import { type ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emit
import { type ObjectRecordDestroyEvent } from 'src/engine/core-modules/event-emitter/types/object-record-destroy.event';
import { type ObjectRecordRestoreEvent } from 'src/engine/core-modules/event-emitter/types/object-record-restore.event';
import { type ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
import { type ObjectRecordUpsertEvent } from 'src/engine/core-modules/event-emitter/types/object-record-upsert.event';
export type ObjectRecordEvent<T = object> =
| ObjectRecordUpdateEvent<T>
| ObjectRecordDeleteEvent<T>
| ObjectRecordCreateEvent<T>
| ObjectRecordDestroyEvent<T>
| ObjectRecordRestoreEvent<T>;
| ObjectRecordRestoreEvent<T>
| ObjectRecordUpsertEvent<T>;
@@ -2,9 +2,11 @@ import { type ObjectRecordCreateEvent } from 'src/engine/core-modules/event-emit
import { type ObjectRecordDeleteEvent } from 'src/engine/core-modules/event-emitter/types/object-record-delete.event';
import { type ObjectRecordRestoreEvent } from 'src/engine/core-modules/event-emitter/types/object-record-restore.event';
import { type ObjectRecordUpdateEvent } from 'src/engine/core-modules/event-emitter/types/object-record-update.event';
import { type ObjectRecordUpsertEvent } from 'src/engine/core-modules/event-emitter/types/object-record-upsert.event';
export type ObjectRecordNonDestructiveEvent =
| ObjectRecordCreateEvent
| ObjectRecordUpdateEvent
| ObjectRecordDeleteEvent
| ObjectRecordRestoreEvent;
| ObjectRecordRestoreEvent
| ObjectRecordUpsertEvent;
@@ -0,0 +1,13 @@
import { type ObjectRecordDiff } from 'src/engine/core-modules/event-emitter/types/object-record-diff';
import { ObjectRecordBaseEvent } from 'src/engine/core-modules/event-emitter/types/object-record.base.event';
export class ObjectRecordUpsertEvent<
T = object,
> extends ObjectRecordBaseEvent<T> {
properties: {
before?: T;
after: T;
diff?: Partial<ObjectRecordDiff<T>>;
updatedFields?: string[];
};
}