Files
twenty/packages/twenty-front/src/modules/workflow/utils/generateWorkflowDiagram.ts
Baptiste Devessier 31f03764d6 Improve the layout of the Workflow Visualizer (#8372)
- Increase the dimensions of the ReactFlow nodes. This allows to ditch
scaling which made it hard to get the width of the nodes as they were
visually scaled by 1.3.
- Center the flow when the flow mounts and when the state of the right
drawer opens.
- Put the node type inside of the node so it doesn't overlap with the
arrow
- Make the edges non deletable

We'll have to make a refactor so the viewport can be animated properly:
https://github.com/twentyhq/twenty/issues/8387.


https://github.com/user-attachments/assets/69494a32-5403-4898-be75-7fc38058e263

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-12 17:52:12 +01:00

124 lines
2.7 KiB
TypeScript

import { TRIGGER_STEP_ID } from '@/workflow/constants/TriggerStepId';
import { WorkflowStep, WorkflowTrigger } from '@/workflow/types/Workflow';
import {
WorkflowDiagram,
WorkflowDiagramEdge,
WorkflowDiagramNode,
} from '@/workflow/types/WorkflowDiagram';
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName';
import { MarkerType } from '@xyflow/react';
import { isDefined } from 'twenty-ui';
import { v4 } from 'uuid';
import { capitalize } from '~/utils/string/capitalize';
export const generateWorkflowDiagram = ({
trigger,
steps,
}: {
trigger: WorkflowTrigger | undefined;
steps: Array<WorkflowStep>;
}): WorkflowDiagram => {
const nodes: Array<WorkflowDiagramNode> = [];
const edges: Array<WorkflowDiagramEdge> = [];
// Helper function to generate nodes and edges recursively
const processNode = (
step: WorkflowStep,
parentNodeId: string,
xPos: number,
yPos: number,
) => {
const nodeId = step.id;
nodes.push({
id: nodeId,
data: {
nodeType: 'action',
actionType: step.type,
label: step.name,
},
position: {
x: xPos,
y: yPos,
},
});
// Create an edge from the parent node to this node
edges.push({
id: v4(),
source: parentNodeId,
target: nodeId,
markerEnd: {
type: MarkerType.ArrowClosed,
},
deletable: false,
});
return nodeId;
};
// Start with the trigger node
const triggerNodeId = TRIGGER_STEP_ID;
if (isDefined(trigger)) {
let triggerLabel: string;
switch (trigger.type) {
case 'MANUAL': {
triggerLabel = 'Manual Trigger';
break;
}
case 'DATABASE_EVENT': {
const triggerEvent = splitWorkflowTriggerEventName(
trigger.settings.eventName,
);
triggerLabel = `${capitalize(triggerEvent.objectType)} is ${capitalize(triggerEvent.event)}`;
break;
}
default: {
return assertUnreachable(
trigger,
`Expected the trigger "${JSON.stringify(trigger)}" to be supported.`,
);
}
}
nodes.push({
id: triggerNodeId,
data: {
nodeType: 'trigger',
triggerType: trigger.type,
label: triggerLabel,
},
position: {
x: 0,
y: 0,
},
});
} else {
nodes.push({
id: triggerNodeId,
type: 'empty-trigger',
data: {} as any,
position: {
x: 0,
y: 0,
},
});
}
let lastStepId = triggerNodeId;
for (const step of steps) {
lastStepId = processNode(step, lastStepId, 150, 100);
}
return {
nodes,
edges,
};
};