Skip to content

Commit d68e16d

Browse files
committed
add Move submenu to file context menu and fix shift-click anchor update
- Add nested Move submenu to FileRowContextMenu using DropdownMenuSub/SubTrigger/SubContent; shows available folders filtered by selection, converts '__root__' -> null for moving to the root level - Add handleContextMenuMove in files.tsx that calls moveItems.mutateAsync directly (no modal) and clears selection on success - Fix shift-click range selection: update lastSelectedIndexRef after range select so chained shift-clicks extend from the new anchor point correctly
1 parent c129135 commit d68e16d

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/components/file-row-context-menu/file-row-context-menu.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
11
'use client'
22

33
import { memo } from 'react'
4+
import { FolderInput } from 'lucide-react'
45
import {
56
Download,
67
DropdownMenu,
78
DropdownMenuContent,
89
DropdownMenuItem,
910
DropdownMenuSeparator,
11+
DropdownMenuSub,
12+
DropdownMenuSubContent,
13+
DropdownMenuSubTrigger,
1014
DropdownMenuTrigger,
1115
Eye,
1216
Pencil,
1317
Trash2,
1418
} from '@/components/emcn'
19+
import { Folder } from '@/components/emcn/icons'
20+
21+
interface MoveOption {
22+
value: string
23+
label: string
24+
}
1525

1626
interface FileRowContextMenuProps {
1727
isOpen: boolean
@@ -21,6 +31,8 @@ interface FileRowContextMenuProps {
2131
onDownload?: () => void
2232
onRename: () => void
2333
onDelete: () => void
34+
onMove?: (optionValue: string) => void
35+
moveOptions?: MoveOption[]
2436
canEdit: boolean
2537
selectedCount: number
2638
}
@@ -33,6 +45,8 @@ export const FileRowContextMenu = memo(function FileRowContextMenu({
3345
onDownload,
3446
onRename,
3547
onDelete,
48+
onMove,
49+
moveOptions,
3650
canEdit,
3751
selectedCount,
3852
}: FileRowContextMenuProps) {
@@ -81,6 +95,22 @@ export const FileRowContextMenu = memo(function FileRowContextMenu({
8195
Rename
8296
</DropdownMenuItem>
8397
)}
98+
{onMove && moveOptions && moveOptions.length > 0 && (
99+
<DropdownMenuSub>
100+
<DropdownMenuSubTrigger>
101+
<FolderInput />
102+
{isMultiSelect ? `Move ${selectedCount} items` : 'Move to'}
103+
</DropdownMenuSubTrigger>
104+
<DropdownMenuSubContent>
105+
{moveOptions.map((option) => (
106+
<DropdownMenuItem key={option.value} onSelect={() => onMove(option.value)}>
107+
<Folder />
108+
{option.label}
109+
</DropdownMenuItem>
110+
))}
111+
</DropdownMenuSubContent>
112+
</DropdownMenuSub>
113+
)}
84114
<DropdownMenuItem onSelect={onDelete}>
85115
<Trash2 />
86116
{isMultiSelect ? `Delete ${selectedCount} items` : 'Delete'}

apps/sim/app/workspace/[workspaceId]/files/files.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ export function Files() {
509509
for (let i = start; i <= end; i++) next.add(visibleRowIds[i])
510510
return next
511511
})
512+
lastSelectedIndexRef.current = currentIndex
512513
} else {
513514
setSelectedRowIds((prev) => {
514515
const next = new Set(prev)
@@ -1194,6 +1195,26 @@ export function Files() {
11941195
closeContextMenu()
11951196
}, [selectedRowIds, handleBulkDelete, closeContextMenu])
11961197

1198+
const handleContextMenuMove = useCallback(
1199+
async (optionValue: string) => {
1200+
const targetFolderId = optionValue === '__root__' ? null : optionValue
1201+
try {
1202+
await moveItems.mutateAsync({
1203+
workspaceId,
1204+
fileIds: selectedFileIds,
1205+
folderIds: selectedFolderIds,
1206+
targetFolderId,
1207+
})
1208+
setSelectedRowIds(new Set())
1209+
closeContextMenu()
1210+
} catch (error) {
1211+
logger.error('Failed to move items:', error)
1212+
toast.error(toError(error).message)
1213+
}
1214+
},
1215+
[moveItems.mutateAsync, workspaceId, selectedFileIds, selectedFolderIds, closeContextMenu]
1216+
)
1217+
11971218
const handleContentContextMenu = useCallback(
11981219
(e: React.MouseEvent) => {
11991220
const target = e.target as HTMLElement
@@ -1799,6 +1820,8 @@ export function Files() {
17991820
onDownload={handleContextMenuDownload}
18001821
onRename={handleContextMenuRename}
18011822
onDelete={handleContextMenuDelete}
1823+
onMove={handleContextMenuMove}
1824+
moveOptions={moveFolderOptions}
18021825
canEdit={canEdit}
18031826
selectedCount={selectedRowIds.size}
18041827
/>

0 commit comments

Comments
 (0)