mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-30 20:27:55 +00:00 
			
		
		
		
	8563 workflow workflow node does not open on step click (#8582)
- fix multiple node selection - fix console error - fix close right drawer no unselect nodes - fix edges not selectable - fix sometime node not selected when clicking ## After https://github.com/user-attachments/assets/ceec847f-5b7d-4452-9685-81a845bbf21e
This commit is contained in:
		| @@ -10,12 +10,7 @@ import { useTheme } from '@emotion/react'; | |||||||
| import styled from '@emotion/styled'; | import styled from '@emotion/styled'; | ||||||
| import { motion } from 'framer-motion'; | import { motion } from 'framer-motion'; | ||||||
| import { useRef } from 'react'; | import { useRef } from 'react'; | ||||||
| import { | import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil'; | ||||||
|   useRecoilCallback, |  | ||||||
|   useRecoilState, |  | ||||||
|   useRecoilValue, |  | ||||||
|   useSetRecoilState, |  | ||||||
| } from 'recoil'; |  | ||||||
| import { Key } from 'ts-key-enum'; | import { Key } from 'ts-key-enum'; | ||||||
| import { isDefined } from '~/utils/isDefined'; | import { isDefined } from '~/utils/isDefined'; | ||||||
|  |  | ||||||
| @@ -24,8 +19,8 @@ import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState'; | |||||||
| import { rightDrawerPageState } from '../states/rightDrawerPageState'; | import { rightDrawerPageState } from '../states/rightDrawerPageState'; | ||||||
| import { RightDrawerHotkeyScope } from '../types/RightDrawerHotkeyScope'; | import { RightDrawerHotkeyScope } from '../types/RightDrawerHotkeyScope'; | ||||||
|  |  | ||||||
| import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent'; |  | ||||||
| import { RightDrawerRouter } from './RightDrawerRouter'; | import { RightDrawerRouter } from './RightDrawerRouter'; | ||||||
|  | import { workflowReactFlowRefState } from '@/workflow/states/workflowReactFlowRefState'; | ||||||
|  |  | ||||||
| const StyledContainer = styled(motion.div)<{ isRightDrawerMinimized: boolean }>` | const StyledContainer = styled(motion.div)<{ isRightDrawerMinimized: boolean }>` | ||||||
|   background: ${({ theme }) => theme.background.primary}; |   background: ${({ theme }) => theme.background.primary}; | ||||||
| @@ -94,9 +89,7 @@ export const RightDrawer = () => { | |||||||
|  |  | ||||||
|   type RightDrawerAnimationVariant = keyof typeof animationVariants; |   type RightDrawerAnimationVariant = keyof typeof animationVariants; | ||||||
|  |  | ||||||
|   const [isRightDrawerOpen, setIsRightDrawerOpen] = useRecoilState( |   const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState); | ||||||
|     isRightDrawerOpenState, |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState); |   const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState); | ||||||
|  |  | ||||||
| @@ -109,13 +102,17 @@ export const RightDrawer = () => { | |||||||
|   const { closeRightDrawer } = useRightDrawer(); |   const { closeRightDrawer } = useRightDrawer(); | ||||||
|  |  | ||||||
|   const rightDrawerRef = useRef<HTMLDivElement>(null); |   const rightDrawerRef = useRef<HTMLDivElement>(null); | ||||||
|  |   const workflowReactFlowRef = useRecoilValue(workflowReactFlowRefState); | ||||||
|  |  | ||||||
|   const { useListenClickOutside } = useClickOutsideListener( |   const { useListenClickOutside } = useClickOutsideListener( | ||||||
|     RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID, |     RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID, | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   useListenClickOutside({ |   useListenClickOutside({ | ||||||
|     refs: [rightDrawerRef], |     refs: [ | ||||||
|  |       rightDrawerRef, | ||||||
|  |       ...(workflowReactFlowRef ? [workflowReactFlowRef] : []), | ||||||
|  |     ], | ||||||
|     callback: useRecoilCallback( |     callback: useRecoilCallback( | ||||||
|       ({ snapshot, set }) => |       ({ snapshot, set }) => | ||||||
|         (event) => { |         (event) => { | ||||||
| @@ -128,7 +125,6 @@ export const RightDrawer = () => { | |||||||
|  |  | ||||||
|           if (isRightDrawerOpen && !isRightDrawerMinimized) { |           if (isRightDrawerOpen && !isRightDrawerMinimized) { | ||||||
|             set(rightDrawerCloseEventState, event); |             set(rightDrawerCloseEventState, event); | ||||||
|             emitRightDrawerCloseEvent(); |  | ||||||
|  |  | ||||||
|             closeRightDrawer(); |             closeRightDrawer(); | ||||||
|           } |           } | ||||||
| @@ -141,10 +137,12 @@ export const RightDrawer = () => { | |||||||
|   useScopedHotkeys( |   useScopedHotkeys( | ||||||
|     [Key.Escape], |     [Key.Escape], | ||||||
|     () => { |     () => { | ||||||
|       closeRightDrawer(); |       if (isRightDrawerOpen && !isRightDrawerMinimized) { | ||||||
|  |         closeRightDrawer(); | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|     RightDrawerHotkeyScope.RightDrawer, |     RightDrawerHotkeyScope.RightDrawer, | ||||||
|     [setIsRightDrawerOpen], |     [isRightDrawerOpen, isRightDrawerMinimized], | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   const isMobile = useIsMobile(); |   const isMobile = useIsMobile(); | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import { rightDrawerCloseEventState } from '@/ui/layout/right-drawer/states/righ | |||||||
| import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState'; | import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState'; | ||||||
| import { rightDrawerPageState } from '../states/rightDrawerPageState'; | import { rightDrawerPageState } from '../states/rightDrawerPageState'; | ||||||
| import { RightDrawerPages } from '../types/RightDrawerPages'; | import { RightDrawerPages } from '../types/RightDrawerPages'; | ||||||
|  | import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent'; | ||||||
|  |  | ||||||
| export const useRightDrawer = () => { | export const useRightDrawer = () => { | ||||||
|   const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState); |   const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState); | ||||||
| @@ -28,6 +29,7 @@ export const useRightDrawer = () => { | |||||||
|       () => { |       () => { | ||||||
|         set(isRightDrawerOpenState, false); |         set(isRightDrawerOpenState, false); | ||||||
|         set(isRightDrawerMinimizedState, false); |         set(isRightDrawerMinimizedState, false); | ||||||
|  |         emitRightDrawerCloseEvent(); | ||||||
|       }, |       }, | ||||||
|     [], |     [], | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -28,6 +28,8 @@ import '@xyflow/react/dist/style.css'; | |||||||
| import React, { useEffect, useMemo, useRef } from 'react'; | import React, { useEffect, useMemo, useRef } from 'react'; | ||||||
| import { useRecoilValue, useSetRecoilState } from 'recoil'; | import { useRecoilValue, useSetRecoilState } from 'recoil'; | ||||||
| import { GRAY_SCALE, isDefined, THEME_COMMON } from 'twenty-ui'; | import { GRAY_SCALE, isDefined, THEME_COMMON } from 'twenty-ui'; | ||||||
|  | import { useListenRightDrawerClose } from '@/ui/layout/right-drawer/hooks/useListenRightDrawerClose'; | ||||||
|  | import { workflowReactFlowRefState } from '@/workflow/states/workflowReactFlowRefState'; | ||||||
|  |  | ||||||
| const StyledResetReactflowStyles = styled.div` | const StyledResetReactflowStyles = styled.div` | ||||||
|   height: 100%; |   height: 100%; | ||||||
| @@ -86,6 +88,9 @@ export const WorkflowDiagramCanvasBase = ({ | |||||||
|   children?: React.ReactNode; |   children?: React.ReactNode; | ||||||
| }) => { | }) => { | ||||||
|   const reactflow = useReactFlow(); |   const reactflow = useReactFlow(); | ||||||
|  |   const setWorkflowReactFlowRefState = useSetRecoilState( | ||||||
|  |     workflowReactFlowRefState, | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   const { nodes, edges } = useMemo( |   const { nodes, edges } = useMemo( | ||||||
|     () => getOrganizedDiagram(diagram), |     () => getOrganizedDiagram(diagram), | ||||||
| @@ -144,6 +149,12 @@ export const WorkflowDiagramCanvasBase = ({ | |||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   useListenRightDrawerClose(() => { | ||||||
|  |     reactflow.setNodes((nodes) => | ||||||
|  |       nodes.map((node) => ({ ...node, selected: false })), | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   const containerRef = useRef<HTMLDivElement>(null); |   const containerRef = useRef<HTMLDivElement>(null); | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
| @@ -176,6 +187,11 @@ export const WorkflowDiagramCanvasBase = ({ | |||||||
|   return ( |   return ( | ||||||
|     <StyledResetReactflowStyles ref={containerRef}> |     <StyledResetReactflowStyles ref={containerRef}> | ||||||
|       <ReactFlow |       <ReactFlow | ||||||
|  |         ref={(node) => { | ||||||
|  |           if (isDefined(node)) { | ||||||
|  |             setWorkflowReactFlowRefState({ current: node }); | ||||||
|  |           } | ||||||
|  |         }} | ||||||
|         onInit={() => { |         onInit={() => { | ||||||
|           if (!isDefined(containerRef.current)) { |           if (!isDefined(containerRef.current)) { | ||||||
|             throw new Error('Expect the container ref to be defined'); |             throw new Error('Expect the container ref to be defined'); | ||||||
| @@ -192,11 +208,16 @@ export const WorkflowDiagramCanvasBase = ({ | |||||||
|         minZoom={defaultFitViewOptions.minZoom} |         minZoom={defaultFitViewOptions.minZoom} | ||||||
|         maxZoom={defaultFitViewOptions.maxZoom} |         maxZoom={defaultFitViewOptions.maxZoom} | ||||||
|         nodeTypes={nodeTypes} |         nodeTypes={nodeTypes} | ||||||
|         nodes={nodes.map((node) => ({ ...node, draggable: false }))} |         nodes={nodes} | ||||||
|         edges={edges} |         edges={edges} | ||||||
|         onNodesChange={handleNodesChange} |         onNodesChange={handleNodesChange} | ||||||
|         onEdgesChange={handleEdgesChange} |         onEdgesChange={handleEdgesChange} | ||||||
|         proOptions={{ hideAttribution: true }} |         proOptions={{ hideAttribution: true }} | ||||||
|  |         multiSelectionKeyCode={null} | ||||||
|  |         nodesFocusable={false} | ||||||
|  |         edgesFocusable={false} | ||||||
|  |         nodesDraggable={false} | ||||||
|  |         paneClickDistance={10} // Fix small unwanted user dragging does not select node | ||||||
|       > |       > | ||||||
|         <Background color={GRAY_SCALE.gray25} size={2} /> |         <Background color={GRAY_SCALE.gray25} size={2} /> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import { ReactNode, Fragment } from 'react'; | ||||||
|  | import styled from '@emotion/styled'; | ||||||
| import { useGetManyServerlessFunctions } from '@/settings/serverless-functions/hooks/useGetManyServerlessFunctions'; | import { useGetManyServerlessFunctions } from '@/settings/serverless-functions/hooks/useGetManyServerlessFunctions'; | ||||||
| import { Select, SelectOption } from '@/ui/input/components/Select'; | import { Select, SelectOption } from '@/ui/input/components/Select'; | ||||||
| import { WorkflowEditGenericFormBase } from '@/workflow/components/WorkflowEditGenericFormBase'; | import { WorkflowEditGenericFormBase } from '@/workflow/components/WorkflowEditGenericFormBase'; | ||||||
| @@ -8,8 +10,6 @@ import { getDefaultFunctionInputFromInputSchema } from '@/workflow/utils/getDefa | |||||||
| import { mergeDefaultFunctionInputAndFunctionInput } from '@/workflow/utils/mergeDefaultFunctionInputAndFunctionInput'; | import { mergeDefaultFunctionInputAndFunctionInput } from '@/workflow/utils/mergeDefaultFunctionInputAndFunctionInput'; | ||||||
| import { setNestedValue } from '@/workflow/utils/setNestedValue'; | import { setNestedValue } from '@/workflow/utils/setNestedValue'; | ||||||
| import { useTheme } from '@emotion/react'; | import { useTheme } from '@emotion/react'; | ||||||
| import styled from '@emotion/styled'; |  | ||||||
| import { ReactNode } from 'react'; |  | ||||||
| import { HorizontalSeparator, IconCode, isDefined } from 'twenty-ui'; | import { HorizontalSeparator, IconCode, isDefined } from 'twenty-ui'; | ||||||
| import { useDebouncedCallback } from 'use-debounce'; | import { useDebouncedCallback } from 'use-debounce'; | ||||||
|  |  | ||||||
| @@ -165,12 +165,12 @@ export const WorkflowEditActionFormServerlessFunction = ({ | |||||||
|       if (inputValue !== null && typeof inputValue === 'object') { |       if (inputValue !== null && typeof inputValue === 'object') { | ||||||
|         if (isRoot) { |         if (isRoot) { | ||||||
|           return ( |           return ( | ||||||
|             <> |             <Fragment key={pathKey}> | ||||||
|               {displaySeparator(functionInput) && ( |               {displaySeparator(functionInput) && ( | ||||||
|                 <HorizontalSeparator noMargin /> |                 <HorizontalSeparator noMargin /> | ||||||
|               )} |               )} | ||||||
|               {renderFields(inputValue, currentPath, false)} |               {renderFields(inputValue, currentPath, false)} | ||||||
|             </> |             </Fragment> | ||||||
|           ); |           ); | ||||||
|         } |         } | ||||||
|         return ( |         return ( | ||||||
|   | |||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | import { createState } from 'twenty-ui'; | ||||||
|  | import { RefObject } from 'react'; | ||||||
|  |  | ||||||
|  | export const workflowReactFlowRefState = | ||||||
|  |   createState<RefObject<HTMLDivElement> | null>({ | ||||||
|  |     key: 'workflowReactFlowRefState', | ||||||
|  |     defaultValue: null, | ||||||
|  |   }); | ||||||
| @@ -70,6 +70,7 @@ export const generateWorkflowDiagram = ({ | |||||||
|         type: MarkerType.ArrowClosed, |         type: MarkerType.ArrowClosed, | ||||||
|       }, |       }, | ||||||
|       deletable: false, |       deletable: false, | ||||||
|  |       selectable: false, | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     return nodeId; |     return nodeId; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 martmull
					martmull