From 4da128d77cdbb1c3f5eb5b753af8f3f17b95395d Mon Sep 17 00:00:00 2001 From: Waleed Date: Wed, 31 Dec 2025 17:59:44 -0800 Subject: [PATCH] improvement(context-menu): gray out undo redo if the stack is empty (#2657) --- .../components/context-menu/pane-context-menu.tsx | 6 ++++-- .../w/[workflowId]/components/context-menu/types.ts | 4 ++++ .../[workspaceId]/w/[workflowId]/workflow.tsx | 13 +++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/pane-context-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/pane-context-menu.tsx index e95c07e6a..f8aca55c2 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/pane-context-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/pane-context-menu.tsx @@ -24,6 +24,8 @@ export function PaneContextMenu({ hasClipboard = false, disableEdit = false, disableAdmin = false, + canUndo = false, + canRedo = false, }: PaneContextMenuProps) { return ( @@ -40,7 +42,7 @@ export function PaneContextMenu({ {/* Undo */} { onUndo() onClose() @@ -53,7 +55,7 @@ export function PaneContextMenu({ {/* Redo */} { onRedo() onClose() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/types.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/types.ts index 9c75c74e7..e607e0361 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/types.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/context-menu/types.ts @@ -86,4 +86,8 @@ export interface PaneContextMenuProps { disableEdit?: boolean /** Whether admin actions are disabled (no admin permission) */ disableAdmin?: boolean + /** Whether undo is available */ + canUndo?: boolean + /** Whether redo is available */ + canRedo?: boolean } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 268d21ba2..25237d430 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -16,6 +16,7 @@ import ReactFlow, { import 'reactflow/dist/style.css' import { createLogger } from '@sim/logger' import { useShallow } from 'zustand/react/shallow' +import { useSession } from '@/lib/auth/auth-client' import type { OAuthConnectEventDetail } from '@/lib/copilot/tools/client/other/oauth-request-access' import type { OAuthProvider } from '@/lib/oauth' import { DEFAULT_HORIZONTAL_SPACING } from '@/lib/workflows/autolayout/constants' @@ -65,6 +66,7 @@ import { useCopilotStore } from '@/stores/panel/copilot/store' import { usePanelEditorStore } from '@/stores/panel/editor/store' import { useSearchModalStore } from '@/stores/search-modal/store' import { useGeneralStore } from '@/stores/settings/general/store' +import { useUndoRedoStore } from '@/stores/undo-redo' import { useVariablesStore } from '@/stores/variables/store' import { useWorkflowDiffStore } from '@/stores/workflow-diff/store' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' @@ -232,6 +234,15 @@ const WorkflowContent = React.memo(() => { const currentWorkflow = useCurrentWorkflow() + // Undo/redo availability for context menu + const { data: session } = useSession() + const userId = session?.user?.id || 'unknown' + const undoRedoStacks = useUndoRedoStore((s) => s.stacks) + const undoRedoKey = activeWorkflowId && userId ? `${activeWorkflowId}:${userId}` : '' + const undoRedoStack = (undoRedoKey && undoRedoStacks[undoRedoKey]) || { undo: [], redo: [] } + const canUndo = undoRedoStack.undo.length > 0 + const canRedo = undoRedoStack.redo.length > 0 + const { updateNodeDimensions, setDragStartPosition, getDragStartPosition } = useWorkflowStore( useShallow((state) => ({ updateNodeDimensions: state.updateNodeDimensions, @@ -2892,6 +2903,8 @@ const WorkflowContent = React.memo(() => { hasClipboard={hasClipboard()} disableEdit={!effectivePermissions.canEdit} disableAdmin={!effectivePermissions.canAdmin} + canUndo={canUndo} + canRedo={canRedo} /> )}