fix: renaming folders!

This commit is contained in:
Kevin
2025-06-17 12:08:37 -05:00
parent 6ac164d15c
commit 5e972eb18f
5 changed files with 138 additions and 9 deletions

View File

@ -162,7 +162,7 @@ function RenameForm({
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Escape') {
e.stopPropagation()
onSubmit(e)
onSubmit()
} else if (e.key === 'Enter') {
// This is needed to prevent events to bubble up and the form to be submitted.
// (Alternatively the form could be changed into a div.)
@ -274,7 +274,7 @@ export const FileExplorerRowElement = ({
onSubmit={(event) => {
row.rowRenameEnd(event)
}}
></RenameForm>
></RenameForm>
)}
<div className="ml-auto">{row.status}</div>
<div style={{ width: '0.25rem' }}></div>

View File

@ -18,6 +18,10 @@ import { useState, useRef, useEffect } from 'react'
import { systemIOActor } from '@src/lib/singletons'
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
import { sortFilesAndDirectories } from '@src/lib/desktopFS'
import { joinOSPaths } from '@src/lib/paths'
import {
useProjectDirectoryPath,
} from '@src/machines/systemIO/hooks'
const isFileExplorerEntryOpened = (
rows: { [key: string]: boolean },
@ -41,6 +45,8 @@ export const ProjectExplorer = ({
}: {
project: Project
}) => {
const projectDirectoryPath = useProjectDirectoryPath()
// cache the state of opened rows to allow nested rows to be opened if a parent one is closed
// when the parent opens the children will already be opened
const [openedRows, setOpenedRows] = useState<{ [key: string]: boolean }>({})
@ -164,12 +170,31 @@ export const ProjectExplorer = ({
},
rowRenameEnd: (event) => {
setIsRenaming(false)
const requestedRename = String(event.target.value)
const name = row.name
// if (requestedProjectName !== projectName) {
// }
}
const requestedFolderName = String(event?.target?.value || '')
if (!requestedFolderName) {
// user pressed esc
return
}
const folderName = row.name
if (requestedFolderName !== folderName) {
systemIOActor.send({type:SystemIOMachineEvents.renameFolder, data: {
requestedFolderName,
folderName,
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)
}
}
},
}
return row

View File

@ -140,7 +140,15 @@ export const systemIOMachine = setup({
requestedProjectName: string
requestedFileName: string
}
},
}
| {
type: SystemIOMachineEvents.renameFolder
data: {
requestedFolderName: string
folderName: string
absolutePathToParentDirectory: string
}
}
},
actions: {
[SystemIOMachineActions.setFolders]: assign({
@ -370,6 +378,21 @@ export const systemIOMachine = setup({
return { message: '', fileName: '', projectName: '', subRoute: '' }
}
),
[SystemIOMachineActors.renameFolder]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
rootContext: AppMachineContext
requestedFolderName: string
folderName: string
absolutePathToParentDirectory: string
}
}) => {
return { message: '', folderName: '', requestedFolderName: '' }
}
),
},
}).createMachine({
initial: SystemIOMachineStates.idle,
@ -448,6 +471,9 @@ export const systemIOMachine = setup({
[SystemIOMachineEvents.bulkCreateKCLFilesAndNavigateToFile]: {
target: SystemIOMachineStates.bulkCreatingKCLFilesAndNavigateToFile,
},
[SystemIOMachineEvents.renameFolder]: {
target: SystemIOMachineStates.renamingFolder,
}
},
},
[SystemIOMachineStates.readingFolders]: {
@ -765,5 +791,28 @@ export const systemIOMachine = setup({
},
},
},
[SystemIOMachineStates.renamingFolder]: {
invoke: {
id: SystemIOMachineActors.renameFolder,
src: SystemIOMachineActors.renameFolder,
input: ({ context, event, self }) => {
assertEvent(event, SystemIOMachineEvents.renameFolder)
return {
context,
requestedFolderName: event.data.requestedFolderName,
folderName: event.data.folderName,
absolutePathToParentDirectory: event.data.absolutePathToParentDirectory,
rootContext: self.system.get('root').getSnapshot().context,
}
},
onDone: {
target: SystemIOMachineStates.readingFolders,
},
onError: {
target: SystemIOMachineStates.idle,
actions: [SystemIOMachineActions.toastError],
},
},
},
},
})

View File

@ -398,5 +398,57 @@ export const systemIOMachineDesktop = systemIOMachine.provide({
}
}
),
[SystemIOMachineActors.renameFolder]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
rootContext: AppMachineContext
requestedFolderName: string
folderName: string
absolutePathToParentDirectory: string
}
}) => {
const { folderName, requestedFolderName, absolutePathToParentDirectory} = input
const oldPath = window.electron.path.join(
absolutePathToParentDirectory,
folderName
)
const newPath = window.electron.path.join(
absolutePathToParentDirectory,
requestedFolderName
)
// no-op
if (oldPath === newPath) {
return {
message: `Old is the same as new.`,
folderName,
requestedFolderName,
}
}
// 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 === requestedFolderName) {
return Promise.reject(new Error('Filename already exists.'))
}
}
window.electron.rename(oldPath, newPath)
return {
message:`Successfully renamed "${folderName}" to "${requestedFolderName}"`,
folderName,
requestedFolderName
}
}
),
},
})

View File

@ -16,6 +16,7 @@ export enum SystemIOMachineActors {
bulkCreateKCLFiles = 'bulk create kcl files',
bulkCreateKCLFilesAndNavigateToProject = 'bulk create kcl files and navigate to project',
bulkCreateKCLFilesAndNavigateToFile = 'bulk create kcl files and navigate to file',
renameFolder = 'renameFolder',
}
export enum SystemIOMachineStates {
@ -33,6 +34,7 @@ export enum SystemIOMachineStates {
bulkCreatingKCLFiles = 'bulkCreatingKCLFiles',
bulkCreatingKCLFilesAndNavigateToProject = 'bulkCreatingKCLFilesAndNavigateToProject',
bulkCreatingKCLFilesAndNavigateToFile = 'bulkCreatingKCLFilesAndNavigateToFile',
renamingFolder = 'renamingFolder',
}
const donePrefix = 'xstate.done.actor.'
@ -61,6 +63,7 @@ export enum SystemIOMachineEvents {
bulkCreateKCLFilesAndNavigateToFile = 'bulk create kcl files and navigate to file',
done_bulkCreateKCLFilesAndNavigateToFile = donePrefix +
'bulk create kcl files and navigate to file',
renameFolder = 'rename folder',
}
export enum SystemIOMachineActions {