feat: Add drag-to-create node with placeholder preview in workflow diagram (#16873)
Closes #14951 --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
+137
-7
@@ -7,12 +7,15 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { WorkflowDiagramRightClickCommandMenu } from '@/workflow/workflow-diagram/components/WorkflowDiagramRightClickCommandMenu';
|
||||
import { WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEmptyNodeDefinition';
|
||||
import { useResetWorkflowInsertStepIds } from '@/workflow/workflow-diagram/hooks/useResetWorkflowInsertStepIds';
|
||||
import { useWorkflowDiagramScreenToFlowPosition } from '@/workflow/workflow-diagram/hooks/useWorkflowDiagramScreenToFlowPosition';
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
|
||||
import { workflowDiagramWaitingNodesDimensionsComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramWaitingNodesDimensionsComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import {
|
||||
type StartNodeCreationParams,
|
||||
type WorkflowConnection,
|
||||
type WorkflowDiagram,
|
||||
type WorkflowDiagramEdge,
|
||||
@@ -23,8 +26,13 @@ import {
|
||||
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 { EDGE_BRANCH_ARROW_MARKER } from '@/workflow/workflow-diagram/workflow-edges/constants/EdgeBranchArrowMarker';
|
||||
import { useEdgeState } from '@/workflow/workflow-diagram/workflow-edges/hooks/useEdgeState';
|
||||
import { type WorkflowDiagramEdgeComponentProps } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeComponentProps';
|
||||
import { getConnectionOptionsForSourceHandle } from '@/workflow/workflow-diagram/workflow-edges/utils/getConnectionOptionsForSourceHandle';
|
||||
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 { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
@@ -39,6 +47,7 @@ import {
|
||||
type NodeChange,
|
||||
type NodeProps,
|
||||
type OnBeforeDelete,
|
||||
type OnConnectStartParams,
|
||||
type OnDelete,
|
||||
type OnNodeDrag,
|
||||
type OnReconnect,
|
||||
@@ -105,6 +114,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
onReconnect,
|
||||
onReconnectStart,
|
||||
onReconnectEnd,
|
||||
startNodeCreation,
|
||||
handlePaneContextMenu,
|
||||
nodesConnectable = false,
|
||||
nodesDraggable = false,
|
||||
@@ -142,6 +152,7 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
onReconnect?: OnReconnect;
|
||||
onReconnectStart?: () => void;
|
||||
onReconnectEnd?: () => void;
|
||||
startNodeCreation?: (params: StartNodeCreationParams) => void;
|
||||
nodesConnectable?: boolean;
|
||||
nodesDraggable?: boolean;
|
||||
handlePaneContextMenu?: ({
|
||||
@@ -182,17 +193,67 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
workflowDiagramWaitingNodesDimensionsComponentState,
|
||||
);
|
||||
|
||||
const workflowInsertStepIds = useRecoilComponentValue(
|
||||
workflowInsertStepIdsComponentState,
|
||||
);
|
||||
|
||||
const { workflowDiagramScreenToFlowPosition } =
|
||||
useWorkflowDiagramScreenToFlowPosition();
|
||||
|
||||
const { setEdgeHovered, clearEdgeHover } = useEdgeState();
|
||||
|
||||
const [workflowDiagramFlowInitialized, setWorkflowDiagramFlowInitialized] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const [connectionStartInfo, setConnectionStartInfo] = useState<{
|
||||
nodeId: string;
|
||||
handleId: string;
|
||||
} | null>(null);
|
||||
|
||||
const { nodes, edges } = useMemo(() => {
|
||||
if (isDefined(workflowDiagram)) {
|
||||
return workflowDiagram;
|
||||
if (!isDefined(workflowDiagram)) {
|
||||
return { nodes: [], edges: [] };
|
||||
}
|
||||
return { nodes: [], edges: [] };
|
||||
}, [workflowDiagram]);
|
||||
|
||||
const nodes = [...workflowDiagram.nodes];
|
||||
const edges = [...workflowDiagram.edges];
|
||||
|
||||
if (
|
||||
isDefined(workflowInsertStepIds.position) &&
|
||||
!isDefined(workflowInsertStepIds.nextStepId)
|
||||
) {
|
||||
const emptyNode = {
|
||||
...WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION,
|
||||
position: workflowInsertStepIds.position,
|
||||
data: {
|
||||
...WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION.data,
|
||||
position: workflowInsertStepIds.position,
|
||||
},
|
||||
};
|
||||
|
||||
nodes.push(emptyNode);
|
||||
|
||||
if (isDefined(workflowInsertStepIds.parentStepId)) {
|
||||
edges.push({
|
||||
id: 'empty-edge',
|
||||
type: 'blank',
|
||||
source: workflowInsertStepIds.parentStepId,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
target: WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION.id,
|
||||
targetHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_TARGET_HANDLE_ID,
|
||||
markerStart: undefined,
|
||||
...EDGE_BRANCH_ARROW_MARKER.Default,
|
||||
deletable: false,
|
||||
selectable: false,
|
||||
data: {
|
||||
edgeType: 'default',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { nodes, edges };
|
||||
}, [workflowDiagram, workflowInsertStepIds]);
|
||||
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||
@@ -328,11 +389,20 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
snapshot,
|
||||
workflowDiagramState,
|
||||
);
|
||||
|
||||
const filteredChanges = changes.filter(
|
||||
(change) =>
|
||||
!(
|
||||
'id' in change &&
|
||||
change.id === WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION.id
|
||||
),
|
||||
);
|
||||
|
||||
let updatedWorkflowDiagram = workflowDiagram;
|
||||
if (isDefined(workflowDiagram)) {
|
||||
if (isDefined(workflowDiagram) && filteredChanges.length > 0) {
|
||||
updatedWorkflowDiagram = {
|
||||
...workflowDiagram,
|
||||
nodes: applyNodeChanges(changes, workflowDiagram.nodes),
|
||||
nodes: applyNodeChanges(filteredChanges, workflowDiagram.nodes),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -430,12 +500,70 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
clearEdgeHover();
|
||||
}, [clearEdgeHover]);
|
||||
|
||||
const handleConnectStart = (
|
||||
_: MouseEvent | TouchEvent,
|
||||
params: OnConnectStartParams,
|
||||
) => {
|
||||
if (isDefined(params.nodeId) && isDefined(params.handleId)) {
|
||||
setConnectionStartInfo({
|
||||
nodeId: params.nodeId,
|
||||
handleId: params.handleId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleConnect = (connection: Connection) => {
|
||||
assertWorkflowConnectionOrThrow(connection);
|
||||
|
||||
setConnectionStartInfo(null);
|
||||
onConnect?.(connection);
|
||||
};
|
||||
|
||||
const handleConnectEnd = (event: MouseEvent | TouchEvent) => {
|
||||
let startInfo = connectionStartInfo;
|
||||
|
||||
setConnectionStartInfo((prev) => {
|
||||
startInfo = prev;
|
||||
return null;
|
||||
});
|
||||
|
||||
if (
|
||||
!isDefined(startInfo) ||
|
||||
!isDefined(startNodeCreation) ||
|
||||
!(event instanceof MouseEvent) ||
|
||||
!isDefined(containerRef.current)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bounds = containerRef.current.getBoundingClientRect();
|
||||
|
||||
const screenPosition = {
|
||||
x: event.clientX - bounds.left,
|
||||
y: event.clientY - bounds.top,
|
||||
};
|
||||
|
||||
const flowPosition = workflowDiagramScreenToFlowPosition(screenPosition);
|
||||
|
||||
if (!isDefined(flowPosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DEFAULT_NODE_WIDTH = 200;
|
||||
const adjustedPosition = {
|
||||
x: flowPosition.x - DEFAULT_NODE_WIDTH / 2,
|
||||
y: flowPosition.y + 50,
|
||||
};
|
||||
|
||||
startNodeCreation({
|
||||
parentStepId: startInfo.nodeId,
|
||||
nextStepId: undefined,
|
||||
position: adjustedPosition,
|
||||
connectionOptions: getConnectionOptionsForSourceHandle({
|
||||
sourceHandleId: startInfo.handleId,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledResetReactflowStyles ref={containerRef}>
|
||||
<WorkflowDiagramCustomMarkers />
|
||||
@@ -455,6 +583,8 @@ export const WorkflowDiagramCanvasBase = ({
|
||||
onNodesChange={handleNodesChanges}
|
||||
onEdgesChange={handleEdgesChange}
|
||||
onConnect={handleConnect}
|
||||
onConnectStart={handleConnectStart}
|
||||
onConnectEnd={handleConnectEnd}
|
||||
onReconnect={onReconnect}
|
||||
onReconnectStart={onReconnectStart}
|
||||
onReconnectEnd={onReconnectEnd}
|
||||
|
||||
+5
@@ -4,6 +4,7 @@ import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithC
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase';
|
||||
import { WorkflowDiagramCanvasEditableEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect';
|
||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { workflowDiagramRightClickMenuPositionState } from '@/workflow/workflow-diagram/states/workflowDiagramRightClickMenuPositionState';
|
||||
import {
|
||||
@@ -57,6 +58,8 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
|
||||
const { updateTrigger } = useUpdateWorkflowVersionTrigger();
|
||||
|
||||
const { startNodeCreation } = useStartNodeCreation();
|
||||
|
||||
const onConnect = (edgeConnect: WorkflowConnection) => {
|
||||
setWorkflowDiagram((diagram) => {
|
||||
if (isDefined(diagram) === false) {
|
||||
@@ -162,6 +165,7 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
nodeTypes={{
|
||||
default: WorkflowDiagramStepNodeEditable,
|
||||
'empty-trigger': WorkflowDiagramEmptyTriggerEditable,
|
||||
empty: WorkflowDiagramStepNodeEditable,
|
||||
}}
|
||||
edgeTypes={{
|
||||
blank: WorkflowDiagramBlankEdge,
|
||||
@@ -177,6 +181,7 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
nodesConnectable
|
||||
nodesDraggable
|
||||
onDeleteEdge={onDeleteEdge}
|
||||
startNodeCreation={startNodeCreation}
|
||||
/>
|
||||
|
||||
<WorkflowDiagramCanvasEditableEffect />
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const EMPTY_NODE_ID = 'empty-node';
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { EMPTY_NODE_ID } from '@/workflow/workflow-diagram/constants/EmptyNodeId';
|
||||
import { type WorkflowDiagramStepNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
|
||||
export const WORKFLOW_DIAGRAM_EMPTY_NODE_DEFINITION = {
|
||||
id: EMPTY_NODE_ID,
|
||||
type: 'empty',
|
||||
selected: false,
|
||||
selectable: false,
|
||||
draggable: false,
|
||||
deletable: false,
|
||||
connectable: true,
|
||||
focusable: false,
|
||||
data: {
|
||||
nodeType: 'action',
|
||||
actionType: 'EMPTY',
|
||||
name: 'Add an Action',
|
||||
hasNextStepIds: false,
|
||||
stepId: EMPTY_NODE_ID,
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
},
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
} satisfies WorkflowDiagramStepNode;
|
||||
+2
-7
@@ -6,7 +6,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
import { type WorkflowStepConnectionOptions } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowStepConnectionOptions';
|
||||
import { type StartNodeCreationParams } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import { useCallback, useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
@@ -42,12 +42,7 @@ export const useStartNodeCreation = () => {
|
||||
nextStepId,
|
||||
position,
|
||||
connectionOptions,
|
||||
}: {
|
||||
parentStepId: string | undefined;
|
||||
nextStepId: string | undefined;
|
||||
position?: { x: number; y: number };
|
||||
connectionOptions?: WorkflowStepConnectionOptions;
|
||||
}) => {
|
||||
}: StartNodeCreationParams) => {
|
||||
setWorkflowInsertStepIds({
|
||||
parentStepId,
|
||||
nextStepId,
|
||||
|
||||
+9
-1
@@ -3,6 +3,7 @@ import {
|
||||
type WorkflowRunStepStatus,
|
||||
type WorkflowTriggerType,
|
||||
} from '@/workflow/types/Workflow';
|
||||
import { type WorkflowStepConnectionOptions } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowStepConnectionOptions';
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import {
|
||||
type Connection,
|
||||
@@ -117,6 +118,13 @@ export type WorkflowDiagramDefaultEdgeData = {
|
||||
|
||||
export type WorkflowDiagramEdgeData = WorkflowDiagramDefaultEdgeData;
|
||||
|
||||
export type WorkflowDiagramNodeType = 'default' | 'empty-trigger';
|
||||
export type WorkflowDiagramNodeType = 'default' | 'empty-trigger' | 'empty';
|
||||
|
||||
export type WorkflowDiagramEdgeType = 'blank' | 'editable' | 'readonly';
|
||||
|
||||
export type StartNodeCreationParams = {
|
||||
parentStepId?: string;
|
||||
nextStepId?: string;
|
||||
position?: { x: number; y: number };
|
||||
connectionOptions?: WorkflowStepConnectionOptions;
|
||||
};
|
||||
|
||||
+63
-47
@@ -1,4 +1,6 @@
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { WorkflowDiagramCreateStepElement } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepElement';
|
||||
import { EMPTY_NODE_ID } from '@/workflow/workflow-diagram/constants/EmptyNodeId';
|
||||
import { WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramStepNodeClickOutsideId';
|
||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||
import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||
@@ -16,6 +18,7 @@ import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/co
|
||||
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 { isNodeTitleHighlighted } from '@/workflow/workflow-diagram/workflow-nodes/utils/isNodeTitleHighlighted';
|
||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { Position } from '@xyflow/react';
|
||||
@@ -61,6 +64,10 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
|
||||
const { isNodeCreationStarted } = useStartNodeCreation();
|
||||
|
||||
const workflowInsertStepIds = useRecoilComponentValue(
|
||||
workflowInsertStepIdsComponentState,
|
||||
);
|
||||
|
||||
const { isConnectable, isConnectingSource, isConnectionInProgress } =
|
||||
useConnectionState(data.nodeType);
|
||||
|
||||
@@ -79,6 +86,11 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
actionType: data.nodeType === 'action' ? data.actionType : undefined,
|
||||
});
|
||||
|
||||
const isCreatingEmptyNodeFromThisNode =
|
||||
isDefined(workflowInsertStepIds.position) &&
|
||||
!isDefined(workflowInsertStepIds.nextStepId) &&
|
||||
workflowInsertStepIds.parentStepId === data.stepId;
|
||||
|
||||
return (
|
||||
<>
|
||||
<WorkflowNodeContainer
|
||||
@@ -111,56 +123,60 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
</WorkflowNodeRightPart>
|
||||
</WorkflowNodeContainer>
|
||||
|
||||
{!data.hasNextStepIds && !isConnectionInProgress && (
|
||||
<StyledAddStepButtonContainer
|
||||
shouldDisplay={
|
||||
data.nodeType === 'trigger' ||
|
||||
isHovered ||
|
||||
selected ||
|
||||
isNodeCreationStarted({ parentStepId: data.stepId })
|
||||
}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleAddStepButtonContainerClick}
|
||||
>
|
||||
<WorkflowDiagramCreateStepElement
|
||||
data={data}
|
||||
Label={
|
||||
isDefined(data.defaultHandleOptions?.label) ? (
|
||||
<WorkflowDiagramEdgeLabel
|
||||
label={i18n._(data.defaultHandleOptions.label)}
|
||||
/>
|
||||
) : undefined
|
||||
{!data.hasNextStepIds &&
|
||||
!isConnectionInProgress &&
|
||||
!isCreatingEmptyNodeFromThisNode && (
|
||||
<StyledAddStepButtonContainer
|
||||
shouldDisplay={
|
||||
data.nodeType === 'trigger' ||
|
||||
isHovered ||
|
||||
selected ||
|
||||
isNodeCreationStarted({ parentStepId: data.stepId })
|
||||
}
|
||||
/>
|
||||
</StyledAddStepButtonContainer>
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleAddStepButtonContainerClick}
|
||||
>
|
||||
<WorkflowDiagramCreateStepElement
|
||||
data={data}
|
||||
Label={
|
||||
isDefined(data.defaultHandleOptions?.label) ? (
|
||||
<WorkflowDiagramEdgeLabel
|
||||
label={i18n._(data.defaultHandleOptions.label)}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</StyledAddStepButtonContainer>
|
||||
)}
|
||||
|
||||
{id !== EMPTY_NODE_ID && (
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
selected={
|
||||
isSourceSelected({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
selected ||
|
||||
isConnectingSource({
|
||||
nodeId: id,
|
||||
sourceHandleId: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
(isNodeConnectable && isHovered)
|
||||
}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) || isHovered
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<WorkflowDiagramHandleSource
|
||||
id={WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID}
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
selected={
|
||||
isSourceSelected({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
selected ||
|
||||
isConnectingSource({
|
||||
nodeId: id,
|
||||
sourceHandleId: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
(isNodeConnectable && isHovered)
|
||||
}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
nodeId: id,
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) || isHovered
|
||||
}
|
||||
/>
|
||||
|
||||
{isDefined(data.rightHandleOptions) && (
|
||||
{id !== EMPTY_NODE_ID && isDefined(data.rightHandleOptions) && (
|
||||
<WorkflowDiagramHandleSource
|
||||
id={data.rightHandleOptions.id}
|
||||
type="source"
|
||||
|
||||
Reference in New Issue
Block a user