Allow nodes connection to loop edge (#14661)
## Before https://github.com/user-attachments/assets/4cfb01cb-559a-4cfa-89d6-ee991a5e2550 ## After https://github.com/user-attachments/assets/236e81b0-4f1f-44c5-8714-aa6f1c9358e1 Closes https://github.com/twentyhq/core-team-issues/issues/1521
This commit is contained in:
committed by
GitHub
parent
7cb294169d
commit
bbc97f4ab3
+8
-1
@@ -14,6 +14,7 @@ import {
|
||||
import { getWorkflowVersionStatusTagProps } from '@/workflow/workflow-diagram/utils/getWorkflowVersionStatusTagProps';
|
||||
import { WorkflowDiagramBlankEdge } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramBlankEdge';
|
||||
import { WorkflowDiagramDefaultEdgeEditable } from '@/workflow/workflow-diagram/workflow-edges/components/WorkflowDiagramDefaultEdgeEditable';
|
||||
import { getConnectionOptionsForSourceHandle } from '@/workflow/workflow-diagram/workflow-edges/utils/getConnectionOptionsForSourceHandle';
|
||||
import { WorkflowDiagramEmptyTriggerEditable } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramEmptyTriggerEditable';
|
||||
import { WorkflowDiagramStepNodeEditable } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditable';
|
||||
import { useCreateEdge } from '@/workflow/workflow-steps/hooks/useCreateEdge';
|
||||
@@ -63,7 +64,13 @@ export const WorkflowDiagramCanvasEditable = () => {
|
||||
};
|
||||
});
|
||||
|
||||
createEdge(edgeConnect);
|
||||
createEdge({
|
||||
source: edgeConnect.source,
|
||||
target: edgeConnect.target,
|
||||
connectionOptions: getConnectionOptionsForSourceHandle({
|
||||
sourceHandleId: edgeConnect.sourceHandle,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const onDeleteEdge = async (edge: WorkflowDiagramEdge) => {
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ export const useEdgeState = () => {
|
||||
sourceHandle,
|
||||
}: {
|
||||
nodeId: string;
|
||||
sourceHandle: string | null | undefined;
|
||||
sourceHandle: string;
|
||||
}) => {
|
||||
return (
|
||||
workflowSelectedEdge?.source === nodeId &&
|
||||
@@ -33,7 +33,7 @@ export const useEdgeState = () => {
|
||||
sourceHandle,
|
||||
}: {
|
||||
nodeId: string;
|
||||
sourceHandle: string | null | undefined;
|
||||
sourceHandle: string;
|
||||
}) => {
|
||||
return (
|
||||
workflowHoveredEdge?.source === nodeId &&
|
||||
|
||||
+16
-8
@@ -74,11 +74,13 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
|
||||
const { isNodeCreationStarted } = useStartNodeCreation();
|
||||
|
||||
const { isConnectable, isSourceConnected, isInProgressConnection } =
|
||||
const { isConnectable, isConnectingSource, isConnectionInProgress } =
|
||||
useConnectionState(data.nodeType);
|
||||
|
||||
const { isSourceSelected, isSourceHovered } = useEdgeState();
|
||||
|
||||
const isNodeConnectable = isConnectable({ nodeId: id });
|
||||
|
||||
const handleAddStepButtonContainerClick = (
|
||||
event: React.MouseEvent<HTMLDivElement>,
|
||||
) => {
|
||||
@@ -92,9 +94,9 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
isConnectable={isConnectable(id)}
|
||||
isConnectable={isNodeConnectable}
|
||||
>
|
||||
<WorkflowDiagramHandleTarget isConnectable={isConnectable(id)} />
|
||||
<WorkflowDiagramHandleTarget isConnectable={isNodeConnectable} />
|
||||
|
||||
<WorkflowNodeIconContainer>
|
||||
<WorkflowDiagramStepNodeIcon data={data} />
|
||||
@@ -119,7 +121,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
)}
|
||||
</WorkflowNodeContainer>
|
||||
|
||||
{!data.hasNextStepIds && !isInProgressConnection && (
|
||||
{!data.hasNextStepIds && !isConnectionInProgress && (
|
||||
<StyledAddStepButtonContainer
|
||||
shouldDisplay={
|
||||
isHovered ||
|
||||
@@ -153,8 +155,11 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
sourceHandle: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
selected ||
|
||||
isSourceConnected(id) ||
|
||||
(isConnectable(id) && isHovered)
|
||||
isConnectingSource({
|
||||
nodeId: id,
|
||||
sourceHandleId: WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID,
|
||||
}) ||
|
||||
(isNodeConnectable && isHovered)
|
||||
}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
@@ -175,8 +180,11 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
||||
sourceHandle: data.rightHandleOptions.id,
|
||||
}) ||
|
||||
selected ||
|
||||
isSourceConnected(id) ||
|
||||
(isConnectable(id) && isHovered)
|
||||
isConnectingSource({
|
||||
nodeId: id,
|
||||
sourceHandleId: data.rightHandleOptions.id,
|
||||
}) ||
|
||||
(isNodeConnectable && isHovered)
|
||||
}
|
||||
hovered={
|
||||
isSourceHovered({
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import type { WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { css } from '@emotion/react';
|
||||
import { getWorkflowDiagramColors } from '@/workflow/workflow-diagram/utils/getWorkflowDiagramColors';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledNodeContainer = styled.div<{
|
||||
runStatus?: WorkflowRunStepStatus;
|
||||
@@ -44,7 +44,7 @@ const StyledNodeContainer = styled.div<{
|
||||
|
||||
.selected & {
|
||||
background-color: ${colors.selected.background};
|
||||
border: 1px solid ${colors.selected.borderColor};
|
||||
border-color: ${colors.selected.borderColor};
|
||||
}
|
||||
`;
|
||||
}}
|
||||
|
||||
+24
-12
@@ -5,14 +5,14 @@ export const useConnectionState = (nodeType: 'action' | 'trigger') => {
|
||||
|
||||
const edges = useEdges();
|
||||
|
||||
const isInProgressConnection = connection.inProgress;
|
||||
const isConnectionInProgress = connection.inProgress;
|
||||
|
||||
const isConnectable = (nodeId: string) => {
|
||||
const isConnectable = ({ nodeId }: { nodeId: string }) => {
|
||||
if (nodeType === 'trigger') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isInProgressConnection) {
|
||||
if (!isConnectionInProgress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,17 +20,29 @@ export const useConnectionState = (nodeType: 'action' | 'trigger') => {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !edges.some(
|
||||
const edgeAlreadyExists = edges.some(
|
||||
(edge) =>
|
||||
edge.target === nodeId &&
|
||||
connection.fromNode?.id &&
|
||||
edge.source === connection.fromNode.id,
|
||||
edge.source === connection.fromNode.id &&
|
||||
edge.sourceHandle === connection.fromHandle.id &&
|
||||
edge.target === nodeId,
|
||||
);
|
||||
|
||||
return !edgeAlreadyExists;
|
||||
};
|
||||
|
||||
const isConnectingSource = ({
|
||||
nodeId,
|
||||
sourceHandleId,
|
||||
}: {
|
||||
nodeId: string;
|
||||
sourceHandleId: string;
|
||||
}) => {
|
||||
return (
|
||||
connection.inProgress &&
|
||||
connection.fromNode.id === nodeId &&
|
||||
connection.fromHandle.id === sourceHandleId
|
||||
);
|
||||
};
|
||||
|
||||
const isSourceConnected = (nodeId: string) => {
|
||||
return connection.inProgress && connection.fromNode.id === nodeId;
|
||||
};
|
||||
|
||||
return { isConnectable, isSourceConnected, isInProgressConnection };
|
||||
return { isConnectable, isConnectingSource, isConnectionInProgress };
|
||||
};
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
|
||||
import { type WorkflowDiagramEdgeDescriptor } from '@/workflow/workflow-diagram/workflow-edges/types/WorkflowDiagramEdgeDescriptor';
|
||||
import { type WorkflowStepConnectionOptions } from '@/workflow/workflow-diagram/workflow-iterator/types/WorkflowStepConnectionOptions';
|
||||
import { useCreateWorkflowVersionEdge } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionEdge';
|
||||
import { useState } from 'react';
|
||||
|
||||
type CreateEdgeParams = Pick<
|
||||
WorkflowDiagramEdgeDescriptor,
|
||||
'source' | 'target'
|
||||
> & {
|
||||
connectionOptions?: WorkflowStepConnectionOptions;
|
||||
};
|
||||
|
||||
export const useCreateEdge = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@@ -14,7 +22,8 @@ export const useCreateEdge = () => {
|
||||
const createEdge = async ({
|
||||
source,
|
||||
target,
|
||||
}: WorkflowDiagramEdgeDescriptor) => {
|
||||
connectionOptions,
|
||||
}: CreateEdgeParams) => {
|
||||
if (isLoading) {
|
||||
return;
|
||||
}
|
||||
@@ -29,6 +38,7 @@ export const useCreateEdge = () => {
|
||||
workflowVersionId,
|
||||
source,
|
||||
target,
|
||||
sourceConnectionOptions: connectionOptions,
|
||||
})
|
||||
)?.data?.createWorkflowVersionEdge;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user