Skip to content

Commit f89a84e

Browse files
committed
rm move file function and fix things with rename and moving
1 parent 845255b commit f89a84e

File tree

7 files changed

+96
-119
lines changed

7 files changed

+96
-119
lines changed

electron/main/filesystem/filesystem.ts

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as fs from 'fs'
2-
import * as fsPromises from 'fs/promises'
32
import * as path from 'path'
43

54
import chokidar from 'chokidar'
@@ -178,39 +177,6 @@ export function readFile(filePath: string): string {
178177
return data
179178
}
180179

181-
export const moveFileOrDirectory = async (sourcePath: string, destinationPath: string): Promise<string> => {
182-
await fsPromises.access(sourcePath)
183-
184-
let destinationStats
185-
try {
186-
destinationStats = await fsPromises.lstat(destinationPath)
187-
} catch (error) {
188-
// Error means destination path does not exist, which is fine
189-
}
190-
191-
let resolvedDestinationPath = destinationPath
192-
if (destinationStats && destinationStats.isFile()) {
193-
resolvedDestinationPath = path.dirname(destinationPath)
194-
}
195-
196-
await fsPromises.mkdir(resolvedDestinationPath, { recursive: true })
197-
198-
const newPath = path.join(resolvedDestinationPath, path.basename(sourcePath))
199-
200-
try {
201-
await fsPromises.access(newPath)
202-
throw new Error(`A file already exists at destination: ${newPath}`)
203-
} catch (error) {
204-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
205-
await fsPromises.rename(sourcePath, newPath)
206-
} else {
207-
throw error
208-
}
209-
}
210-
211-
return newPath
212-
}
213-
214180
export function splitDirectoryPathIntoBaseAndRepo(fullPath: string) {
215181
const normalizedPath = path.normalize(fullPath)
216182

electron/main/filesystem/ipcHandlers.ts

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import * as fs from 'fs'
22
import * as path from 'path'
33

4-
import { ipcMain, BrowserWindow, dialog } from 'electron'
4+
import { ipcMain, dialog } from 'electron'
55
import Store from 'electron-store'
66

77
import WindowsManager from '../common/windowManager'
88
import { StoreSchema } from '../electron-store/storeConfig'
9-
import { orchestrateEntryMove, updateFileInTable } from '../vector-database/tableHelperFunctions'
10-
11-
import {
12-
GetFilesInfoTree,
13-
createFileRecursive,
14-
isHidden,
15-
GetFilesInfoListForListOfPaths,
16-
startWatchingDirectory,
17-
updateFileListForRenderer,
18-
} from './filesystem'
9+
import { handleFileRename, updateFileInTable } from '../vector-database/tableHelperFunctions'
10+
11+
import { GetFilesInfoTree, createFileRecursive, isHidden, GetFilesInfoListForListOfPaths } from './filesystem'
1912
import { FileInfoTree, WriteFileProps, RenameFileProps, FileInfoWithContent } from './types'
2013

2114
const registerFileHandlers = (store: Store<StoreSchema>, _windowsManager: WindowsManager) => {
@@ -91,36 +84,7 @@ const registerFileHandlers = (store: Store<StoreSchema>, _windowsManager: Window
9184
throw new Error('Window info not found.')
9285
}
9386

94-
windowsManager.watcher?.unwatch(windowInfo?.vaultDirectoryForWindow)
95-
96-
if (process.platform === 'win32') {
97-
windowsManager.watcher?.close().then(() => {
98-
fs.rename(renameFileProps.oldFilePath, renameFileProps.newFilePath, (err) => {
99-
if (err) {
100-
throw err
101-
}
102-
103-
// Re-start watching all paths in array
104-
const win = BrowserWindow.fromWebContents(event.sender)
105-
if (win) {
106-
windowsManager.watcher = startWatchingDirectory(win, windowInfo.vaultDirectoryForWindow)
107-
updateFileListForRenderer(win, windowInfo.vaultDirectoryForWindow)
108-
}
109-
})
110-
})
111-
} else {
112-
// On non-Windows platforms, directly perform the rename operation
113-
fs.rename(renameFileProps.oldFilePath, renameFileProps.newFilePath, (err) => {
114-
if (err) {
115-
throw err
116-
}
117-
// Re-watch the vault directory after renaming
118-
windowsManager.watcher?.add(windowInfo?.vaultDirectoryForWindow)
119-
})
120-
}
121-
122-
// then need to trigger reindexing of folder
123-
windowInfo.dbTableClient.updateDBItemsWithNewFilePath(renameFileProps.oldFilePath, renameFileProps.newFilePath)
87+
await handleFileRename(windowsManager, windowInfo, renameFileProps, event.sender)
12488
})
12589

