related to https://github.com/twentyhq/core-team-issues/issues/601 ## Done - add a `onDbEvent` `Subscription` graphql endpoint to listen to database_event using what we have done with webhooks: - you can subscribe to any `action` (created, updated, ...) for any `objectNameSingular` or a specific `recordId`. Parameters are nullable and treated as wildcards when null. - returns events with following shape ```typescript @Field(() => String) eventId: string; @Field() emittedAt: string; @Field(() => DatabaseEventAction) action: DatabaseEventAction; @Field(() => String) objectNameSingular: string; @Field(() => GraphQLJSON) record: ObjectRecord; @Field(() => [String], { nullable: true }) updatedFields?: string[]; ``` - front provide a componentEffect `<ListenRecordUpdatesEffect />` that listen for an `objectNameSingular`, a `recordId` and a list of `listenedFields`. It subscribes to record updates and updates its apollo cached value for specified `listenedFields` - subscription is protected with credentials ## Result Here is an application with `workflowRun` https://github.com/user-attachments/assets/c964d857-3b54-495f-bf14-587ba26c5a8c --------- Co-authored-by: prastoin <paul@twenty.com>
44 lines
1.5 KiB
TypeScript
44 lines
1.5 KiB
TypeScript
import { Args, Resolver, Subscription } from '@nestjs/graphql';
|
|
import { Inject, UseGuards } from '@nestjs/common';
|
|
|
|
import { RedisPubSub } from 'graphql-redis-subscriptions';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
|
|
import { OnDbEventDTO } from 'src/engine/subscriptions/dtos/on-db-event.dto';
|
|
import { OnDbEventInput } from 'src/engine/subscriptions/dtos/on-db-event.input';
|
|
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
|
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
|
|
|
@Resolver()
|
|
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
|
|
export class SubscriptionsResolver {
|
|
constructor(@Inject('PUB_SUB') private readonly pubSub: RedisPubSub) {}
|
|
|
|
@Subscription(() => OnDbEventDTO, {
|
|
filter: (
|
|
payload: { onDbEvent: OnDbEventDTO },
|
|
variables: { input: OnDbEventInput },
|
|
) => {
|
|
const isActionMatching =
|
|
!isDefined(variables.input.action) ||
|
|
payload.onDbEvent.action === variables.input.action;
|
|
|
|
const isObjectNameSingularMatching =
|
|
!isDefined(variables.input.objectNameSingular) ||
|
|
payload.onDbEvent.objectNameSingular ===
|
|
variables.input.objectNameSingular;
|
|
|
|
const isRecordIdMatching =
|
|
!isDefined(variables.input.recordId) ||
|
|
payload.onDbEvent.record.id === variables.input.recordId;
|
|
|
|
return (
|
|
isActionMatching && isObjectNameSingularMatching && isRecordIdMatching
|
|
);
|
|
},
|
|
})
|
|
onDbEvent(@Args('input') _: OnDbEventInput) {
|
|
return this.pubSub.asyncIterator('onDbEvent');
|
|
}
|
|
}
|