Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions apps/docs/content/docs/en/keyboard-shortcuts/index.mdx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
---
title: Keyboard Shortcuts
description: Master the workflow canvas with keyboard shortcuts and mouse controls
---

import { Callout } from 'fumadocs-ui/components/callout'

Speed up your workflow building with these keyboard shortcuts and mouse controls. All shortcuts work when the canvas is focused (not when typing in an input field).

<Callout type="info">
**Mod** refers to `Cmd` on macOS and `Ctrl` on Windows/Linux.
</Callout>

## Canvas Controls

### Mouse Controls

| Action | Control |
|--------|---------|
| Pan/move canvas | Left-drag on empty space |
| Pan/move canvas | Scroll or trackpad |
| Select multiple blocks | Right-drag to draw selection box |
Comment thread
icecrasher321 marked this conversation as resolved.
| Drag block | Left-drag on block header |
| Add to selection | `Mod` + click on blocks |

### Workflow Actions

| Shortcut | Action |
|----------|--------|
| `Mod` + `Enter` | Run workflow (or cancel if running) |
| `Mod` + `Z` | Undo |
| `Mod` + `Shift` + `Z` | Redo |
| `Mod` + `C` | Copy selected blocks |
| `Mod` + `V` | Paste blocks |
| `Delete` or `Backspace` | Delete selected blocks or edges |
| `Shift` + `L` | Auto-layout canvas |

## Panel Navigation

These shortcuts switch between panel tabs on the right side of the canvas.

| Shortcut | Action |
|----------|--------|
| `C` | Focus Copilot tab |
| `T` | Focus Toolbar tab |
| `E` | Focus Editor tab |
| `Mod` + `F` | Focus Toolbar search |

## Global Navigation

| Shortcut | Action |
|----------|--------|
| `Mod` + `K` | Open search |
| `Mod` + `Shift` + `A` | Add new agent workflow |
| `Mod` + `Y` | Go to templates |
| `Mod` + `L` | Go to logs |

## Utility

| Shortcut | Action |
|----------|--------|
| `Mod` + `D` | Clear terminal console |
| `Mod` + `E` | Clear notifications |

3 changes: 2 additions & 1 deletion apps/docs/content/docs/en/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,7 +14,8 @@
"execution",
"permissions",
"sdks",
"self-hosting"
"self-hosting",
"./keyboard-shortcuts/index"
],
"defaultOpen": false
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,7 +61,7 @@ export interface SubflowNodeData {
*/
export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeData>) => {
const { getNodes } = useReactFlow()
const { collaborativeRemoveBlock } = useCollaborativeWorkflow()
const { collaborativeBatchRemoveBlocks } = useCollaborativeWorkflow()
const blockRef = useRef<HTMLDivElement>(null)

const currentWorkflow = useCurrentWorkflow()
Expand DownExpand Up@@ -184,7 +184,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
variant='ghost'
onClick={(e) => {
e.stopPropagation()
collaborativeRemoveBlock(id)
collaborativeBatchRemoveBlocks([id])
}}
className='h-[14px] w-[14px] p-0 opacity-0 transition-opacity duration-100 group-hover:opacity-100'
>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,8 +4,13 @@ import { Button, Copy, Tooltip, Trash2 } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { getUniqueBlockName, prepareDuplicateBlockState } from '@/stores/workflows/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'

const DEFAULT_DUPLICATE_OFFSET = { x: 50, y: 50 }

/**
* Props for the ActionBar component
*/
Expand All@@ -27,11 +32,39 @@ interface ActionBarProps {
export const ActionBar = memo(
function ActionBar({ blockId, blockType, disabled = false }: ActionBarProps) {
const {
collaborativeRemoveBlock,
collaborativeBatchAddBlocks,
collaborativeBatchRemoveBlocks,
collaborativeToggleBlockEnabled,
collaborativeDuplicateBlock,
collaborativeToggleBlockHandles,
} = useCollaborativeWorkflow()
const { activeWorkflowId } = useWorkflowRegistry()
const blocks = useWorkflowStore((state) => state.blocks)
const subBlockStore = useSubBlockStore()

const handleDuplicateBlock = useCallback(() => {
const sourceBlock = blocks[blockId]
if (!sourceBlock) return

const newId = crypto.randomUUID()
const newName = getUniqueBlockName(sourceBlock.name, blocks)
const subBlockValues = subBlockStore.workflowValues[activeWorkflowId || '']?.[blockId] || {}

const { block, subBlockValues: filteredValues } = prepareDuplicateBlockState({
sourceBlock,
newId,
newName,
positionOffset: DEFAULT_DUPLICATE_OFFSET,
subBlockValues,
})

collaborativeBatchAddBlocks([block], [], {}, {}, { [newId]: filteredValues })
}, [
blockId,
blocks,
activeWorkflowId,
subBlockStore.workflowValues,
collaborativeBatchAddBlocks,
])

/**
* Optimized single store subscription for all block data
Expand DownExpand Up@@ -115,7 +148,7 @@ export const ActionBar = memo(
onClick={(e) => {
e.stopPropagation()
if (!disabled) {
collaborativeDuplicateBlock(blockId)
handleDuplicateBlock()
}
}}
className='hover:!text-[var(--text-inverse)] h-[23px] w-[23px] rounded-[8px] bg-[var(--surface-7)] p-0 text-[var(--text-secondary)] hover:bg-[var(--brand-secondary)]'
Expand DownExpand Up@@ -185,7 +218,7 @@ export const ActionBar = memo(
onClick={(e) => {
e.stopPropagation()
if (!disabled) {
collaborativeRemoveBlock(blockId)
collaborativeBatchRemoveBlocks([blockId])
}
}}
className='hover:!text-[var(--text-inverse)] h-[23px] w-[23px] rounded-[8px] bg-[var(--surface-7)] p-0 text-[var(--text-secondary)] hover:bg-[var(--brand-secondary)]'
Expand Down
Loading