diff --git a/src/components/Explorer/ProjectExplorer.tsx b/src/components/Explorer/ProjectExplorer.tsx index 13655bb2a..6856ece15 100644 --- a/src/components/Explorer/ProjectExplorer.tsx +++ b/src/components/Explorer/ProjectExplorer.tsx @@ -169,37 +169,54 @@ export const ProjectExplorer = ({ isRenamingRef.current = true }, rowRenameEnd: (event) => { + // TODO: Implement renameFolder and renameFile to navigate setIsRenaming(false) isRenamingRef.current = false - const requestedFolderName = String(event?.target?.value || '') - if (!requestedFolderName) { + const requestedName = String(event?.target?.value || '') + if (!requestedName) { // user pressed esc return } - const folderName = row.name - if (requestedFolderName !== folderName) { + const name = row.name + // Rename a folder + if (row.isFolder) { + if (requestedName !== name) { + systemIOActor.send({ + type: SystemIOMachineEvents.renameFolder, + data: { + requestedFolderName: requestedName, + folderName: name, + absolutePathToParentDirectory: joinOSPaths( + projectDirectoryPath, + child.parentPath + ), + }, + }) + // TODO: Gotcha... Set new string open even if it fails? + if (openedRowsRef.current[child.key]) { + // If the file tree had the folder opened make the new one open. + const newOpenedRows = { ...openedRowsRef.current } + const key = constructPath({ + parentPath: child.parentPath, + name: requestedName, + }) + newOpenedRows[key] = true + setOpenedRows(newOpenedRows) + } + } + } else { + // rename a file systemIOActor.send({ - type: SystemIOMachineEvents.renameFolder, + type: SystemIOMachineEvents.renameFile, data: { - requestedFolderName, - folderName, + requestedFileNameWithExtension: requestedName, + fileNameWithExtension: name, absolutePathToParentDirectory: joinOSPaths( projectDirectoryPath, child.parentPath ), }, }) - // TODO: Gotcha... Set new string open even if it fails? - if (openedRowsRef.current[child.key]) { - // If the file tree had the folder opened make the new one open. - const newOpenedRows = { ...openedRowsRef.current } - const key = constructPath({ - parentPath: child.parentPath, - name: requestedFolderName, - }) - newOpenedRows[key] = true - setOpenedRows(newOpenedRows) - } } }, } @@ -237,8 +254,10 @@ export const ProjectExplorer = ({ } const keyDownHandler = (event) => { - - if (activeIndexRef.current === NOTHING_IS_SELECTED || isRenamingRef.current) { + if ( + activeIndexRef.current === NOTHING_IS_SELECTED || + isRenamingRef.current + ) { // NO OP you are not focused in this DOM element return } diff --git a/src/machines/systemIO/systemIOMachine.ts b/src/machines/systemIO/systemIOMachine.ts index 0dbc15a52..86f72d2d7 100644 --- a/src/machines/systemIO/systemIOMachine.ts +++ b/src/machines/systemIO/systemIOMachine.ts @@ -148,6 +148,14 @@ export const systemIOMachine = setup({ folderName: string absolutePathToParentDirectory: string } + } + | { + type: SystemIOMachineEvents.renameFile + data: { + requestedFileNameWithExtension: string + fileNameWithExtension: string + absolutePathToParentDirectory: string + } }, }, actions: { @@ -393,6 +401,21 @@ export const systemIOMachine = setup({ return { message: '', folderName: '', requestedFolderName: '' } } ), + [SystemIOMachineActors.renameFile]: fromPromise( + async ({ + input, + }: { + input: { + context: SystemIOContext + rootContext: AppMachineContext + requestedFileNameWithExtension: string + fileNameWithExtension: string + absolutePathToParentDirectory: string + } + }) => { + return { message: '', fileNameWithExtension: '', requestedFileNameWithExtension: '' } + } + ), }, }).createMachine({ initial: SystemIOMachineStates.idle, @@ -474,6 +497,9 @@ export const systemIOMachine = setup({ [SystemIOMachineEvents.renameFolder]: { target: SystemIOMachineStates.renamingFolder, }, + [SystemIOMachineEvents.renameFile]: { + target: SystemIOMachineStates.renamingFile, + }, }, }, [SystemIOMachineStates.readingFolders]: { @@ -802,12 +828,38 @@ export const systemIOMachine = setup({ requestedFolderName: event.data.requestedFolderName, folderName: event.data.folderName, absolutePathToParentDirectory: - event.data.absolutePathToParentDirectory, + event.data.absolutePathToParentDirectory, rootContext: self.system.get('root').getSnapshot().context, } }, onDone: { target: SystemIOMachineStates.readingFolders, + actions: [SystemIOMachineActions.toastSuccess], + }, + onError: { + target: SystemIOMachineStates.idle, + actions: [SystemIOMachineActions.toastError], + }, + }, + }, + [SystemIOMachineStates.renamingFile]: { + invoke: { + id: SystemIOMachineActors.renameFile, + src: SystemIOMachineActors.renameFile, + input: ({ context, event, self }) => { + assertEvent(event, SystemIOMachineEvents.renameFile) + return { + context, + requestedFileNameWithExtension: event.data.requestedFileNameWithExtension, + fileNameWithExtension: event.data.fileNameWithExtension, + absolutePathToParentDirectory: + event.data.absolutePathToParentDirectory, + rootContext: self.system.get('root').getSnapshot().context, + } + }, + onDone: { + target: SystemIOMachineStates.readingFolders, + actions: [SystemIOMachineActions.toastSuccess], }, onError: { target: SystemIOMachineStates.idle, diff --git a/src/machines/systemIO/systemIOMachineDesktop.ts b/src/machines/systemIO/systemIOMachineDesktop.ts index c620ba407..b44a4c629 100644 --- a/src/machines/systemIO/systemIOMachineDesktop.ts +++ b/src/machines/systemIO/systemIOMachineDesktop.ts @@ -453,5 +453,61 @@ export const systemIOMachineDesktop = systemIOMachine.provide({ } } ), + [SystemIOMachineActors.renameFile]: fromPromise( + async ({ + input, + }: { + input: { + context: SystemIOContext + rootContext: AppMachineContext + requestedFileNameWithExtension: string + fileNameWithExtension: string + absolutePathToParentDirectory: string + } + }) => { + const { + fileNameWithExtension, + requestedFileNameWithExtension, + absolutePathToParentDirectory, + } = input + + const oldPath = window.electron.path.join( + absolutePathToParentDirectory, + fileNameWithExtension + ) + const newPath = window.electron.path.join( + absolutePathToParentDirectory, + requestedFileNameWithExtension + ) + + // no-op + if (oldPath === newPath) { + return { + message: `Old is the same as new.`, + fileNameWithExtension, + requestedFileNameWithExtension, + } + } + + // if there are any siblings with the same name, report error. + const entries = await window.electron.readdir( + window.electron.path.dirname(newPath) + ) + + for (let entry of entries) { + if (entry === requestedFileNameWithExtension) { + return Promise.reject(new Error('Filename already exists.')) + } + } + + window.electron.rename(oldPath, newPath) + + return { + message: `Successfully renamed "${fileNameWithExtension}" to "${requestedFileNameWithExtension}"`, + fileNameWithExtension, + requestedFileNameWithExtension + } + } + ), }, }) diff --git a/src/machines/systemIO/utils.ts b/src/machines/systemIO/utils.ts index f9ae4a7dc..8a6d12c5f 100644 --- a/src/machines/systemIO/utils.ts +++ b/src/machines/systemIO/utils.ts @@ -17,6 +17,7 @@ export enum SystemIOMachineActors { bulkCreateKCLFilesAndNavigateToProject = 'bulk create kcl files and navigate to project', bulkCreateKCLFilesAndNavigateToFile = 'bulk create kcl files and navigate to file', renameFolder = 'renameFolder', + renameFile = 'renameFile' } export enum SystemIOMachineStates { @@ -35,6 +36,7 @@ export enum SystemIOMachineStates { bulkCreatingKCLFilesAndNavigateToProject = 'bulkCreatingKCLFilesAndNavigateToProject', bulkCreatingKCLFilesAndNavigateToFile = 'bulkCreatingKCLFilesAndNavigateToFile', renamingFolder = 'renamingFolder', + renamingFile = 'renamingFile' } const donePrefix = 'xstate.done.actor.' @@ -64,6 +66,7 @@ export enum SystemIOMachineEvents { done_bulkCreateKCLFilesAndNavigateToFile = donePrefix + 'bulk create kcl files and navigate to file', renameFolder = 'rename folder', + renameFile = 'rename file' } export enum SystemIOMachineActions {