diff --git a/web/app/components/workflow-app/components/user-cursors-state.ts b/web/app/components/workflow-app/components/user-cursors-state.ts deleted file mode 100644 index de422de393..0000000000 --- a/web/app/components/workflow-app/components/user-cursors-state.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { create } from 'zustand' - -type UserCursorsState = { - showUserCursors: boolean - toggleUserCursors: () => void -} - -export const useUserCursorsState = create(set => ({ - showUserCursors: true, - toggleUserCursors: () => set(state => ({ showUserCursors: !state.showUserCursors })), -})) diff --git a/web/app/components/workflow-app/components/workflow-main.tsx b/web/app/components/workflow-app/components/workflow-main.tsx index 3e9f494694..a0d93bff87 100644 --- a/web/app/components/workflow-app/components/workflow-main.tsx +++ b/web/app/components/workflow-app/components/workflow-main.tsx @@ -12,8 +12,6 @@ import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants' import { WorkflowWithInnerContext } from '@/app/components/workflow' import type { WorkflowProps } from '@/app/components/workflow' import WorkflowChildren from './workflow-children' -import UserCursors from '@/app/components/workflow/collaboration/components/user-cursors' -import { useUserCursorsState } from './user-cursors-state' import { useAvailableNodesMetaData, @@ -49,7 +47,6 @@ const WorkflowMain = ({ const store = useStoreApi() const { startCursorTracking, stopCursorTracking, onlineUsers, cursors, isConnected } = useCollaboration(appId || '', store) const [myUserId, setMyUserId] = useState(null) - const { showUserCursors } = useUserCursorsState() useEffect(() => { if (isConnected) @@ -299,10 +296,12 @@ const WorkflowMain = ({ viewport={viewport} onWorkflowDataUpdate={handleWorkflowDataUpdate} hooksStore={hooksStore as any} + cursors={filteredCursors} + myUserId={myUserId} + onlineUsers={onlineUsers} > - ) } diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 6286a5956d..932a7a83e5 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -76,6 +76,7 @@ import LimitTips from './limit-tips' import { setupScrollToNodeListener } from './utils/node-navigation' import { CommentCursor, CommentIcon, CommentInput, CommentThread } from './comment' import { useWorkflowComment } from './hooks/use-workflow-comment' +import UserCursors from './collaboration/components/user-cursors' import { useStore, useWorkflowStore, @@ -119,6 +120,9 @@ export type WorkflowProps = { viewport?: Viewport children?: React.ReactNode onWorkflowDataUpdate?: (v: any) => void + cursors?: Record + myUserId?: string | null + onlineUsers?: any[] } export const Workflow: FC = memo(({ nodes: originalNodes, @@ -126,6 +130,9 @@ export const Workflow: FC = memo(({ viewport, children, onWorkflowDataUpdate, + cursors, + myUserId, + onlineUsers, }) => { const workflowContainerRef = useRef(null) const workflowStore = useWorkflowStore() @@ -193,6 +200,8 @@ export const Workflow: FC = memo(({ handleCommentReplyUpdate, handleCommentReplyDelete, } = useWorkflowComment() + const showUserComments = useStore(s => s.showUserComments) + const showUserCursors = useStore(s => s.showUserCursors) const mousePosition = useStore(s => s.mousePosition) eventEmitter?.useSubscription((v: any) => { @@ -463,13 +472,13 @@ export const Workflow: FC = memo(({ ) } - return ( + return (showUserComments || controlMode === ControlMode.Comment) ? ( handleCommentIconClick(comment)} /> - ) + ) : null })} {children} = memo(({ className="bg-workflow-canvas-workflow-bg" color='var(--color-workflow-canvas-workflow-dot-color)' /> + {showUserCursors && cursors && ( + + )} ) @@ -530,14 +546,25 @@ export const Workflow: FC = memo(({ type WorkflowWithInnerContextProps = WorkflowProps & { hooksStore?: Partial + cursors?: Record + myUserId?: string | null + onlineUsers?: any[] } export const WorkflowWithInnerContext = memo(({ hooksStore, + cursors, + myUserId, + onlineUsers, ...restProps }: WorkflowWithInnerContextProps) => { return ( - + ) }) diff --git a/web/app/components/workflow/operator/index.tsx b/web/app/components/workflow/operator/index.tsx index e8d4b42a5e..57c2988d24 100644 --- a/web/app/components/workflow/operator/index.tsx +++ b/web/app/components/workflow/operator/index.tsx @@ -5,7 +5,7 @@ import ZoomInOut from './zoom-in-out' import VariableTrigger from '../variable-inspect/trigger' import VariableInspectPanel from '../variable-inspect' import { useStore } from '../store' -import { useUserCursorsState } from '@/app/components/workflow-app/components/user-cursors-state' +import { ControlMode } from '../types' export type OperatorProps = { handleUndo: () => void @@ -15,12 +15,25 @@ export type OperatorProps = { const Operator = ({ handleUndo, handleRedo }: OperatorProps) => { const bottomPanelRef = useRef(null) const [showMiniMap, setShowMiniMap] = useState(true) - const { showUserCursors, toggleUserCursors } = useUserCursorsState() + const showUserCursors = useStore(s => s.showUserCursors) + const setShowUserCursors = useStore(s => s.setShowUserCursors) + const showUserComments = useStore(s => s.showUserComments) + const setShowUserComments = useStore(s => s.setShowUserComments) + const controlMode = useStore(s => s.controlMode) + const isCommentMode = controlMode === ControlMode.Comment const handleToggleMiniMap = useCallback(() => { setShowMiniMap(prev => !prev) }, []) + const handleToggleUserCursors = useCallback(() => { + setShowUserCursors(!showUserCursors) + }, [showUserCursors, setShowUserCursors]) + + const handleToggleUserComments = useCallback(() => { + setShowUserComments(!showUserComments) + }, [showUserComments, setShowUserComments]) + const workflowCanvasWidth = useStore(s => s.workflowCanvasWidth) const rightPanelWidth = useStore(s => s.rightPanelWidth) const setBottomPanelWidth = useStore(s => s.setBottomPanelWidth) @@ -82,7 +95,10 @@ const Operator = ({ handleUndo, handleRedo }: OperatorProps) => { showMiniMap={showMiniMap} onToggleMiniMap={handleToggleMiniMap} showUserCursors={showUserCursors} - onToggleUserCursors={toggleUserCursors} + onToggleUserCursors={handleToggleUserCursors} + showUserComments={showUserComments} + onToggleUserComments={handleToggleUserComments} + isCommentMode={isCommentMode} /> diff --git a/web/app/components/workflow/operator/zoom-in-out.tsx b/web/app/components/workflow/operator/zoom-in-out.tsx index c6f0207fa3..673a58e671 100644 --- a/web/app/components/workflow/operator/zoom-in-out.tsx +++ b/web/app/components/workflow/operator/zoom-in-out.tsx @@ -39,6 +39,7 @@ enum ZoomType { zoomTo75 = 'zoomTo75', zoomTo100 = 'zoomTo100', zoomTo200 = 'zoomTo200', + toggleUserComments = 'toggleUserComments', toggleUserCursors = 'toggleUserCursors', toggleMiniMap = 'toggleMiniMap', } @@ -48,6 +49,9 @@ type ZoomInOutProps = { onToggleMiniMap?: () => void showUserCursors?: boolean onToggleUserCursors?: () => void + showUserComments?: boolean + onToggleUserComments?: () => void + isCommentMode?: boolean } const ZoomInOut: FC = ({ @@ -55,6 +59,9 @@ const ZoomInOut: FC = ({ onToggleMiniMap, showUserCursors = true, onToggleUserCursors, + showUserComments = true, + onToggleUserComments, + isCommentMode = false, }) => { const { t } = useTranslation() const { @@ -99,6 +106,10 @@ const ZoomInOut: FC = ({ }, ], [ + { + key: ZoomType.toggleUserComments, + text: t('workflow.operator.showUserComments'), + }, { key: ZoomType.toggleUserCursors, text: t('workflow.operator.showUserCursors'), @@ -132,6 +143,13 @@ const ZoomInOut: FC = ({ if (type === ZoomType.zoomTo200) zoomTo(2) + if (type === ZoomType.toggleUserComments) { + if (!isCommentMode) + onToggleUserComments?.() + + return + } + if (type === ZoomType.toggleUserCursors) { onToggleUserCursors?.() return @@ -225,10 +243,20 @@ const ZoomInOut: FC = ({ options.map(option => (
handleZoom(option.key)} >
+ {option.key === ZoomType.toggleUserComments && showUserComments && ( + + )} + {option.key === ZoomType.toggleUserComments && !showUserComments && ( +
+ )} {option.key === ZoomType.toggleUserCursors && showUserCursors && ( )} diff --git a/web/app/components/workflow/store/workflow/panel-slice.ts b/web/app/components/workflow/store/workflow/panel-slice.ts index 87b5cb880e..c248e791b2 100644 --- a/web/app/components/workflow/store/workflow/panel-slice.ts +++ b/web/app/components/workflow/store/workflow/panel-slice.ts @@ -12,6 +12,10 @@ export type PanelSliceShape = { setShowDebugAndPreviewPanel: (showDebugAndPreviewPanel: boolean) => void showCommentsPanel: boolean setShowCommentsPanel: (showCommentsPanel: boolean) => void + showUserComments: boolean + setShowUserComments: (showUserComments: boolean) => void + showUserCursors: boolean + setShowUserCursors: (showUserCursors: boolean) => void panelMenu?: { top: number left: number @@ -42,6 +46,10 @@ export const createPanelSlice: StateCreator = set => ({ setShowDebugAndPreviewPanel: showDebugAndPreviewPanel => set(() => ({ showDebugAndPreviewPanel })), showCommentsPanel: false, setShowCommentsPanel: showCommentsPanel => set(() => ({ showCommentsPanel })), + showUserComments: true, + setShowUserComments: showUserComments => set(() => ({ showUserComments })), + showUserCursors: true, + setShowUserCursors: showUserCursors => set(() => ({ showUserCursors })), panelMenu: undefined, setPanelMenu: panelMenu => set(() => ({ panelMenu })), selectionMenu: undefined, diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 210d700c38..915ad67bf3 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -326,6 +326,7 @@ const translation = { zoomTo50: 'Zoom to 50%', zoomTo100: 'Zoom to 100%', zoomToFit: 'Zoom to Fit', + showUserComments: 'Comments', showUserCursors: 'Collaborator cursors', showMiniMap: 'Minimap', alignNodes: 'Align Nodes',