Create the necessary tooling to listen to metadata events and plug it to the front components. Now we have a hot reload like experience when we edit a component in an app. ## Backend - Split `EventWithQueryIds` into `ObjectRecordEventWithQueryIds` and `MetadataEventWithQueryIds` - Publish metadata event batches to active SSE streams in `MetadataEventsToDbListener` ## Frontend - Create a metadata event dispatching pipeline: SSE metadata events are grouped by metadata name, transformed into `MetadataOperationBrowserEventDetail` objects, and dispatched as browser `CustomEvents` - Add `useListenToMetadataOperationBrowserEvent` hook for consuming metadata operation events filtered by metadata name and operation type - Rename `useListenToObjectRecordEventsForQuery` to `useListenToEventsForQuery`, now accepting both `RecordGqlOperationSignature` and `MetadataGqlOperationSignature` - Implement `useOnFrontComponentUpdated` which subscribes to front component metadata events and updates the Apollo cache when the component is modified - Add `builtComponentChecksum` to the front component query and appends it to the component URL for browser cache invalidation
55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import { type MetadataOperationBrowserEventDetail } from '@/browser-event/types/MetadataOperationBrowserEventDetail';
|
|
import { useApolloClient } from '@apollo/client';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import {
|
|
FindOneFrontComponentDocument,
|
|
type FindOneFrontComponentQuery,
|
|
type FrontComponent,
|
|
} from '~/generated-metadata/graphql';
|
|
|
|
type UseUpdateFrontComponentApolloCacheArgs = {
|
|
frontComponentId: string;
|
|
};
|
|
|
|
export const useUpdateFrontComponentApolloCache = ({
|
|
frontComponentId,
|
|
}: UseUpdateFrontComponentApolloCacheArgs) => {
|
|
const apolloClient = useApolloClient();
|
|
|
|
const updateFrontComponentApolloCache = (
|
|
detail: MetadataOperationBrowserEventDetail<FrontComponent>,
|
|
) => {
|
|
if (detail.operation.type !== 'update') {
|
|
return;
|
|
}
|
|
|
|
const { updatedRecord } = detail.operation;
|
|
|
|
if (!isDefined(updatedRecord) || updatedRecord.id !== frontComponentId) {
|
|
return;
|
|
}
|
|
|
|
apolloClient.cache.updateQuery<FindOneFrontComponentQuery>(
|
|
{
|
|
query: FindOneFrontComponentDocument,
|
|
variables: { id: frontComponentId },
|
|
},
|
|
(existingData) => {
|
|
if (!isDefined(existingData?.frontComponent)) {
|
|
return existingData;
|
|
}
|
|
|
|
return {
|
|
...existingData,
|
|
frontComponent: {
|
|
...existingData.frontComponent,
|
|
...updatedRecord,
|
|
},
|
|
};
|
|
},
|
|
);
|
|
};
|
|
|
|
return { updateFrontComponentApolloCache };
|
|
};
|