martmull
2025-08-25 15:14:05 +02:00
committed by GitHub
parent 9f16b13843
commit 97e5f06ff9
18 changed files with 243 additions and 122 deletions
@@ -1,7 +1,7 @@
import { useTheme } from '@emotion/react';
import { BaseEdge, type EdgeProps } from '@xyflow/react';
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { useEdgeSelected } from '@/workflow/workflow-diagram/hooks/useEdgeSelected';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
type WorkflowDiagramBaseEdgeProps = Pick<
EdgeProps<WorkflowDiagramEdge>,
@@ -19,11 +19,17 @@ export const WorkflowDiagramBaseEdge = ({
}: WorkflowDiagramBaseEdgeProps) => {
const theme = useTheme();
const { isEdgeSelected } = useEdgeSelected();
const { isEdgeSelected, isEdgeHovered } = useEdgeState();
const selected = isEdgeSelected({ source, target });
const stroke = selected ? theme.color.blue : theme.border.color.strong;
const isHovered = isEdgeHovered({ source, target });
const stroke = selected
? theme.color.blue
: isHovered
? theme.font.color.light
: theme.border.color.strong;
return (
<BaseEdge
@@ -7,7 +7,6 @@ import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/components/WorkflowDiagramCustomMarkers';
import { WorkflowDiagramRightClickCommandMenu } from '@/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu';
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
import { useRightDrawerState } from '@/workflow/workflow-diagram/hooks/useRightDrawerState';
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
@@ -55,6 +54,7 @@ import { isDefined } from 'twenty-shared/utils';
import { Tag, type TagColor } from 'twenty-ui/components';
import { THEME_COMMON } from 'twenty-ui/theme';
import { FeatureFlagKey } from '~/generated/graphql';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
const StyledResetReactflowStyles = styled.div`
height: 100%;
@@ -178,7 +178,7 @@ export const WorkflowDiagramCanvasBase = ({
workflowDiagramWaitingNodesDimensionsComponentState,
);
const { setEdgeHovered, setNoEdgeHovered } = useEdgeHovered();
const { setEdgeHovered, clearEdgeHover } = useEdgeState();
const isWorkflowBranchEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_WORKFLOW_BRANCH_ENABLED,
@@ -444,15 +444,21 @@ export const WorkflowDiagramCanvasBase = ({
);
const onEdgeMouseEnter = useCallback(
(_: React.MouseEvent<Element, MouseEvent>, edge: WorkflowDiagramEdge) => {
setEdgeHovered(edge.id);
(
_: React.MouseEvent<Element, MouseEvent>,
hoveredEdge: WorkflowDiagramEdge,
) => {
setEdgeHovered({
source: hoveredEdge.source,
target: hoveredEdge.target,
});
},
[setEdgeHovered],
);
const onEdgeMouseLeave = useCallback(() => {
setNoEdgeHovered();
}, [setNoEdgeHovered]);
clearEdgeHover();
}, [clearEdgeHover]);
return (
<StyledResetReactflowStyles ref={containerRef}>
@@ -1,4 +1,4 @@
import { useEdgeSelected } from '@/workflow/workflow-diagram/hooks/useEdgeSelected';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import {
type OnSelectionChangeParams,
@@ -9,7 +9,7 @@ import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey } from '~/generated/graphql';
export const WorkflowDiagramCanvasEditableEffect = () => {
const { setEdgeSelected, clearEdgeSelection } = useEdgeSelected();
const { setEdgeSelected, clearEdgeSelected } = useEdgeState();
const isWorkflowBranchEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_WORKFLOW_BRANCH_ENABLED,
@@ -24,7 +24,8 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
const selectedEdge = edges?.[0];
if (!isDefined(selectedEdge)) {
clearEdgeSelection();
clearEdgeSelected();
return;
}
@@ -33,7 +34,7 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
target: selectedEdge.target,
});
},
[isWorkflowBranchEnabled, setEdgeSelected, clearEdgeSelection],
[isWorkflowBranchEnabled, setEdgeSelected, clearEdgeSelected],
);
useOnSelectionChange({
@@ -1,4 +1,4 @@
import { EDGE_BRANCH_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeBranchArrowMarkerId';
import { EdgeBranchArrowMarker } from '@/workflow/workflow-diagram/constants/EdgeBranchArrowMarker';
import { useTheme } from '@emotion/react';
export const WorkflowDiagramCustomMarkers = () => {
@@ -8,7 +8,7 @@ export const WorkflowDiagramCustomMarkers = () => {
<svg style={{ position: 'absolute', top: 0, left: 0 }}>
<defs>
<marker
id={EDGE_BRANCH_ARROW_MARKER_ID}
id={EdgeBranchArrowMarker.Default}
markerHeight={8}
markerWidth={10}
refX={5}
@@ -20,6 +20,34 @@ export const WorkflowDiagramCustomMarkers = () => {
fill={theme.background.primary}
/>
</marker>
<marker
id={EdgeBranchArrowMarker.Hover}
markerHeight={8}
markerWidth={10}
refX={5}
refY={4}
>
<path
d="M1.7915 1.38672H8.18311C8.57541 1.38705 8.81458 1.81852 8.60693 2.15137L5.41064 7.26465C5.21481 7.57798 4.75882 7.57798 4.56299 7.26465L1.3667 2.15137C1.15906 1.81841 1.39896 1.38672 1.7915 1.38672Z"
stroke={theme.font.color.light}
fill={theme.background.primary}
/>
</marker>
<marker
id={EdgeBranchArrowMarker.Selected}
markerHeight={8}
markerWidth={10}
refX={5}
refY={4}
>
<path
d="M1.7915 1.38672H8.18311C8.57541 1.38705 8.81458 1.81852 8.60693 2.15137L5.41064 7.26465C5.21481 7.57798 4.75882 7.57798 4.56299 7.26465L1.3667 2.15137C1.15906 1.81841 1.39896 1.38672 1.7915 1.38672Z"
stroke={theme.color.blue}
fill={theme.background.primary}
/>
</marker>
</defs>
</svg>
);
@@ -8,7 +8,6 @@ import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/comp
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
@@ -25,11 +24,11 @@ import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconFilter, IconPlus, IconTrash } from 'twenty-ui/display';
import { FeatureFlagKey } from '~/generated/graphql';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
type WorkflowDiagramDefaultEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
export const WorkflowDiagramDefaultEdgeEditable = ({
id,
source,
target,
sourceX,
@@ -45,7 +44,7 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
const { isInRightDrawer } = useContext(ActionMenuContext);
const { isEdgeHovered } = useEdgeHovered();
const { isEdgeHovered } = useEdgeState();
const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
@@ -129,7 +128,9 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
labelY={labelY}
>
<WorkflowDiagramEdgeV2VisibilityContainer
shouldDisplay={nodeCreationStarted || isEdgeHovered(id)}
shouldDisplay={
nodeCreationStarted || isEdgeHovered({ source, target })
}
>
<WorkflowDiagramEdgeButtonGroup
iconButtons={[
@@ -0,0 +1,5 @@
export enum EdgeBranchArrowMarker {
Default = 'edge-branch-arrow-default',
Hover = 'edge-branch-arrow-hover',
Selected = 'edge-branch-arrow-selected',
}
@@ -1 +0,0 @@
export const EDGE_BRANCH_ARROW_MARKER_ID = 'workflow-edge-branch-arrow';
@@ -1,4 +1,4 @@
import { EDGE_BRANCH_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeBranchArrowMarkerId';
import { EdgeBranchArrowMarker } from '@/workflow/workflow-diagram/constants/EdgeBranchArrowMarker';
import {
type WorkflowDiagramEdge,
type WorkflowDiagramEdgeType,
@@ -7,7 +7,7 @@ import {
export const WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION = {
type: 'empty-filter--readonly' satisfies WorkflowDiagramEdgeType,
markerStart: undefined,
markerEnd: EDGE_BRANCH_ARROW_MARKER_ID,
markerEnd: EdgeBranchArrowMarker.Default,
deletable: false,
selectable: false,
data: {
@@ -1,25 +0,0 @@
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { workflowHoveredEdgeIdComponentState } from '@/workflow/workflow-diagram/states/workflowHoveredEdgeIdComponentState';
export const useEdgeHovered = () => {
const [workflowHoveredEdgeId, setWorkflowHoveredEdgeId] =
useRecoilComponentState(workflowHoveredEdgeIdComponentState);
const isEdgeHovered = (edgeId: string) => {
return workflowHoveredEdgeId === edgeId;
};
const setEdgeHovered = (edgeId: string) => {
setWorkflowHoveredEdgeId(edgeId);
};
const setNoEdgeHovered = () => {
setWorkflowHoveredEdgeId(undefined);
};
return {
isEdgeHovered,
setEdgeHovered,
setNoEdgeHovered,
};
};
@@ -1,47 +0,0 @@
import { workflowSelectedEdgeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedEdgeComponentState';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { type WorkflowDiagramHandlesSelected } from '@/workflow/workflow-diagram/types/WorkflowDiagramHandlesSelected';
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge';
export const useEdgeSelected = () => {
const [workflowSelectedEdge, setWorkflowSelectedEdge] =
useRecoilComponentState(workflowSelectedEdgeComponentState);
const isEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
return (
workflowSelectedEdge?.source === source &&
workflowSelectedEdge?.target === target
);
};
const getNodeHandlesSelectedState = (
id: string,
): WorkflowDiagramHandlesSelected => {
return {
targetHandle: workflowSelectedEdge?.target === id,
sourceHandle: workflowSelectedEdge?.source === id,
};
};
const setEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
if (
workflowSelectedEdge?.source === source &&
workflowSelectedEdge?.target === target
) {
return;
}
setWorkflowSelectedEdge({ source, target });
};
const clearEdgeSelection = () => {
setWorkflowSelectedEdge(undefined);
};
return {
isEdgeSelected,
setEdgeSelected,
clearEdgeSelection,
getNodeHandlesSelectedState,
};
};
@@ -0,0 +1,132 @@
import { workflowSelectedEdgeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedEdgeComponentState';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { type WorkflowDiagramNodeHandles } from '@/workflow/workflow-diagram/types/WorkflowDiagramNodeHandles';
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge';
import { workflowHoveredEdgeComponentState } from '@/workflow/workflow-diagram/states/workflowHoveredEdgeComponentState';
import { useReactFlow } from '@xyflow/react';
import { EdgeBranchArrowMarker } from '@/workflow/workflow-diagram/constants/EdgeBranchArrowMarker';
export const useEdgeState = () => {
const reactflow = useReactFlow();
const [workflowSelectedEdge, setWorkflowSelectedEdge] =
useRecoilComponentState(workflowSelectedEdgeComponentState);
const [workflowHoveredEdge, setWorkflowHoveredEdge] = useRecoilComponentState(
workflowHoveredEdgeComponentState,
);
const isEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
return (
workflowSelectedEdge?.source === source &&
workflowSelectedEdge?.target === target
);
};
const isEdgeHovered = ({ source, target }: WorkflowDiagramEdge) => {
return (
workflowHoveredEdge?.source === source &&
workflowHoveredEdge?.target === target
);
};
const getNodeHandlesSelectedState = (
id: string,
): WorkflowDiagramNodeHandles => {
return {
targetHandle: workflowSelectedEdge?.target === id,
sourceHandle: workflowSelectedEdge?.source === id,
};
};
const getNodeHandlesHoveredState = (
id: string,
): WorkflowDiagramNodeHandles => {
return {
targetHandle: workflowHoveredEdge?.target === id,
sourceHandle: workflowHoveredEdge?.source === id,
};
};
const setEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
if (
workflowSelectedEdge?.source === source &&
workflowSelectedEdge?.target === target
) {
return;
}
setWorkflowSelectedEdge({ source, target });
reactflow.setEdges((edges) =>
edges.map((edge) => ({
...edge,
markerEnd:
edge.source === source && edge.target === target
? EdgeBranchArrowMarker.Selected
: EdgeBranchArrowMarker.Default,
})),
);
};
const setEdgeHovered = ({ source, target }: WorkflowDiagramEdge) => {
if (
workflowHoveredEdge?.source === source &&
workflowHoveredEdge?.target === target
) {
return;
}
setWorkflowHoveredEdge({ source, target });
reactflow.setEdges((edges) =>
edges.map((edge) =>
edge.source === source &&
edge.target === target &&
edge.markerEnd !== EdgeBranchArrowMarker.Selected
? {
...edge,
markerEnd: EdgeBranchArrowMarker.Hover,
}
: edge,
),
);
};
const clearEdgeSelected = () => {
setWorkflowSelectedEdge(undefined);
reactflow.setEdges((edges) =>
edges.map((edge) => ({
...edge,
markerEnd: EdgeBranchArrowMarker.Default,
})),
);
};
const clearEdgeHover = () => {
setWorkflowHoveredEdge(undefined);
reactflow.setEdges((edges) =>
edges.map((edge) =>
edge.markerEnd === EdgeBranchArrowMarker.Hover
? {
...edge,
markerEnd: EdgeBranchArrowMarker.Default,
}
: edge,
),
);
};
return {
isEdgeSelected,
setEdgeSelected,
clearEdgeSelected,
getNodeHandlesSelectedState,
isEdgeHovered,
setEdgeHovered,
clearEdgeHover,
getNodeHandlesHoveredState,
};
};
@@ -1,10 +1,11 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import type { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagramEdge';
export const workflowHoveredEdgeIdComponentState = createComponentState<
string | undefined
export const workflowHoveredEdgeComponentState = createComponentState<
WorkflowDiagramEdge | undefined
>({
key: 'workflowHoveredEdgeIdComponentState',
key: 'workflowHoveredEdgeComponentState',
defaultValue: undefined,
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
});
@@ -1,4 +1,4 @@
export type WorkflowDiagramHandlesSelected = {
export type WorkflowDiagramNodeHandles = {
targetHandle: boolean;
sourceHandle: boolean;
};
@@ -119,7 +119,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-0",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "trigger",
@@ -133,7 +133,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-1",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step1",
@@ -147,7 +147,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-2",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step2",
@@ -349,7 +349,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-3",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "trigger",
@@ -363,7 +363,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-4",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step1",
@@ -377,7 +377,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-5",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step2",
@@ -579,7 +579,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-6",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "trigger",
@@ -593,7 +593,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-7",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step1",
@@ -607,7 +607,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-8",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step2",
@@ -828,7 +828,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-9",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "trigger",
@@ -842,7 +842,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-10",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step1",
@@ -856,7 +856,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-11",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step2",
@@ -870,7 +870,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-12",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "step3",
@@ -1057,7 +1057,7 @@ describe('generateWorkflowRunDiagram', () => {
},
"deletable": false,
"id": "8f3b2121-f194-4ba4-9fbf-13",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": false,
"source": "trigger",
@@ -157,7 +157,7 @@ describe('getWorkflowVersionDiagram', () => {
},
"deletable": true,
"id": "8f3b2121-f194-4ba4-9fbf-0",
"markerEnd": "workflow-edge-branch-arrow",
"markerEnd": "edge-branch-arrow-default",
"markerStart": undefined,
"selectable": true,
"source": "trigger",
@@ -14,7 +14,6 @@ import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/comp
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
@@ -48,6 +47,7 @@ import {
import { IconButtonGroup } from 'twenty-ui/input';
import { MenuItem } from 'twenty-ui/navigation';
import { FeatureFlagKey } from '~/generated/graphql';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
type WorkflowDiagramFilterEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
@@ -80,7 +80,6 @@ const StyledConfiguredFilterContainer = styled.div`
`;
export const WorkflowDiagramFilterEdgeEditable = ({
id,
source,
target,
sourceY,
@@ -118,7 +117,7 @@ export const WorkflowDiagramFilterEdgeEditable = ({
const { openDropdown } = useOpenDropdown();
const { closeDropdown } = useCloseDropdown();
const { isEdgeHovered } = useEdgeHovered();
const { isEdgeHovered } = useEdgeState();
const setWorkflowDiagramPanOnDrag = useSetRecoilComponentState(
workflowDiagramPanOnDragComponentState,
@@ -197,7 +196,9 @@ export const WorkflowDiagramFilterEdgeEditable = ({
>
<WorkflowDiagramEdgeV2VisibilityContainer shouldDisplay>
<StyledConfiguredFilterContainer>
{isEdgeHovered(id) || isDropdownOpen || nodeCreationStarted ? (
{isEdgeHovered({ source, target }) ||
isDropdownOpen ||
nodeCreationStarted ? (
<WorkflowDiagramEdgeButtonGroup
iconButtons={[
{
@@ -8,22 +8,28 @@ import { FeatureFlagKey } from '~/generated/graphql';
type WorkflowDiagramHandleEditableProps = HandleProps & {
selected: boolean;
hovered?: boolean;
};
const HANDLE_SCALE_ON_HOVER = 1.5;
const StyledHandle = styled(Handle, {
shouldForwardProp: (prop) =>
prop !== 'disableHoverEffect' && prop !== 'selected',
prop !== 'disableHoverEffect' && prop !== 'selected' && prop !== 'hovered',
})<{
disableHoverEffect: boolean;
selected: boolean;
hovered?: boolean;
}>`
&.react-flow__handle {
height: ${NODE_HANDLE_HEIGHT_PX}px;
width: ${NODE_HANDLE_WIDTH_PX}px;
border-color: ${({ theme, selected }) =>
selected ? theme.color.blue : theme.border.color.strong};
border-color: ${({ theme, selected, hovered }) =>
selected
? theme.color.blue
: hovered
? theme.font.color.light
: theme.border.color.strong};
background: ${({ theme, selected }) =>
selected ? theme.adaptiveColors.blue1 : theme.background.primary};
transition:
@@ -79,6 +85,7 @@ export const WorkflowDiagramHandleEditable = ({
type,
position,
selected,
hovered = false,
}: WorkflowDiagramHandleEditableProps) => {
const isWorkflowBranchEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_WORKFLOW_BRANCH_ENABLED,
@@ -90,6 +97,7 @@ export const WorkflowDiagramHandleEditable = ({
position={position}
disableHoverEffect={!isWorkflowBranchEnabled}
selected={selected}
hovered={hovered}
/>
);
};
@@ -1,6 +1,6 @@
import { WorkflowDiagramCreateStepElement } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepElement';
import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId';
import { useEdgeSelected } from '@/workflow/workflow-diagram/hooks/useEdgeSelected';
import { useEdgeState } from '@/workflow/workflow-diagram/hooks/useEdgeState';
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { type WorkflowDiagramNodeVariant } from '@/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant';
@@ -100,10 +100,13 @@ export const WorkflowDiagramStepNodeEditableContent = ({
const { isNodeCreationStarted } = useStartNodeCreation();
const { getNodeHandlesSelectedState } = useEdgeSelected();
const { getNodeHandlesSelectedState, getNodeHandlesHoveredState } =
useEdgeState();
const handlesSelectedState = getNodeHandlesSelectedState(id);
const handlesHoveredState = getNodeHandlesHoveredState(id);
return (
<>
{data.nodeType !== 'trigger' && (
@@ -111,6 +114,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
type="target"
position={Position.Top}
selected={handlesSelectedState.targetHandle}
hovered={handlesHoveredState.targetHandle}
/>
)}
@@ -161,6 +165,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
type="source"
position={Position.Bottom}
selected={handlesSelectedState.sourceHandle || selected}
hovered={handlesHoveredState.sourceHandle}
/>
</>
);