965 flow control arrow menu 1/3 add insert step button (#12519)

Add insert step button to workflow edges



https://github.com/user-attachments/assets/7144f722-f1c7-450f-a8eb-c902071986a1



Also fixes `iconButtonGroup` UI component

## Before


https://github.com/user-attachments/assets/7b5f0245-d0e8-48af-9aa5-a29388a1caea


## After



https://github.com/user-attachments/assets/1820874f-aa99-41ae-8254-c76c275ee3ae
This commit is contained in:
martmull
2025-06-12 14:14:21 +02:00
committed by GitHub
parent a189f15313
commit cf01faf276
31 changed files with 755 additions and 291 deletions
@@ -1,5 +1,5 @@
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
import { renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
@@ -33,10 +33,10 @@ const wrapper = ({ children }: { children: React.ReactNode }) => {
<RecoilRoot
initializeState={({ set }) => {
set(
workflowCreateStepFromParentStepIdComponentState.atomFamily({
workflowInsertStepIdsComponentState.atomFamily({
instanceId: workflowVisualizerComponentInstanceId,
}),
'parent-step-id',
{ parentStepId: 'parent-step-id', nextStepId: undefined },
);
}}
>
@@ -8,7 +8,7 @@ import {
} from '@/workflow/types/Workflow';
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useCreateStep = ({
@@ -24,15 +24,17 @@ export const useCreateStep = ({
workflowLastCreatedStepIdComponentState,
);
const workflowCreateStepFromParentStepId = useRecoilComponentValueV2(
workflowCreateStepFromParentStepIdComponentState,
const workflowInsertStepIds = useRecoilComponentValueV2(
workflowInsertStepIdsComponentState,
);
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
const createStep = async (newStepType: WorkflowStepType) => {
if (!isDefined(workflowCreateStepFromParentStepId)) {
throw new Error('Select a step to create a new step from first.');
if (!isDefined(workflowInsertStepIds.parentStepId)) {
throw new Error(
'No parentStepId. Please select a parent step to create from.',
);
}
const workflowVersionId = await getUpdatableWorkflowVersion(workflow);
@@ -41,8 +43,8 @@ export const useCreateStep = ({
await createWorkflowVersionStep({
workflowVersionId,
stepType: newStepType,
parentStepId: workflowCreateStepFromParentStepId,
nextStepId: undefined,
parentStepId: workflowInsertStepIds.parentStepId,
nextStepId: workflowInsertStepIds.nextStepId,
})
)?.data?.createWorkflowVersionStep;
@@ -37,8 +37,9 @@ export const useCreateWorkflowVersionStep = () => {
variables: { input },
});
const createdStep = result?.data?.createWorkflowVersionStep;
if (!isDefined(createdStep)) {
const insertedStep = result?.data?.createWorkflowVersionStep;
if (!isDefined(insertedStep)) {
return;
}
@@ -50,20 +51,29 @@ export const useCreateWorkflowVersionStep = () => {
return;
}
const { parentStepId, nextStepId } = input;
const updatedExistingSteps =
cachedRecord.steps?.map((step) => {
if (step.id === input.parentStepId) {
cachedRecord.steps?.map((existingStep) => {
if (existingStep.id === parentStepId) {
return {
...step,
nextStepIds: [...(step.nextStepIds || []), createdStep.id],
...existingStep,
nextStepIds: [
...new Set([
...(existingStep.nextStepIds?.filter(
(id) => id !== nextStepId,
) || []),
insertedStep.id,
]),
],
};
}
return step;
return existingStep;
}) ?? [];
const newCachedRecord = {
...cachedRecord,
steps: [...updatedExistingSteps, createdStep],
steps: [...updatedExistingSteps, insertedStep],
};
const recordGqlFields = {