Improve workflow arrows' design (#9619)

Old design:

![CleanShot_2024-11-12_at_17 37
33](https://github.com/user-attachments/assets/1fcaba6d-f23c-4679-b038-d051abeb0bbd)


New design:

![CleanShot 2025-01-14 at 18 22
10@2x](https://github.com/user-attachments/assets/a683163d-2e3c-42ed-8abd-1f1fd31bf7db)
This commit is contained in:
Baptiste Devessier
2025-01-14 22:38:44 +01:00
committed by GitHub
parent f2bee55e6c
commit c543a930cd
8 changed files with 66 additions and 19 deletions

View File

@ -48,7 +48,7 @@ const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
position: relative;
box-shadow: ${({ variant, theme }) =>
variant === 'placeholder' ? 'none' : theme.boxShadow.superHeavy};
variant === 'placeholder' ? 'none' : theme.boxShadow.strong};
.selectable.selected &,
.selectable:focus &,
@ -63,7 +63,7 @@ const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
display: flex;
font-size: ${({ theme }) => theme.font.size.lg};
font-weight: ${({ theme }) => theme.font.weight.medium};
column-gap: ${({ theme }) => theme.spacing(3)};
column-gap: ${({ theme }) => theme.spacing(2)};
color: ${({ variant, theme }) =>
variant === 'placeholder'
? theme.font.color.extraLight
@ -72,7 +72,10 @@ const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
`;
const StyledSourceHandle = styled(Handle)`
background-color: ${({ theme }) => theme.color.gray50};
background-color: ${({ theme }) => theme.grayScale.gray25};
border: none;
width: 4px;
height: 4px;
`;
export const StyledTargetHandle = styled(Handle)`

View File

@ -1,6 +1,7 @@
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { useListenRightDrawerClose } from '@/ui/layout/right-drawer/hooks/useListenRightDrawerClose';
import { WorkflowVersionStatus } from '@/workflow/types/Workflow';
import { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/components/WorkflowDiagramCustomMarkers';
import { WorkflowVersionStatusTag } from '@/workflow/workflow-diagram/components/WorkflowVersionStatusTag';
import { useRightDrawerState } from '@/workflow/workflow-diagram/hooks/useRightDrawerState';
import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
@ -46,6 +47,14 @@ const StyledResetReactflowStyles = styled.div`
white-space: nowrap;
}
.react-flow__handle {
min-height: 0;
min-width: 0;
}
.react-flow__handle.connectionindicator {
cursor: pointer;
}
--xy-node-border-radius: none;
--xy-node-border: none;
--xy-node-background-color: none;
@ -182,6 +191,8 @@ export const WorkflowDiagramCanvasBase = ({
return (
<StyledResetReactflowStyles ref={containerRef}>
<WorkflowDiagramCustomMarkers />
<ReactFlow
ref={(node) => {
if (isDefined(node)) {
@ -214,6 +225,7 @@ export const WorkflowDiagramCanvasBase = ({
edgesFocusable={false}
nodesDraggable={false}
onPaneClick={closeCommandMenu}
nodesConnectable={false}
paneClickDistance={10} // Fix small unwanted user dragging does not select node
>
<Background color={theme.border.color.medium} size={2} />

View File

@ -2,16 +2,20 @@ import styled from '@emotion/styled';
import { Handle, Position } from '@xyflow/react';
import { IconButton, IconPlus } from 'twenty-ui';
const StyledContainer = styled.div`
padding-top: ${({ theme }) => theme.spacing(1)};
`;
export const StyledTargetHandle = styled(Handle)`
visibility: hidden;
`;
export const WorkflowDiagramCreateStepNode = () => {
return (
<>
<StyledContainer>
<StyledTargetHandle type="target" position={Position.Top} />
<IconButton Icon={IconPlus} size="medium" />
</>
</StyledContainer>
);
};

View File

@ -0,0 +1,25 @@
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
import { useTheme } from '@emotion/react';
export const WorkflowDiagramCustomMarkers = () => {
const theme = useTheme();
return (
<svg style={{ position: 'absolute', top: 0, left: 0 }}>
<defs>
<marker
id={EDGE_ROUNDED_ARROW_MARKER_ID}
markerHeight={5}
markerWidth={6}
refX={3}
refY={2.5}
>
<path
d="M0.31094 1.1168C0.178029 0.917434 0.320947 0.650391 0.560555 0.650391H5.43945C5.67905 0.650391 5.82197 0.917434 5.68906 1.1168L3.62404 4.21433C3.32717 4.65963 2.67283 4.65963 2.37596 4.21433L0.31094 1.1168Z"
fill={theme.grayScale.gray25}
/>
</marker>
</defs>
</svg>
);
};

View File

@ -0,0 +1 @@
export const EDGE_ROUNDED_ARROW_MARKER_ID = 'arrow-rounded';

View File

@ -0,0 +1,12 @@
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { THEME_COMMON } from 'twenty-ui';
export const WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION = {
markerEnd: EDGE_ROUNDED_ARROW_MARKER_ID,
style: {
stroke: THEME_COMMON.grayScale.gray25,
},
deletable: false,
selectable: false,
} satisfies Partial<WorkflowDiagramEdge>;

View File

@ -1,9 +1,9 @@
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeDefaultConfiguration';
import {
WorkflowDiagram,
WorkflowDiagramEdge,
WorkflowDiagramNode,
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { MarkerType } from '@xyflow/react';
import { v4 } from 'uuid';
export const addCreateStepNodes = ({ nodes, edges }: WorkflowDiagram) => {
@ -30,13 +30,10 @@ export const addCreateStepNodes = ({ nodes, edges }: WorkflowDiagram) => {
updatedNodes.push(newCreateStepNode);
updatedEdges.push({
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
id: v4(),
source: node.id,
target: newCreateStepNode.id,
markerEnd: {
type: MarkerType.ArrowClosed,
},
deletable: false,
});
}

View File

@ -1,6 +1,7 @@
import { WorkflowStep, WorkflowTrigger } from '@/workflow/types/Workflow';
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName';
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeDefaultConfiguration';
import {
WorkflowDiagram,
WorkflowDiagramEdge,
@ -8,7 +9,6 @@ import {
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
import { MarkerType } from '@xyflow/react';
import { capitalize } from 'twenty-shared';
import { isDefined } from 'twenty-ui';
import { v4 } from 'uuid';
@ -23,7 +23,6 @@ export const generateWorkflowDiagram = ({
const nodes: Array<WorkflowDiagramNode> = [];
const edges: Array<WorkflowDiagramEdge> = [];
// Helper function to generate nodes and edges recursively
const processNode = (
step: WorkflowStep,
parentNodeId: string,
@ -45,22 +44,16 @@ export const generateWorkflowDiagram = ({
},
});
// Create an edge from the parent node to this node
edges.push({
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
id: v4(),
source: parentNodeId,
target: nodeId,
markerEnd: {
type: MarkerType.ArrowClosed,
},
deletable: false,
selectable: false,
});
return nodeId;
};
// Start with the trigger node
const triggerNodeId = TRIGGER_STEP_ID;
if (isDefined(trigger)) {