Files
twenty/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramCanvas.tsx
T
Baptiste Devessier 5d1208f8af Set default zoom to workflows (#7331)
## 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

![CleanShot 2024-09-30 at 10 32
06@2x](https://github.com/user-attachments/assets/ea43cd43-8c9c-491c-a535-8cca9168fb22)

## New Behavior

![CleanShot 2024-09-30 at 10 26
47@2x](https://github.com/user-attachments/assets/7bfb91b2-1782-47a1-ab5a-3eaa9f1be923)


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.
2024-09-30 11:24:57 +02:00

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>
</>
);
};