diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx index 40b69ea38..21c6cdc85 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx @@ -39,6 +39,7 @@ import React, { import { isDefined } from 'twenty-shared/utils'; import { Tag, TagColor } from 'twenty-ui/components'; import { THEME_COMMON } from 'twenty-ui/theme'; +import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; const StyledResetReactflowStyles = styled.div` height: 100%; @@ -133,6 +134,11 @@ export const WorkflowDiagramCanvasBase = ({ const workflowDiagram = useRecoilComponentValueV2( workflowDiagramComponentState, ); + + const setWorkflowInsertStepIds = useSetRecoilComponentStateV2( + workflowInsertStepIdsComponentState, + ); + const [ workflowDiagramFlowInitializationStatus, setWorkflowDiagramFlowInitializationStatus, @@ -174,6 +180,10 @@ export const WorkflowDiagramCanvasBase = ({ reactflow.setNodes((nodes) => nodes.map((node) => ({ ...node, selected: false })), ); + setWorkflowInsertStepIds({ + parentStepId: undefined, + nextStepId: undefined, + }); }); const containerRef = useRef(null); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEdgeOptions.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEdgeOptions.tsx index 70dedbcd3..d54d1f257 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEdgeOptions.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEdgeOptions.tsx @@ -1,25 +1,36 @@ -import { STEP_ICON_WIDTH } from '@/workflow/workflow-diagram/constants/CreateStepNodeWidth'; import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId'; import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation'; import styled from '@emotion/styled'; import { EdgeLabelRenderer } from '@xyflow/react'; -import { isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; import { IconButtonGroup } from 'twenty-ui/input'; - -const EDGE_OPTION_BUTTON_LEFT_MARGIN = 8; +import { useState } from 'react'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; const StyledIconButtonGroup = styled(IconButtonGroup)` + border: 1px solid ${({ theme }) => theme.border.color.strong}; pointer-events: all; `; const StyledContainer = styled.div<{ - labelX?: number; labelY?: number; }>` position: absolute; - transform: ${({ labelX, labelY }) => - `translate(${labelX || 0}px, ${isDefined(labelY) ? labelY - STEP_ICON_WIDTH / 2 : 0}px) translateX(${EDGE_OPTION_BUTTON_LEFT_MARGIN}px)`}; + transform: ${({ labelY }) => `translate(${21}px, ${(labelY || 0) - 14}px)`}; +`; + +const StyledHoverZone = styled.div` + position: absolute; + width: 48px; + height: 52px; + transform: translate(-13px, -16px); + background: transparent; +`; + +const StyledWrapper = styled.div` + pointer-events: all; + position: relative; `; type WorkflowDiagramEdgeOptionsProps = { @@ -30,31 +41,47 @@ type WorkflowDiagramEdgeOptionsProps = { }; export const WorkflowDiagramEdgeOptions = ({ - labelX, labelY, parentStepId, nextStepId, }: WorkflowDiagramEdgeOptionsProps) => { + const [hovered, setHovered] = useState(false); + const { startNodeCreation } = useStartNodeCreation(); + const workflowInsertStepIds = useRecoilComponentValueV2( + workflowInsertStepIdsComponentState, + ); + + const isSelected = + workflowInsertStepIds.parentStepId === parentStepId && + workflowInsertStepIds.nextStepId === nextStepId; + return ( - { - startNodeCreation({ parentStepId, nextStepId }); - }, - }, - ]} - /> + setHovered(true)} + onMouseLeave={() => setHovered(false)} + > + + {(hovered || isSelected) && ( + { + startNodeCreation({ parentStepId, nextStepId }); + }, + }, + ]} + /> + )} + ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts index a5cea2a6b..e73d4a07d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts @@ -11,6 +11,7 @@ export const useStartNodeCreation = () => { const setWorkflowInsertStepIds = useSetRecoilComponentStateV2( workflowInsertStepIdsComponentState, ); + const { openStepSelectInCommandMenu } = useWorkflowCommandMenu(); const workflowVisualizerWorkflowId = useRecoilComponentValueV2( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts index fff48f470..2236b97e4 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts @@ -1,4 +1,3 @@ -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState'; @@ -11,6 +10,7 @@ import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/us import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState'; import { isDefined } from 'twenty-shared/utils'; import { useState } from 'react'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; export const useCreateStep = ({ workflow, @@ -26,9 +26,8 @@ export const useCreateStep = ({ workflowLastCreatedStepIdComponentState, ); - const workflowInsertStepIds = useRecoilComponentValueV2( - workflowInsertStepIdsComponentState, - ); + const [workflowInsertStepIds, setWorkflowInsertStepIds] = + useRecoilComponentStateV2(workflowInsertStepIdsComponentState); const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); @@ -63,9 +62,10 @@ export const useCreateStep = ({ setWorkflowSelectedNode(createdStep.id); setWorkflowLastCreatedStepId(createdStep.id); - } catch (error) { - setIsLoading(false); - throw error; + setWorkflowInsertStepIds({ + parentStepId: undefined, + nextStepId: undefined, + }); } finally { setIsLoading(false); } diff --git a/packages/twenty-ui/src/input/button/components/InsideButton.tsx b/packages/twenty-ui/src/input/button/components/InsideButton.tsx index 742a00d10..d7ed2e527 100644 --- a/packages/twenty-ui/src/input/button/components/InsideButton.tsx +++ b/packages/twenty-ui/src/input/button/components/InsideButton.tsx @@ -31,6 +31,15 @@ const StyledButton = styled.button` } `; +const StyledAnimatedIconWrapper = styled.span` + display: flex; + transition: transform 0.1s ease; + + &:hover { + transform: translateY(-3%); + } +`; + export const InsideButton = ({ className, Icon, @@ -41,7 +50,11 @@ export const InsideButton = ({ return ( - {Icon && } + {Icon && ( + + + + )} ); };