12690
ipcMain.handle('index-file-in-database', async (event, filePath: string) => {
@@ -151,14 +115,6 @@ const registerFileHandlers = (store: Store<StoreSchema>, _windowsManager: Window
151115
}
152116
})
153117

154-
ipcMain.handle('move-file-or-dir', async (event, sourcePath: string, destinationPath: string) => {
155-
const windowInfo = windowsManager.getWindowInfoForContents(event.sender)
156-
if (!windowInfo) {
157-
throw new Error('Window info not found.')
158-
}
159-
orchestrateEntryMove(windowInfo.dbTableClient, sourcePath, destinationPath)
160-
})
161-
162118
ipcMain.handle('get-files', async (_event, filePaths: string[]): Promise<FileInfoWithContent[]> => {
163119
const fileItems = GetFilesInfoListForListOfPaths(filePaths)
164120
const fileContents = fileItems.map((fileItem) => fs.readFileSync(fileItem.path, 'utf-8'))

electron/main/vector-database/tableHelperFunctions.ts

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import * as fs from 'fs'
2+
import * as fsPromises from 'fs/promises'
23

4+
import { BrowserWindow } from 'electron'
35
import { chunkMarkdownByHeadingsAndByCharsIfBig } from '../common/chunking'
46
import {
57
GetFilesInfoList,
6-
GetFilesInfoTree,
78
flattenFileInfoTree,
8-
moveFileOrDirectory,
99
readFile,
10+
updateFileListForRenderer,
11+
startWatchingDirectory,
1012
} from '../filesystem/filesystem'
11-
import { FileInfo, FileInfoTree } from '../filesystem/types'
13+
import { FileInfo, FileInfoTree, RenameFileProps } from '../filesystem/types'
1214

1315
import LanceDBTableWrapper, { convertRecordToDBType } from './lanceTableWrapper'
1416
import { DBEntry, DatabaseFields } from './schema'
17+
import WindowsManager from '../common/windowManager'
1518

1619
const convertFileTypeToDBType = async (file: FileInfo): Promise<DBEntry[]> => {
1720
const fileContent = readFile(file.path)
@@ -27,6 +30,58 @@ const convertFileTypeToDBType = async (file: FileInfo): Promise<DBEntry[]> => {
2730
return entries
2831
}
2932

33+
export const handleFileRename = async (
34+
windowsManager: WindowsManager,
35+
windowInfo: { vaultDirectoryForWindow: string; dbTableClient: any },
36+
renameFileProps: RenameFileProps,
37+
sender: Electron.WebContents,
38+
): Promise<void> => {
39+
windowsManager.watcher?.unwatch(windowInfo.vaultDirectoryForWindow)
40+
41+
try {
42+
await fsPromises.access(renameFileProps.newFilePath)
43+
throw new Error(`A file already exists at destination: ${renameFileProps.newFilePath}`)
44+
} catch (error) {
45+
// If error is ENOENT (file doesn't exist), proceed with rename
46+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
47+
throw error
48+
}
49+
}
50+
51+
if (process.platform === 'win32') {
52+
await windowsManager.watcher?.close()
53+
await new Promise<void>((resolve, reject) => {
54+
fs.rename(renameFileProps.oldFilePath, renameFileProps.newFilePath, (err) => {
55+
if (err) {
56+
reject(err)
57+
return
58+
}
59+
60+
const win = BrowserWindow.fromWebContents(sender)
61+
if (win) {
62+
// eslint-disable-next-line no-param-reassign
63+
windowsManager.watcher = startWatchingDirectory(win, windowInfo.vaultDirectoryForWindow)
64+
updateFileListForRenderer(win, windowInfo.vaultDirectoryForWindow)
65+
}
66+
resolve()
67+
})
68+
})
69+
} else {
70+
await new Promise<void>((resolve, reject) => {
71+
fs.rename(renameFileProps.oldFilePath, renameFileProps.newFilePath, (err) => {
72+
if (err) {
73+
reject(err)
74+
return
75+
}
76+
windowsManager.watcher?.add(windowInfo.vaultDirectoryForWindow)
77+
resolve()
78+
})
79+
})
80+
}
81+
82+
await windowInfo.dbTableClient.updateDBItemsWithNewFilePath(renameFileProps.oldFilePath, renameFileProps.newFilePath)
83+
}
84+
3085
export const convertFileInfoListToDBItems = async (filesInfoList: FileInfo[]): Promise<DBEntry[][]> => {
3186
const promises = filesInfoList.map(convertFileTypeToDBType)
3287
const filesAsChunksToAddToDB = await Promise.all(promises)
@@ -157,16 +212,6 @@ export const addFileTreeToDBTable = async (dbTable: LanceDBTableWrapper, fileTre
157212
await dbTable.add(dbEntries)
158213
}
159214

160-
export const orchestrateEntryMove = async (table: LanceDBTableWrapper, sourcePath: string, destinationPath: string) => {
161-
const fileSystemTree = GetFilesInfoTree(sourcePath)
162-
await removeFileTreeFromDBTable(table, fileSystemTree)
163-
164-
const newDestinationPath = await moveFileOrDirectory(sourcePath, destinationPath)
165-
if (newDestinationPath) {
166-
await addFileTreeToDBTable(table, GetFilesInfoTree(newDestinationPath))
167-
}
168-
}
169-
170215
export function formatTimestampForLanceDB(date: Date): string {
171216
const year = date.getFullYear()
172217
const month = date.getMonth() + 1 // getMonth() is zero-based

electron/preload/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ const fileSystem = {
9090
createDirectory: createIPCHandler<(dirPath: string) => Promise<void>>('create-directory'),
9191
checkFileExists: createIPCHandler<(filePath: string) => Promise<boolean>>('check-file-exists'),
9292
deleteFile: createIPCHandler<(filePath: string) => Promise<void>>('delete-file'),
93-
moveFileOrDir: createIPCHandler<(sourcePath: string, destinationPath: string) => Promise<void>>('move-file-or-dir'),
9493
getAllFilenamesInDirectory: createIPCHandler<(dirName: string) => Promise<string[]>>('get-files-in-directory'),
9594
getFiles: createIPCHandler<(filePaths: string[]) => Promise<FileInfoWithContent[]>>('get-files'),
9695
}

src/components/Sidebars/FileSideBar/FileItemRows.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { FaChevronDown, FaChevronRight } from 'react-icons/fa'
44
import posthog from 'posthog-js'
55
import { isFileNodeDirectory } from '@shared/utils'
66
import { useFileContext } from '@/contexts/FileContext'
7-
import { moveFile, removeFileExtension } from '@/lib/file'
7+
import { removeFileExtension } from '@/lib/file'
88
import { useContentContext } from '@/contexts/ContentContext'
99
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@/components/ui/context-menu'
1010
import NewDirectoryComponent from '@/components/File/NewDirectory'
@@ -20,6 +20,7 @@ const FileItemRows: React.FC<ListChildComponentProps> = ({ index, style, data })
2020
deleteFile,
2121
selectedDirectory,
2222
setSelectedDirectory,
23+
renameFile,
2324
} = useFileContext()
2425
const { openContent, createUntitledNote } = useContentContext()
2526
const [isNewDirectoryModalOpen, setIsNewDirectoryModalOpen] = useState(false)
@@ -54,21 +55,26 @@ const FileItemRows: React.FC<ListChildComponentProps> = ({ index, style, data })
5455
e.stopPropagation()
5556
setIsDragOver(false)
5657
const sourcePath = e.dataTransfer.getData('text/plain')
57-
const destinationPath = isDirectory ? file.path : await window.path.dirname(file.path)
58-
moveFile(sourcePath, destinationPath)
58+
const destinationDirectory = isDirectory ? file.path : await window.path.dirname(file.path)
59+
const destinationPath = await window.path.join(destinationDirectory, await window.path.basename(sourcePath))
60+
renameFile(sourcePath, destinationPath)
5961
},
60-
[file.path, isDirectory],
62+
[file.path, isDirectory, renameFile],
6163
)
6264

63-
const clickOnFileOrDirectory = useCallback(() => {
64-
if (isDirectory) {
65-
handleDirectoryToggle(file.path)
66-
setSelectedDirectory(file.path)
67-
} else {
68-
openContent(file.path)
69-
posthog.capture('open_file_from_sidebar')
70-
}
71-
}, [file.path, isDirectory, handleDirectoryToggle, openContent, setSelectedDirectory])
65+
const clickOnFileOrDirectory = useCallback(
66+
(e: React.MouseEvent) => {
67+
if (isDirectory) {
68+
handleDirectoryToggle(file.path)
69+
setSelectedDirectory(file.path)
70+
} else {
71+
openContent(file.path)
72+
posthog.capture('open_file_from_sidebar')
73+
}
74+
e.stopPropagation()
75+
},
76+
[file.path, isDirectory, handleDirectoryToggle, openContent, setSelectedDirectory],
77+
)
7278

7379
const openNewDirectoryModal = useCallback(async () => {
7480
const dirPath = isDirectory ? file.path : await window.path.dirname(file.path)

src/components/Sidebars/FileSideBar/FileSidebar.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { FixedSizeList } from 'react-window'
44
import { isFileNodeDirectory } from '@shared/utils'
55
import { useFileContext } from '@/contexts/FileContext'
66
import FileItemRows from './FileItemRows'
7-
import { moveFile } from '@/lib/file'
87

98
const getFilesAndIndentationsForSidebar = (
109
files: FileInfoTree,
@@ -32,21 +31,26 @@ interface FileExplorerProps {
3231

3332
const FileSidebar: React.FC<FileExplorerProps> = ({ lheight }) => {
3433
const [listHeight, setListHeight] = useState(lheight ?? window.innerHeight - 50)
35-
const { vaultFilesTree, expandedDirectories } = useFileContext()
34+
const { vaultFilesTree, expandedDirectories, renameFile, setSelectedDirectory } = useFileContext()
3635

3736
const handleDrop = async (e: React.DragEvent) => {
3837
e.preventDefault()
3938
e.stopPropagation()
4039
const sourcePath = e.dataTransfer.getData('text/plain')
41-
const destinationPath = await window.electronStore.getVaultDirectoryForWindow()
42-
moveFile(sourcePath, destinationPath)
40+
const destinationDirectory = await window.electronStore.getVaultDirectoryForWindow()
41+
const destinationPath = await window.path.join(destinationDirectory, await window.path.basename(sourcePath))
42+
renameFile(sourcePath, destinationPath)
4343
}
4444

4545
const handleDragOver = (e: React.DragEvent) => {
4646
e.preventDefault()
4747
e.stopPropagation()
4848
}
4949

50+
const handleClick = () => {
51+
setSelectedDirectory(null)
52+
}
53+
5054
useEffect(() => {
5155
const updateHeight = () => {
5256
setListHeight(lheight ?? window.innerHeight - 50)
@@ -61,7 +65,12 @@ const FileSidebar: React.FC<FileExplorerProps> = ({ lheight }) => {
6165
const itemCount = filesAndIndentations.length
6266

6367
return (
64-
<div className="h-full grow px-1 pt-2 opacity-70" onDrop={handleDrop} onDragOver={handleDragOver}>
68+
<div
69+
className="h-full grow px-1 pt-2 opacity-70"
70+
onDrop={handleDrop}
71+
onDragOver={handleDragOver}
72+
onClick={handleClick}
73+
>
6574
<FixedSizeList
6675
height={listHeight}
6776
itemCount={itemCount}

src/lib/file.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ export function flattenFileInfoTree(tree: FileInfoTree): FileInfo[] {
1919
}, [])
2020
}
2121

22-
export const moveFile = async (sourcePath: string, destinationPath: string) => {
23-
await window.fileSystem.moveFileOrDir(sourcePath, destinationPath)
24-
}
25-
2622
export const getFilesInDirectory = async (directoryPath: string, filesTree: FileInfo[]): Promise<FileInfo[]> => {
2723
return filesTree.filter((file) => file.path.startsWith(directoryPath))
2824
}

0 commit comments

Comments
 (0)