5d1208f8af
## Improvements - This PR calls `fitView` when the Reactflow component inits. It tries to fit the flow in a view with a fixed min and max zoom. - Every time the WorkflowDiagramCanvas is rendered for a different `workflowVersionId`, the `fitView` will be re-called. This is implemented with a React `key`. - The canvas will be re-rendered when an activated/deactivated version is updated (and a new draft version is created.) - It will also be re-rendered when the user selects another workflow version and this doesn't cause the `WorkflowDiagramCanvas` component to unmount. It happens if the user wants to go the previous or next workflow or workflow version. ## Previous Behavior  ## New Behavior  https://github.com/user-attachments/assets/cb73f456-58b1-49c3-bd31-a1650810e9dd ## Notes Closes #7047 This PR is a simplification of #7151. We'll have to improve the way we manage zoom in another PR.
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import { WorkflowDiagramCanvasEffect } from '@/workflow/components/WorkflowDiagramCanvasEffect';
|
|
import { WorkflowDiagramCreateStepNode } from '@/workflow/components/WorkflowDiagramCreateStepNode';
|
|
import { WorkflowDiagramEmptyTrigger } from '@/workflow/components/WorkflowDiagramEmptyTrigger';
|
|
import { WorkflowDiagramStepNode } from '@/workflow/components/WorkflowDiagramStepNode';
|
|
import { WorkflowVersionStatusTag } from '@/workflow/components/WorkflowVersionStatusTag';
|
|
import { workflowDiagramState } from '@/workflow/states/workflowDiagramState';
|
|
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
|
import {
|
|
WorkflowDiagram,
|
|
WorkflowDiagramEdge,
|
|
WorkflowDiagramNode,
|
|
} from '@/workflow/types/WorkflowDiagram';
|
|
import { getOrganizedDiagram } from '@/workflow/utils/getOrganizedDiagram';
|
|
import styled from '@emotion/styled';
|
|
import {
|
|
applyEdgeChanges,
|
|
applyNodeChanges,
|
|
Background,
|
|
EdgeChange,
|
|
FitViewOptions,
|
|
NodeChange,
|
|
ReactFlow,
|
|
} from '@xyflow/react';
|
|
import '@xyflow/react/dist/style.css';
|
|
import { useMemo } from 'react';
|
|
import { useSetRecoilState } from 'recoil';
|
|
import { GRAY_SCALE, isDefined } from 'twenty-ui';
|
|
|
|
const StyledStatusTagContainer = styled.div`
|
|
left: 0;
|
|
top: 0;
|
|
position: absolute;
|
|
padding: ${({ theme }) => theme.spacing(2)};
|
|
`;
|
|
|
|
const defaultFitViewOptions: FitViewOptions = {
|
|
minZoom: 1.3,
|
|
maxZoom: 1.3,
|
|
};
|
|
|
|
export const WorkflowDiagramCanvas = ({
|
|
diagram,
|
|
workflowWithCurrentVersion,
|
|
}: {
|
|
diagram: WorkflowDiagram;
|
|
workflowWithCurrentVersion: WorkflowWithCurrentVersion;
|
|
}) => {
|
|
const { nodes, edges } = useMemo(
|
|
() => getOrganizedDiagram(diagram),
|
|
[diagram],
|
|
);
|
|
|
|
const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
|
|
|
|
const handleNodesChange = (
|
|
nodeChanges: Array<NodeChange<WorkflowDiagramNode>>,
|
|
) => {
|
|
setWorkflowDiagram((diagram) => {
|
|
if (isDefined(diagram) === false) {
|
|
throw new Error(
|
|
'It must be impossible for the nodes to be updated if the diagram is not defined yet. Be sure the diagram is rendered only when defined.',
|
|
);
|
|
}
|
|
|
|
return {
|
|
...diagram,
|
|
nodes: applyNodeChanges(nodeChanges, diagram.nodes),
|
|
};
|
|
});
|
|
};
|
|
|
|
const handleEdgesChange = (
|
|
edgeChanges: Array<EdgeChange<WorkflowDiagramEdge>>,
|
|
) => {
|
|
setWorkflowDiagram((diagram) => {
|
|
if (isDefined(diagram) === false) {
|
|
throw new Error(
|
|
'It must be impossible for the edges to be updated if the diagram is not defined yet. Be sure the diagram is rendered only when defined.',
|
|
);
|
|
}
|
|
|
|
return {
|
|
...diagram,
|
|
edges: applyEdgeChanges(edgeChanges, diagram.edges),
|
|
};
|
|
});
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<ReactFlow
|
|
key={workflowWithCurrentVersion.currentVersion.id}
|
|
onInit={({ fitView }) => {
|
|
fitView(defaultFitViewOptions);
|
|
}}
|
|
nodeTypes={{
|
|
default: WorkflowDiagramStepNode,
|
|
'create-step': WorkflowDiagramCreateStepNode,
|
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
|
}}
|
|
fitView
|
|
nodes={nodes.map((node) => ({ ...node, draggable: false }))}
|
|
edges={edges}
|
|
onNodesChange={handleNodesChange}
|
|
onEdgesChange={handleEdgesChange}
|
|
>
|
|
<WorkflowDiagramCanvasEffect />
|
|
|
|
<Background color={GRAY_SCALE.gray25} size={2} />
|
|
</ReactFlow>
|
|
|
|
<StyledStatusTagContainer>
|
|
<WorkflowVersionStatusTag
|
|
versionStatus={workflowWithCurrentVersion.currentVersion.status}
|
|
/>
|
|
</StyledStatusTagContainer>
|
|
</>
|
|
);
|
|
};
|