Fix edge hovering and selection (#14416)
## Before https://github.com/user-attachments/assets/416160bb-8289-43cb-bf0d-d2da053b2056 ## After https://github.com/user-attachments/assets/d1e3bcfc-e1cb-46d1-a7c8-9d0a32993f6d
This commit is contained in:
committed by
GitHub
parent
e3c84f289e
commit
fffff75156
+15
-4
@@ -12,15 +12,18 @@ import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diag
|
||||
import { workflowDiagramWaitingNodesDimensionsComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import {
|
||||
type WorkflowConnection,
|
||||
type WorkflowDiagram,
|
||||
type WorkflowDiagramEdge,
|
||||
type WorkflowDiagramEdgeType,
|
||||
type WorkflowDiagramNode,
|
||||
type WorkflowDiagramNodeType,
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { assertWorkflowConnectionOrThrow } from '@/workflow/workflow-diagram/utils/assertWorkflowConnectionOrThrow';
|
||||
import { WorkflowDiagramConnection } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramConnection';
|
||||
import { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramCustomMarkers';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
@@ -32,7 +35,6 @@ import {
|
||||
useReactFlow,
|
||||
type Connection,
|
||||
type EdgeChange,
|
||||
type EdgeProps,
|
||||
type FitViewOptions,
|
||||
type NodeChange,
|
||||
type NodeProps,
|
||||
@@ -119,7 +121,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
Record<
|
||||
WorkflowDiagramEdgeType,
|
||||
React.ComponentType<
|
||||
EdgeProps & {
|
||||
WorkflowDiagramEdgeComponentProps & {
|
||||
data: any;
|
||||
type: any;
|
||||
}
|
||||
@@ -131,7 +133,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
tagColor: TagColor;
|
||||
tagText: string;
|
||||
onInit?: () => void;
|
||||
onConnect?: (params: Connection) => void;
|
||||
onConnect?: (params: WorkflowConnection) => void;
|
||||
onDeleteEdge?: (edge: WorkflowDiagramEdge) => void;
|
||||
onNodeDragStop?: OnNodeDrag<WorkflowDiagramNode>;
|
||||
nodesConnectable?: boolean;
|
||||
@@ -438,6 +440,8 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
setEdgeHovered({
|
||||
source: hoveredEdge.source,
|
||||
target: hoveredEdge.target,
|
||||
sourceHandle: hoveredEdge.sourceHandle,
|
||||
targetHandle: hoveredEdge.targetHandle,
|
||||
});
|
||||
},
|
||||
[setEdgeHovered],
|
||||
@@ -447,6 +451,12 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
clearEdgeHover();
|
||||
}, [clearEdgeHover]);
|
||||
|
||||
const handleConnect = (connection: Connection) => {
|
||||
assertWorkflowConnectionOrThrow(connection);
|
||||
|
||||
onConnect?.(connection);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledResetReactflowStyles ref={containerRef}>
|
||||
<WorkflowDiagramCustomMarkers />
|
||||
@@ -457,6 +467,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
maxZoom={defaultFitViewOptions.maxZoom}
|
||||
defaultViewport={{ x: 0, y: 150, zoom: defaultFitViewOptions.maxZoom }}
|
||||
nodeTypes={nodeTypes}
|
||||
// @ts-expect-error We override Reactflow types for sourceHandle and targetHandle to be required
|
||||
edgeTypes={edgeTypes}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
@@ -464,7 +475,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
onEdgeMouseLeave={onEdgeMouseLeave}
|
||||
onNodesChange={handleNodesChanges}
|
||||
onEdgesChange={handleEdgesChange}
|
||||
onConnect={onConnect}
|
||||
onConnect={handleConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onBeforeDelete={onBeforeDelete}
|
||||
onDelete={onDelete}
|
||||
|
||||
+10
-4
@@ -7,6 +7,7 @@ import { WorkflowDiagramCanvasEditableEffect } from '@/workflow/workflow-diagram
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { workflowDiagramRightClickMenuPositionState } from '@/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState';
|
||||
import {
|
||||
type WorkflowConnection,
|
||||
type WorkflowDiagramEdge,
|
||||
type WorkflowDiagramNode,
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
@@ -21,7 +22,7 @@ import { useCreateEdge } from '@/workflow/workflow-steps/hooks/useCreateEdge';
|
||||
import { useDeleteEdge } from '@/workflow/workflow-steps/hooks/useDeleteEdge';
|
||||
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
||||
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
||||
import { addEdge, type Connection, ReactFlowProvider } from '@xyflow/react';
|
||||
import { addEdge, ReactFlowProvider } from '@xyflow/react';
|
||||
import React from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -50,7 +51,7 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
|
||||
const { updateTrigger } = useUpdateWorkflowVersionTrigger();
|
||||
|
||||
const onConnect = (edgeConnect: Connection) => {
|
||||
const onConnect = (edgeConnect: WorkflowConnection) => {
|
||||
setWorkflowDiagram((diagram) => {
|
||||
if (isDefined(diagram) === false) {
|
||||
throw new Error(
|
||||
@@ -60,7 +61,7 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
|
||||
return {
|
||||
...diagram,
|
||||
edges: addEdge(edgeConnect, diagram.edges),
|
||||
edges: addEdge<WorkflowDiagramEdge>(edgeConnect, diagram.edges),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -68,7 +69,12 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
};
|
||||
|
||||
const onDeleteEdge = async (edge: WorkflowDiagramEdge) => {
|
||||
await deleteEdge(edge);
|
||||
await deleteEdge({
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
sourceHandle: edge.sourceHandle,
|
||||
targetHandle: edge.targetHandle,
|
||||
});
|
||||
};
|
||||
|
||||
const onNodeDragStop = async (
|
||||
|
||||
+5
@@ -1,3 +1,4 @@
|
||||
import { assertEdgeHasDefinedHandlesOrThrow } from '@/workflow/workflow-diagram/utils/assertEdgeHasDefinedHandlesOrThrow';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import {
|
||||
type OnSelectionChangeParams,
|
||||
@@ -19,9 +20,13 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEdgeHasDefinedHandlesOrThrow(selectedEdge);
|
||||
|
||||
setEdgeSelected({
|
||||
source: selectedEdge.source,
|
||||
target: selectedEdge.target,
|
||||
sourceHandle: selectedEdge.sourceHandle,
|
||||
targetHandle: selectedEdge.targetHandle,
|
||||
});
|
||||
},
|
||||
[setEdgeSelected, clearEdgeSelected],
|
||||
|
||||
+15
-2
@@ -6,12 +6,25 @@ import {
|
||||
import { type WorkflowDiagramIteratorEmptyActionNodeData } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowDiagramIteratorEmptyActionNodeData';
|
||||
import { type FilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter';
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import { type Edge, type Node, type Position } from '@xyflow/react';
|
||||
import {
|
||||
type Connection,
|
||||
type Edge,
|
||||
type Node,
|
||||
type Position,
|
||||
} from '@xyflow/react';
|
||||
import { type StepStatus } from 'twenty-shared/workflow';
|
||||
|
||||
export type WorkflowDiagramStepNode = Node<WorkflowDiagramStepNodeData>;
|
||||
export type WorkflowDiagramNode = Node<WorkflowDiagramNodeData>;
|
||||
export type WorkflowDiagramEdge = Edge<WorkflowDiagramEdgeData>;
|
||||
export type WorkflowDiagramEdge = Edge<WorkflowDiagramEdgeData> & {
|
||||
sourceHandle: string;
|
||||
targetHandle: string;
|
||||
};
|
||||
|
||||
export type WorkflowConnection = Connection & {
|
||||
sourceHandle: string;
|
||||
targetHandle: string;
|
||||
};
|
||||
|
||||
export type WorkflowRunDiagramNode = Node<WorkflowRunDiagramNodeData>;
|
||||
|
||||
|
||||
+28
@@ -121,7 +121,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -136,7 +138,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step1",
|
||||
"sourceHandle": "default",
|
||||
"target": "step2",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -151,7 +155,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step2",
|
||||
"sourceHandle": "default",
|
||||
"target": "step3",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -352,7 +358,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -367,7 +375,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step1",
|
||||
"sourceHandle": "default",
|
||||
"target": "step2",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -382,7 +392,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step2",
|
||||
"sourceHandle": "default",
|
||||
"target": "step3",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -583,7 +595,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -598,7 +612,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step1",
|
||||
"sourceHandle": "default",
|
||||
"target": "step2",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -613,7 +629,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step2",
|
||||
"sourceHandle": "default",
|
||||
"target": "step3",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -833,7 +851,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -848,7 +868,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step1",
|
||||
"sourceHandle": "default",
|
||||
"target": "step2",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -863,7 +885,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step2",
|
||||
"sourceHandle": "default",
|
||||
"target": "step3",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -878,7 +902,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "step3",
|
||||
"sourceHandle": "default",
|
||||
"target": "step4",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
@@ -1064,7 +1090,9 @@ describe('generateWorkflowRunDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": false,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--run",
|
||||
"zIndex": -2,
|
||||
},
|
||||
|
||||
+2
@@ -161,7 +161,9 @@ describe('getWorkflowVersionDiagram', () => {
|
||||
"markerStart": undefined,
|
||||
"selectable": true,
|
||||
"source": "trigger",
|
||||
"sourceHandle": "default",
|
||||
"target": "step-1",
|
||||
"targetHandle": "default",
|
||||
"type": "empty-filter--editable",
|
||||
"zIndex": -2,
|
||||
},
|
||||
|
||||
+28
@@ -34,7 +34,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
{
|
||||
id: 'A-C',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
data: {
|
||||
edgeType: 'default',
|
||||
},
|
||||
@@ -96,13 +98,17 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
{
|
||||
id: 'A-B',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'B',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
{
|
||||
id: 'B-C',
|
||||
source: 'B',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
],
|
||||
@@ -148,7 +154,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
id: 'A-C-filter-B',
|
||||
type: 'filter--editable',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
selectable: true,
|
||||
deletable: true,
|
||||
data: {
|
||||
@@ -229,25 +237,33 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
{
|
||||
id: 'A-B1',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'B1',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
{
|
||||
id: 'B1-C',
|
||||
source: 'B1',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
{
|
||||
id: 'C-B2',
|
||||
source: 'C',
|
||||
sourceHandle: 'default',
|
||||
target: 'B2',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
{
|
||||
id: 'B2-D',
|
||||
source: 'B2',
|
||||
sourceHandle: 'default',
|
||||
target: 'D',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
],
|
||||
@@ -275,7 +291,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
id: 'A-C-filter-B1',
|
||||
type: 'filter--editable',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
selectable: true,
|
||||
deletable: true,
|
||||
data: {
|
||||
@@ -294,7 +312,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
id: 'C-D-filter-B2',
|
||||
type: 'filter--editable',
|
||||
source: 'C',
|
||||
sourceHandle: 'default',
|
||||
target: 'D',
|
||||
targetHandle: 'default',
|
||||
selectable: true,
|
||||
deletable: true,
|
||||
data: {
|
||||
@@ -339,7 +359,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
{
|
||||
id: 'A-B',
|
||||
source: 'A',
|
||||
sourceHandle: 'default',
|
||||
target: 'B',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
],
|
||||
@@ -415,13 +437,17 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
{
|
||||
id: 'trigger-B',
|
||||
source: 'trigger',
|
||||
sourceHandle: 'default',
|
||||
target: 'B',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
{
|
||||
id: 'B-C',
|
||||
source: 'B',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
data: { edgeType: 'default' },
|
||||
},
|
||||
],
|
||||
@@ -467,7 +493,9 @@ describe('transformFilterNodesAsEdges', () => {
|
||||
id: 'trigger-C-filter-B',
|
||||
type: 'filter--editable',
|
||||
source: 'trigger',
|
||||
sourceHandle: 'default',
|
||||
target: 'C',
|
||||
targetHandle: 'default',
|
||||
selectable: true,
|
||||
deletable: true,
|
||||
data: {
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { type Edge } from '@xyflow/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type AssertEdgeHasDefinedHandlesOrThrow = (
|
||||
edge: Edge,
|
||||
) => asserts edge is Edge & {
|
||||
sourceHandle: string;
|
||||
targetHandle: string;
|
||||
};
|
||||
|
||||
export const assertEdgeHasDefinedHandlesOrThrow: AssertEdgeHasDefinedHandlesOrThrow =
|
||||
(edge) => {
|
||||
if (!isDefined(edge.sourceHandle) || !isDefined(edge.targetHandle)) {
|
||||
throw new Error(
|
||||
'sourceHandle and targetHandle must be defined on the edge.',
|
||||
);
|
||||
}
|
||||
};
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { type WorkflowConnection } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type Connection } from '@xyflow/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type AssertWorkflowConnectionOrThrow = (
|
||||
connection: Connection,
|
||||
) => asserts connection is WorkflowConnection;
|
||||
|
||||
export const assertWorkflowConnectionOrThrow: AssertWorkflowConnectionOrThrow =
|
||||
(connection) => {
|
||||
if (
|
||||
!isDefined(connection.sourceHandle) ||
|
||||
!isDefined(connection.targetHandle)
|
||||
) {
|
||||
throw new Error(
|
||||
'WorkflowConnection must have defined sourceHandle and targetHandle.',
|
||||
);
|
||||
}
|
||||
};
|
||||
+4
@@ -7,6 +7,8 @@ import {
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { getEdgeTypeBetweenTwoNodes } from '@/workflow/workflow-diagram/utils/getEdgeTypeBetweenTwoNodes';
|
||||
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowVisualizerEdgeDefaultConfiguration';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
@@ -61,7 +63,9 @@ export const generateNodesAndEdgesForDefaultNode = ({
|
||||
type: edgeTypeBetweenTwoNodes,
|
||||
id: v4(),
|
||||
source: step.id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
target: child,
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
|
||||
+8
@@ -9,6 +9,8 @@ import { getEdgeTypeBetweenTwoNodes } from '@/workflow/workflow-diagram/utils/ge
|
||||
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowVisualizerEdgeDefaultConfiguration';
|
||||
import { type WorkflowDiagramIteratorEmptyActionNodeData } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowDiagramIteratorEmptyActionNodeData';
|
||||
import { WORKFLOW_DIAGRAM_ITERATOR_NODE_LOOP_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramIteratorNodeLoopHandleId';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards';
|
||||
import { Position } from '@xyflow/react';
|
||||
@@ -88,6 +90,7 @@ export const generateNodesAndEdgesForIteratorNode = ({
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
data: {
|
||||
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION.data,
|
||||
labelOptions: {
|
||||
@@ -128,6 +131,7 @@ export const generateNodesAndEdgesForIteratorNode = ({
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
data: {
|
||||
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION.data,
|
||||
labelOptions: {
|
||||
@@ -142,10 +146,12 @@ export const generateNodesAndEdgesForIteratorNode = ({
|
||||
type: edgeTypeBetweenTwoNodes,
|
||||
id: v4(),
|
||||
source: emptyNodeId,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
target: step.id,
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -155,10 +161,12 @@ export const generateNodesAndEdgesForIteratorNode = ({
|
||||
type: edgeTypeBetweenTwoNodes,
|
||||
id: v4(),
|
||||
source: step.id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
target: child,
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
data: {
|
||||
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION.data,
|
||||
labelOptions: {
|
||||
|
||||
+4
@@ -16,6 +16,8 @@ import { generateNodesAndEdgesForIteratorNode } from '@/workflow/workflow-diagra
|
||||
import { getEdgeTypeBetweenTwoNodes } from '@/workflow/workflow-diagram/utils/getEdgeTypeBetweenTwoNodes';
|
||||
import { getWorkflowDiagramTriggerNode } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramTriggerNode';
|
||||
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowVisualizerEdgeDefaultConfiguration';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
|
||||
import { v4 } from 'uuid';
|
||||
@@ -48,10 +50,12 @@ export const generateWorkflowDiagram = ({
|
||||
type: edgeTypeBetweenTwoNodes,
|
||||
id: v4(),
|
||||
source: TRIGGER_STEP_ID,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
target: stepLinkToTriggerId,
|
||||
...(edgeTypeBetweenTwoNodes.includes('editable')
|
||||
? { deletable: true, selectable: true }
|
||||
: {}),
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+24
-7
@@ -1,11 +1,16 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { BaseEdge, type EdgeProps } from '@xyflow/react';
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { BaseEdge } from '@xyflow/react';
|
||||
|
||||
type WorkflowDiagramBaseEdgeProps = Pick<
|
||||
EdgeProps<WorkflowDiagramEdge>,
|
||||
'source' | 'target' | 'markerStart' | 'markerEnd'
|
||||
WorkflowDiagramEdgeComponentProps,
|
||||
| 'source'
|
||||
| 'sourceHandleId'
|
||||
| 'target'
|
||||
| 'targetHandleId'
|
||||
| 'markerStart'
|
||||
| 'markerEnd'
|
||||
> & {
|
||||
path: string;
|
||||
};
|
||||
@@ -13,6 +18,8 @@ type WorkflowDiagramBaseEdgeProps = Pick<
|
||||
export const WorkflowDiagramBaseEdge = ({
|
||||
source,
|
||||
target,
|
||||
sourceHandleId,
|
||||
targetHandleId,
|
||||
markerStart,
|
||||
markerEnd,
|
||||
path,
|
||||
@@ -21,9 +28,19 @@ export const WorkflowDiagramBaseEdge = ({
|
||||
|
||||
const { isEdgeSelected, isEdgeHovered } = useEdgeState();
|
||||
|
||||
const selected = isEdgeSelected({ source, target });
|
||||
const selected = isEdgeSelected({
|
||||
source,
|
||||
target,
|
||||
sourceHandle: sourceHandleId,
|
||||
targetHandle: targetHandleId,
|
||||
});
|
||||
|
||||
const isHovered = isEdgeHovered({ source, target });
|
||||
const isHovered = isEdgeHovered({
|
||||
source,
|
||||
target,
|
||||
sourceHandle: sourceHandleId,
|
||||
targetHandle: targetHandleId,
|
||||
});
|
||||
|
||||
const stroke = selected
|
||||
? theme.color.blue
|
||||
|
||||
+21
-9
@@ -2,7 +2,6 @@ import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
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';
|
||||
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge';
|
||||
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup';
|
||||
import { WorkflowDiagramEdgeLabel } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeLabel';
|
||||
@@ -11,24 +10,24 @@ import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/work
|
||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
||||
import { useDeleteEdge } from '@/workflow/workflow-steps/hooks/useDeleteEdge';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import {
|
||||
EdgeLabelRenderer,
|
||||
type EdgeProps,
|
||||
getBezierPath,
|
||||
} from '@xyflow/react';
|
||||
import { EdgeLabelRenderer, getBezierPath } from '@xyflow/react';
|
||||
import { type MouseEvent, useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconFilter, IconPlus, IconTrash } from 'twenty-ui/display';
|
||||
|
||||
type WorkflowDiagramDefaultEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramDefaultEdgeEditableProps =
|
||||
WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
export const WorkflowDiagramDefaultEdgeEditable = ({
|
||||
source,
|
||||
sourceHandleId,
|
||||
target,
|
||||
targetHandleId,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
@@ -100,14 +99,21 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
|
||||
const handleDeleteBranch = async (event: MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
|
||||
await deleteEdge({ source, target });
|
||||
await deleteEdge({
|
||||
source,
|
||||
sourceHandle: sourceHandleId,
|
||||
target,
|
||||
targetHandle: targetHandleId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<WorkflowDiagramBaseEdge
|
||||
source={source}
|
||||
sourceHandleId={sourceHandleId}
|
||||
target={target}
|
||||
targetHandleId={targetHandleId}
|
||||
path={edgePath}
|
||||
markerStart={markerStart}
|
||||
markerEnd={markerEnd}
|
||||
@@ -131,7 +137,13 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
|
||||
>
|
||||
<WorkflowDiagramEdgeV2VisibilityContainer
|
||||
shouldDisplay={
|
||||
nodeCreationStarted || isEdgeHovered({ source, target })
|
||||
nodeCreationStarted ||
|
||||
isEdgeHovered({
|
||||
source,
|
||||
target,
|
||||
sourceHandle: sourceHandleId,
|
||||
targetHandle: targetHandleId,
|
||||
})
|
||||
}
|
||||
>
|
||||
<WorkflowDiagramEdgeButtonGroup
|
||||
|
||||
+4
-3
@@ -1,8 +1,9 @@
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { BaseEdge, type EdgeProps, getBezierPath } from '@xyflow/react';
|
||||
import { BaseEdge, getBezierPath } from '@xyflow/react';
|
||||
|
||||
type WorkflowDiagramDefaultEdgeReadonlyProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramDefaultEdgeReadonlyProps =
|
||||
WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
export const WorkflowDiagramDefaultEdgeReadonly = ({
|
||||
sourceX,
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { WorkflowRunDiagramBaseEdge } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowRunDiagramBaseEdge';
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type EdgeProps, getBezierPath } from '@xyflow/react';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { getBezierPath } from '@xyflow/react';
|
||||
|
||||
type WorkflowDiagramDefaultEdgeRunProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramDefaultEdgeRunProps = WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
export const WorkflowDiagramDefaultEdgeRun = ({
|
||||
sourceX,
|
||||
|
||||
+20
-12
@@ -13,10 +13,7 @@ import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diag
|
||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import {
|
||||
type WorkflowDiagramEdge,
|
||||
type WorkflowDiagramEdgeData,
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type WorkflowDiagramEdgeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBaseEdge';
|
||||
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeButtonGroup';
|
||||
@@ -26,6 +23,7 @@ import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/work
|
||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { useDeleteEdge } from '@/workflow/workflow-steps/hooks/useDeleteEdge';
|
||||
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
||||
import { WorkflowStepFilterCounter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterCounter';
|
||||
@@ -34,11 +32,7 @@ import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
EdgeLabelRenderer,
|
||||
type EdgeProps,
|
||||
getBezierPath,
|
||||
} from '@xyflow/react';
|
||||
import { EdgeLabelRenderer, getBezierPath } from '@xyflow/react';
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -53,7 +47,7 @@ import {
|
||||
import { IconButtonGroup } from 'twenty-ui/input';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
|
||||
type WorkflowDiagramFilterEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramFilterEdgeEditableProps = WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
const assertFilterEdgeDataOrThrow: (
|
||||
data: WorkflowDiagramEdgeData | undefined,
|
||||
@@ -86,7 +80,9 @@ const StyledIconButtonGroup = styled(IconButtonGroup)<{ selected?: boolean }>`
|
||||
|
||||
export const WorkflowDiagramFilterEdgeEditable = ({
|
||||
source,
|
||||
sourceHandleId,
|
||||
target,
|
||||
targetHandleId,
|
||||
sourceY,
|
||||
sourceX,
|
||||
targetY,
|
||||
@@ -179,7 +175,12 @@ export const WorkflowDiagramFilterEdgeEditable = ({
|
||||
const handleDeleteBranchClick = async () => {
|
||||
closeDropdown(dropdownId);
|
||||
|
||||
await deleteEdge({ source, target });
|
||||
await deleteEdge({
|
||||
source,
|
||||
sourceHandle: sourceHandleId,
|
||||
target,
|
||||
targetHandle: targetHandleId,
|
||||
});
|
||||
};
|
||||
|
||||
const { filterCounter } = useFilterCounter({ stepId: data.stepId });
|
||||
@@ -189,7 +190,9 @@ export const WorkflowDiagramFilterEdgeEditable = ({
|
||||
<>
|
||||
<WorkflowDiagramBaseEdge
|
||||
source={source}
|
||||
sourceHandleId={sourceHandleId}
|
||||
target={target}
|
||||
targetHandleId={targetHandleId}
|
||||
path={edgePath}
|
||||
markerStart={markerStart}
|
||||
markerEnd={markerEnd}
|
||||
@@ -218,7 +221,12 @@ export const WorkflowDiagramFilterEdgeEditable = ({
|
||||
textColor={theme.font.color.inverted}
|
||||
counter={filterCounter}
|
||||
/>
|
||||
{isEdgeHovered({ source, target }) ||
|
||||
{isEdgeHovered({
|
||||
source,
|
||||
target,
|
||||
sourceHandle: sourceHandleId,
|
||||
targetHandle: targetHandleId,
|
||||
}) ||
|
||||
isDropdownOpen ||
|
||||
nodeCreationStarted ? (
|
||||
<WorkflowDiagramEdgeButtonGroup
|
||||
|
||||
+4
-11
@@ -3,31 +3,24 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useOpenWorkflowViewFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowViewFilterInCommandMenu';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import {
|
||||
type WorkflowDiagramEdge,
|
||||
type WorkflowDiagramEdgeData,
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type WorkflowDiagramEdgeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container';
|
||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { WorkflowStepFilterCounter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterCounter';
|
||||
import { useFilterCounter } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useFilterCounter';
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
BaseEdge,
|
||||
EdgeLabelRenderer,
|
||||
type EdgeProps,
|
||||
getBezierPath,
|
||||
} from '@xyflow/react';
|
||||
import { BaseEdge, EdgeLabelRenderer, getBezierPath } from '@xyflow/react';
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { IconFilter } from 'twenty-ui/display';
|
||||
import { IconButtonGroup } from 'twenty-ui/input';
|
||||
|
||||
type WorkflowDiagramFilterEdgeReadonlyProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramFilterEdgeReadonlyProps = WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
const assertFilterEdgeDataOrThrow: (
|
||||
data: WorkflowDiagramEdgeData | undefined,
|
||||
|
||||
+4
-10
@@ -2,30 +2,24 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { useOpenWorkflowRunFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowRunFilterInCommandMenu';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import {
|
||||
type WorkflowDiagramEdge,
|
||||
type WorkflowDiagramEdgeData,
|
||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type WorkflowDiagramEdgeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2Container';
|
||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||
import { WorkflowRunDiagramBaseEdge } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowRunDiagramBaseEdge';
|
||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/workflow-edges/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { WorkflowStepFilterCounter } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterCounter';
|
||||
import { useFilterCounter } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useFilterCounter';
|
||||
import { css, useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import {
|
||||
EdgeLabelRenderer,
|
||||
type EdgeProps,
|
||||
getBezierPath,
|
||||
} from '@xyflow/react';
|
||||
import { EdgeLabelRenderer, getBezierPath } from '@xyflow/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconFilter } from 'twenty-ui/display';
|
||||
import { IconButtonGroup } from 'twenty-ui/input';
|
||||
|
||||
type WorkflowDiagramFilterEdgeRunProps = EdgeProps<WorkflowDiagramEdge>;
|
||||
type WorkflowDiagramFilterEdgeRunProps = WorkflowDiagramEdgeComponentProps;
|
||||
|
||||
const assertFilterEdgeDataOrThrow: (
|
||||
data: WorkflowDiagramEdgeData | undefined,
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { BaseEdge, type EdgeProps } from '@xyflow/react';
|
||||
import { BaseEdge } from '@xyflow/react';
|
||||
|
||||
type WorkflowRunDiagramBaseEdgeProps = Pick<
|
||||
EdgeProps<WorkflowDiagramEdge>,
|
||||
WorkflowDiagramEdgeComponentProps,
|
||||
'markerStart' | 'markerEnd'
|
||||
> & {
|
||||
path: string;
|
||||
|
||||
+66
-18
@@ -1,9 +1,9 @@
|
||||
import { workflowSelectedEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdge';
|
||||
import { workflowHoveredEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState';
|
||||
import { useReactFlow } from '@xyflow/react';
|
||||
import { EDGE_BRANCH_ARROW_MARKER } from '@/workflow/workflow-diagram/workflow-edges/constants/EdgeBranchArrowMarker';
|
||||
import { workflowHoveredEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowHoveredEdgeComponentState';
|
||||
import { workflowSelectedEdgeComponentState } from '@/workflow/workflow-diagram/workflow-edges/states/workflowSelectedEdgeComponentState';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
import { useReactFlow } from '@xyflow/react';
|
||||
|
||||
export const useEdgeState = () => {
|
||||
const reactflow = useReactFlow();
|
||||
@@ -15,32 +15,73 @@ export const useEdgeState = () => {
|
||||
workflowHoveredEdgeComponentState,
|
||||
);
|
||||
|
||||
const isSourceSelected = (nodeId: string) => {
|
||||
return workflowSelectedEdge?.source === nodeId;
|
||||
const isSourceSelected = ({
|
||||
nodeId,
|
||||
sourceHandle,
|
||||
}: {
|
||||
nodeId: string;
|
||||
sourceHandle: string | null | undefined;
|
||||
}) => {
|
||||
return (
|
||||
workflowSelectedEdge?.source === nodeId &&
|
||||
workflowSelectedEdge.sourceHandle === sourceHandle
|
||||
);
|
||||
};
|
||||
|
||||
const isSourceHovered = (nodeId: string) => {
|
||||
return workflowHoveredEdge?.source === nodeId;
|
||||
const isSourceHovered = ({
|
||||
nodeId,
|
||||
sourceHandle,
|
||||
}: {
|
||||
nodeId: string;
|
||||
sourceHandle: string | null | undefined;
|
||||
}) => {
|
||||
return (
|
||||
workflowHoveredEdge?.source === nodeId &&
|
||||
workflowHoveredEdge.sourceHandle === sourceHandle
|
||||
);
|
||||
};
|
||||
|
||||
const isEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
|
||||
return isSourceSelected(source) && workflowSelectedEdge?.target === target;
|
||||
const isEdgeSelected = ({
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
return (
|
||||
isSourceSelected({ nodeId: source, sourceHandle }) &&
|
||||
workflowSelectedEdge?.target === target &&
|
||||
workflowSelectedEdge.targetHandle === targetHandle
|
||||
);
|
||||
};
|
||||
|
||||
const isEdgeHovered = ({ source, target }: WorkflowDiagramEdge) => {
|
||||
return isSourceHovered(source) && workflowHoveredEdge?.target === target;
|
||||
const isEdgeHovered = ({
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
return (
|
||||
isSourceHovered({ nodeId: source, sourceHandle }) &&
|
||||
workflowHoveredEdge?.target === target &&
|
||||
workflowHoveredEdge.targetHandle === targetHandle
|
||||
);
|
||||
};
|
||||
|
||||
const setEdgeSelected = ({ source, target }: WorkflowDiagramEdge) => {
|
||||
if (isEdgeSelected({ source, target })) {
|
||||
const setEdgeSelected = (edgeDescriptor: WorkflowDiagramEdgeDescriptor) => {
|
||||
if (isEdgeSelected(edgeDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setWorkflowSelectedEdge({ source, target });
|
||||
setWorkflowSelectedEdge(edgeDescriptor);
|
||||
|
||||
reactflow.setEdges((edges) =>
|
||||
edges.map((edge) => {
|
||||
if (edge.source === source && edge.target === target) {
|
||||
if (
|
||||
edge.source === edgeDescriptor.source &&
|
||||
edge.sourceHandle === edgeDescriptor.sourceHandle &&
|
||||
edge.target === edgeDescriptor.target &&
|
||||
edge.targetHandle === edgeDescriptor.targetHandle
|
||||
) {
|
||||
return {
|
||||
...edge,
|
||||
...EDGE_BRANCH_ARROW_MARKER.Selected,
|
||||
@@ -55,14 +96,21 @@ export const useEdgeState = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const setEdgeHovered = ({ source, target }: WorkflowDiagramEdge) => {
|
||||
setWorkflowHoveredEdge({ source, target });
|
||||
const setEdgeHovered = ({
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
setWorkflowHoveredEdge({ source, target, sourceHandle, targetHandle });
|
||||
|
||||
reactflow.setEdges((edges) =>
|
||||
edges.map((edge) => {
|
||||
if (
|
||||
edge.source === source &&
|
||||
edge.sourceHandle === sourceHandle &&
|
||||
edge.target === target &&
|
||||
edge.targetHandle === targetHandle &&
|
||||
edge.markerEnd !== EDGE_BRANCH_ARROW_MARKER.Selected.markerEnd
|
||||
) {
|
||||
return {
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
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/workflow-edges/types/WorkflowDiagramEdge';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
|
||||
export const workflowHoveredEdgeComponentState = createComponentState<
|
||||
WorkflowDiagramEdge | undefined
|
||||
WorkflowDiagramEdgeDescriptor | undefined
|
||||
>({
|
||||
key: 'workflowHoveredEdgeComponentState',
|
||||
defaultValue: undefined,
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
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/workflow-edges/types/WorkflowDiagramEdge';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
|
||||
export const workflowSelectedEdgeComponentState = createComponentState<
|
||||
WorkflowDiagramEdge | undefined
|
||||
WorkflowDiagramEdgeDescriptor | undefined
|
||||
>({
|
||||
key: 'workflowSelectedEdgeComponentState',
|
||||
defaultValue: undefined,
|
||||
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
export type WorkflowDiagramEdge = {
|
||||
source: string;
|
||||
target: string;
|
||||
};
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { type EdgeProps } from '@xyflow/react';
|
||||
|
||||
export type WorkflowDiagramEdgeComponentProps =
|
||||
EdgeProps<WorkflowDiagramEdge> & {
|
||||
sourceHandleId: string;
|
||||
targetHandleId: string;
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export type WorkflowDiagramEdgeDescriptor = {
|
||||
source: string;
|
||||
target: string;
|
||||
sourceHandle: string;
|
||||
targetHandle: string;
|
||||
};
|
||||
+2
@@ -1,3 +1,4 @@
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultTargetHandleId';
|
||||
import styled from '@emotion/styled';
|
||||
import { Handle, Position } from '@xyflow/react';
|
||||
|
||||
@@ -27,6 +28,7 @@ export const WorkflowDiagramHandleTarget = ({
|
||||
}: WorkflowDiagramHandleTargetProps) => {
|
||||
return (
|
||||
<StyledHandle
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID}
|
||||
type="target"
|
||||
position={Position.Top}
|
||||
isConnectableEnd={isConnectable}
|
||||
|
||||
+12
-2
@@ -10,6 +10,7 @@ import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/co
|
||||
import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart';
|
||||
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
|
||||
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { useConnectionState } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useConnectionState';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { Position } from '@xyflow/react';
|
||||
@@ -66,16 +67,25 @@ export const WorkflowDiagramIteratorEmptyActionEditable = ({
|
||||
</WorkflowNodeRightPart>
|
||||
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
disableHoverEffect
|
||||
selected={
|
||||
isSourceSelected(id) ||
|
||||
isSourceSelected({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
selected ||
|
||||
isSourceConnected(id) ||
|
||||
(isConnectable(id) && isHovered)
|
||||
}
|
||||
hovered={isSourceHovered(id) || isHovered}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) || isHovered
|
||||
}
|
||||
/>
|
||||
</WorkflowNodeContainer>
|
||||
);
|
||||
|
||||
+22
-5
@@ -13,6 +13,7 @@ import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/co
|
||||
import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart';
|
||||
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
|
||||
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { useConnectionState } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useConnectionState';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
@@ -143,15 +144,24 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
)}
|
||||
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
selected={
|
||||
isSourceSelected(id) ||
|
||||
isSourceSelected({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
selected ||
|
||||
isSourceConnected(id) ||
|
||||
(isConnectable(id) && isHovered)
|
||||
}
|
||||
hovered={isSourceHovered(id) || isHovered}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) || isHovered
|
||||
}
|
||||
/>
|
||||
|
||||
{isDefined(data.rightHandleOptions) && (
|
||||
@@ -160,13 +170,20 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
selected={
|
||||
isSourceSelected(id) ||
|
||||
isSourceSelected({
|
||||
nodeId: id,
|
||||
sourceHandle: data.rightHandleOptions.id,
|
||||
}) ||
|
||||
selected ||
|
||||
isSourceConnected(id) ||
|
||||
(isConnectable(id) && isHovered)
|
||||
}
|
||||
// TODO: fix hovered state when multiple source handles
|
||||
hovered={isSourceHovered(id) || isHovered}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
nodeId: id,
|
||||
sourceHandle: data.rightHandleOptions.id,
|
||||
}) || isHovered
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/co
|
||||
import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart';
|
||||
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
|
||||
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { Position } from '@xyflow/react';
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
@@ -97,6 +98,7 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
||||
</WorkflowNodeContainer>
|
||||
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
selected={selected}
|
||||
position={Position.Bottom}
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/co
|
||||
import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeLabelWithCounterPart';
|
||||
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
|
||||
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
|
||||
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { Position } from '@xyflow/react';
|
||||
@@ -152,6 +153,7 @@ export const WorkflowRunDiagramStepNode = ({
|
||||
</WorkflowNodeContainer>
|
||||
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
disableHoverEffect
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID = 'default';
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID = 'default';
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdge';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
import { useCreateWorkflowVersionEdge } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionEdge';
|
||||
import { useState } from 'react';
|
||||
|
||||
@@ -11,7 +11,10 @@ export const useCreateEdge = () => {
|
||||
const { getUpdatableWorkflowVersion } =
|
||||
useGetUpdatableWorkflowVersionOrThrow();
|
||||
|
||||
const createEdge = async ({ source, target }: WorkflowDiagramEdge) => {
|
||||
const createEdge = async ({
|
||||
source,
|
||||
target,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
if (isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
import { type WorkflowDiagramEdge } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdge';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
import { useDeleteWorkflowVersionEdge } from '@/workflow/workflow-steps/hooks/useDeleteWorkflowVersionEdge';
|
||||
import { useState } from 'react';
|
||||
|
||||
@@ -11,7 +11,10 @@ export const useDeleteEdge = () => {
|
||||
const { getUpdatableWorkflowVersion } =
|
||||
useGetUpdatableWorkflowVersionOrThrow();
|
||||
|
||||
const deleteEdge = async ({ source, target }: WorkflowDiagramEdge) => {
|
||||
const deleteEdge = async ({
|
||||
source,
|
||||
target,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
if (isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user