Use optimistic rendering when executing a workflow with manual trigger (#12695)
This PR adds optimistic rendering at two places: - In the `runWorkflowVersion`, to create a workflow run entry as fast as possible in the cache and render it immediately in the side panel. - In the `ListenUpdatesEffect`, to be sure the cache is properly set; we also need to set the record in the record store that's used in the fields card. ## Before https://github.com/user-attachments/assets/8b360ea9-c292-4e05-82a0-d2f12176bb6f ## After https://github.com/user-attachments/assets/2d11023c-2ceb-4fa3-a951-187b9a0b5743 ### With a slowed-down network https://github.com/user-attachments/assets/7d2a592a-1ea7-455b-856f-bf3d9d905061 ## Follow up I will create next a PR to ensure the viewport is always set when we know the dimensions of the nodes.
This commit is contained in:
committed by
GitHub
parent
a6b8830b91
commit
dae282ca0f
@ -49,9 +49,7 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
|
||||
if (
|
||||
!(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.output))
|
||||
) {
|
||||
throw new Error(
|
||||
`No workflow run record found for record ID ${recordId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const { stepToOpenByDefault } = generateWorkflowRunDiagram({
|
||||
|
||||
@ -1,9 +1,24 @@
|
||||
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useLazyFindOneRecord } from '@/object-record/hooks/useLazyFindOneRecord';
|
||||
import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache';
|
||||
import { useUpsertFindOneRecordQueryInCache } from '@/object-record/cache/hooks/useUpsertFindOneRecordQueryInCache';
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { computeOptimisticCreateRecordBaseRecordInput } from '@/object-record/utils/computeOptimisticCreateRecordBaseRecordInput';
|
||||
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
|
||||
import { RUN_WORKFLOW_VERSION } from '@/workflow/graphql/mutations/runWorkflowVersion';
|
||||
import { WorkflowRun } from '@/workflow/types/Workflow';
|
||||
import { useApolloClient, useMutation } from '@apollo/client';
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
RunWorkflowVersionMutation,
|
||||
RunWorkflowVersionMutationVariables,
|
||||
@ -11,6 +26,18 @@ import {
|
||||
|
||||
export const useRunWorkflowVersion = () => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||
});
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
const createOneRecordInCache = useCreateOneRecordInCache<WorkflowRun>({
|
||||
objectMetadataItem,
|
||||
});
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const [mutate] = useMutation<
|
||||
RunWorkflowVersionMutation,
|
||||
RunWorkflowVersionMutationVariables
|
||||
@ -18,34 +45,100 @@ export const useRunWorkflowVersion = () => {
|
||||
client: apolloClient,
|
||||
});
|
||||
|
||||
const { findOneRecord: findOneWorkflowRun } =
|
||||
useLazyFindOneRecord<WorkflowRun>({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||
const computedRecordGqlFields = generateDepthOneRecordGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const { upsertFindOneRecordQueryInCache } =
|
||||
useUpsertFindOneRecordQueryInCache({
|
||||
objectMetadataItem,
|
||||
recordGqlFields: computedRecordGqlFields,
|
||||
});
|
||||
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const setRecordInStore = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(workflowRun: WorkflowRun) => {
|
||||
set(recordStoreFamilyState(workflowRun.id), workflowRun);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const runWorkflowVersion = async ({
|
||||
workflowId,
|
||||
workflowVersionId,
|
||||
payload,
|
||||
}: {
|
||||
workflowId: string;
|
||||
workflowVersionId: string;
|
||||
payload?: Record<string, any>;
|
||||
}) => {
|
||||
const { data } = await mutate({
|
||||
variables: { input: { workflowVersionId, payload } },
|
||||
const workflowRunId = v4();
|
||||
|
||||
const recordInput: Partial<WorkflowRun> = {
|
||||
name: '#0',
|
||||
status: 'NOT_STARTED',
|
||||
output: null,
|
||||
context: null,
|
||||
workflowVersionId,
|
||||
workflowId,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const optimisticRecordInput = computeOptimisticRecordFromInput({
|
||||
cache: apolloClient.cache,
|
||||
currentWorkspaceMember: currentWorkspaceMember,
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
recordInput: {
|
||||
...computeOptimisticCreateRecordBaseRecordInput(objectMetadataItem),
|
||||
...recordInput,
|
||||
id: workflowRunId,
|
||||
},
|
||||
objectPermissionsByObjectMetadataId,
|
||||
});
|
||||
|
||||
const workflowRunId = data?.runWorkflowVersion?.workflowRunId;
|
||||
const recordCreatedInCache = createOneRecordInCache({
|
||||
...optimisticRecordInput,
|
||||
id: workflowRunId,
|
||||
__typename: getObjectTypename(objectMetadataItem.nameSingular),
|
||||
});
|
||||
|
||||
await findOneWorkflowRun({
|
||||
const recordNodeCreatedInCache = getRecordNodeFromRecord({
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
record: recordCreatedInCache,
|
||||
computeReferences: false,
|
||||
});
|
||||
|
||||
if (!isDefined(recordNodeCreatedInCache)) {
|
||||
throw new Error('The record should have been created in cache');
|
||||
}
|
||||
|
||||
upsertFindOneRecordQueryInCache({
|
||||
objectRecordToOverwrite: recordCreatedInCache,
|
||||
objectRecordId: workflowRunId,
|
||||
onCompleted: (workflowRun) => {
|
||||
openRecordInCommandMenu({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||
recordId: workflowRun.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
triggerCreateRecordsOptimisticEffect({
|
||||
cache: apolloClient.cache,
|
||||
objectMetadataItem,
|
||||
recordsToCreate: [recordNodeCreatedInCache],
|
||||
objectMetadataItems,
|
||||
shouldMatchRootQueryFilter: true,
|
||||
objectPermissionsByObjectMetadataId,
|
||||
});
|
||||
|
||||
setRecordInStore(recordCreatedInCache);
|
||||
|
||||
openRecordInCommandMenu({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowRun,
|
||||
recordId: workflowRunId,
|
||||
});
|
||||
|
||||
await mutate({
|
||||
variables: { input: { workflowVersionId, workflowRunId, payload } },
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user