Files
twenty/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts
Baptiste Devessier 1115f6fc57 Automatically open pending form nodes in the side panel (#12332)
- Keep the side panel open when submitting a pending form node if the
history isn't empty
- Prevent the same pending Form step from being automatically opened
several times
- Prevent duplicated views of the same pending form in the side panel

> [!WARNING]
Switching from the side panel view to the full-screen view isn't robust,
and I used a hack to make one use case work here. We'll have to improve
that part later.

## Before


https://github.com/user-attachments/assets/0f830e87-7681-49e9-acc8-a08178f631a2

## After


https://github.com/user-attachments/assets/bfd742d6-e38e-4981-a93b-8e895d3aa38a
2025-05-28 18:17:22 +02:00

124 lines
4.8 KiB
TypeScript

import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { flowComponentState } from '@/workflow/states/flowComponentState';
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
import { WorkflowRun } from '@/workflow/types/Workflow';
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
const apolloClient = useApolloClient();
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
const { getIcon } = useIcons();
const runWorkflowRunOpeningInCommandMenuSideEffects = useRecoilCallback(
({ snapshot, set }) =>
({
objectMetadataItem,
recordId,
}: {
objectMetadataItem: ObjectMetadataItem;
recordId: string;
}) => {
const objectMetadataItems = getSnapshotValue(
snapshot,
objectMetadataItemsState,
);
const workflowRunRecord = getRecordFromCache<WorkflowRun>({
objectMetadataItem,
cache: apolloClient.cache,
recordId,
objectMetadataItems,
});
if (
!(isDefined(workflowRunRecord) && isDefined(workflowRunRecord.output))
) {
throw new Error(
`No workflow run record found for record ID ${recordId}`,
);
}
const { stepToOpenByDefault } = generateWorkflowRunDiagram({
steps: workflowRunRecord.output.flow.steps,
stepsOutput: workflowRunRecord.output.stepsOutput,
trigger: workflowRunRecord.output.flow.trigger,
});
if (!isDefined(stepToOpenByDefault)) {
return;
}
set(
workflowVisualizerWorkflowRunIdComponentState.atomFamily({
instanceId: getWorkflowVisualizerComponentInstanceId({
recordId,
}),
}),
workflowRunRecord.id,
);
set(
workflowVisualizerWorkflowIdComponentState.atomFamily({
instanceId: getWorkflowVisualizerComponentInstanceId({
recordId,
}),
}),
workflowRunRecord.workflowId,
);
set(
flowComponentState.atomFamily({
instanceId: getWorkflowVisualizerComponentInstanceId({
recordId,
}),
}),
{
workflowVersionId: workflowRunRecord.workflowVersionId,
trigger: workflowRunRecord.output.flow.trigger,
steps: workflowRunRecord.output.flow.steps,
},
);
set(
workflowSelectedNodeComponentState.atomFamily({
instanceId: getWorkflowVisualizerComponentInstanceId({
recordId,
}),
}),
stepToOpenByDefault.id,
);
set(
workflowRunDiagramAutomaticallyOpenedStepsComponentState.atomFamily({
instanceId: getWorkflowVisualizerComponentInstanceId({
recordId,
}),
}),
(steps) => [...steps, stepToOpenByDefault.id],
);
openWorkflowRunViewStepInCommandMenu({
workflowId: workflowRunRecord.workflowId,
workflowRunId: workflowRunRecord.id,
title: stepToOpenByDefault.data.name,
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
workflowSelectedNode: stepToOpenByDefault.id,
stepExecutionStatus: stepToOpenByDefault.data.runStatus,
});
},
[apolloClient.cache, getIcon, openWorkflowRunViewStepInCommandMenu],
);
return {
runWorkflowRunOpeningInCommandMenuSideEffects,
};
};