diff --git a/src/components/FileSidebar.tsx b/src/components/FileSidebar.tsx index e039ccb0d..0a0c242fd 100644 --- a/src/components/FileSidebar.tsx +++ b/src/components/FileSidebar.tsx @@ -7,6 +7,8 @@ import { transformFilesToTreeData } from "@/lib/utils/transformFilesToTreeData" import type { ICreateFileProps, ICreateFileResult, + IDeleteDirectoryProps, + IDeleteDirectoryResult, IDeleteFileProps, IDeleteFileResult, IRenameFileProps, @@ -23,6 +25,9 @@ interface FileSidebarProps { fileSidebarState: ReturnType> handleCreateFile: (props: ICreateFileProps) => ICreateFileResult handleDeleteFile: (props: IDeleteFileProps) => IDeleteFileResult + handleDeleteDirectory: ( + props: IDeleteDirectoryProps, + ) => IDeleteDirectoryResult handleRenameFile: (props: IRenameFileProps) => IRenameFileResult isCreatingFile: boolean setIsCreatingFile: React.Dispatch> @@ -39,6 +44,7 @@ const FileSidebar: React.FC = ({ fileSidebarState, handleCreateFile, handleDeleteFile, + handleDeleteDirectory, handleRenameFile, isCreatingFile, setIsCreatingFile, @@ -67,6 +73,7 @@ const FileSidebar: React.FC = ({ renamingFile, handleRenameFile, handleDeleteFile, + handleDeleteDirectory, setRenamingFile, onFileSelect, onFolderSelect, diff --git a/src/components/package-port/CodeAndPreview.tsx b/src/components/package-port/CodeAndPreview.tsx index 02a9f2cb7..5728539dd 100644 --- a/src/components/package-port/CodeAndPreview.tsx +++ b/src/components/package-port/CodeAndPreview.tsx @@ -101,6 +101,7 @@ export function CodeAndPreview({ pkg, projectUrl, isPackageFetched }: Props) { createFile, mainComponentPath, deleteFile, + deleteDirectory, isFullyLoaded, onFileSelect, totalFilesCount, @@ -239,6 +240,7 @@ export function CodeAndPreview({ pkg, projectUrl, isPackageFetched }: Props) { loadedFilesCount={loadedFilesCount} isFullyLoaded={isFullyLoaded} handleDeleteFile={deleteFile} + handleDeleteDirectory={deleteDirectory} handleRenameFile={renameFile} isPriorityFileFetched={ !priorityFileFetched && Boolean(urlParams.package_id) diff --git a/src/components/package-port/CodeEditor.tsx b/src/components/package-port/CodeEditor.tsx index e365d91a6..0d4ced01d 100644 --- a/src/components/package-port/CodeEditor.tsx +++ b/src/components/package-port/CodeEditor.tsx @@ -9,6 +9,8 @@ import { useShikiHighlighter } from "@/hooks/use-shiki-highlighter" import { ICreateFileProps, ICreateFileResult, + IDeleteDirectoryProps, + IDeleteDirectoryResult, IDeleteFileProps, IDeleteFileResult, IRenameFileProps, @@ -74,6 +76,7 @@ export const CodeEditor = ({ handleRenameFile, handleCreateFile, handleDeleteFile, + handleDeleteDirectory, pkg, isFullyLoaded = false, totalFilesCount = 0, @@ -85,6 +88,9 @@ export const CodeEditor = ({ isSaving?: boolean handleCreateFile: (props: ICreateFileProps) => ICreateFileResult handleDeleteFile: (props: IDeleteFileProps) => IDeleteFileResult + handleDeleteDirectory: ( + props: IDeleteDirectoryProps, + ) => IDeleteDirectoryResult handleRenameFile: (props: IRenameFileProps) => IRenameFileResult pkg?: Package readOnly?: boolean @@ -814,6 +820,7 @@ export const CodeEditor = ({ handleCreateFile={handleCreateFile} handleRenameFile={handleRenameFile} handleDeleteFile={handleDeleteFile} + handleDeleteDirectory={handleDeleteDirectory} isCreatingFile={isCreatingFile} setIsCreatingFile={setIsCreatingFile} pkg={pkg} diff --git a/src/hooks/useFileManagement.ts b/src/hooks/useFileManagement.ts index 7c5f12a56..d7a24fd41 100644 --- a/src/hooks/useFileManagement.ts +++ b/src/hooks/useFileManagement.ts @@ -36,6 +36,15 @@ export interface IDeleteFileProps { onError: (error: Error) => void } +export interface IDeleteDirectoryProps { + directoryPath: string + onError: (error: Error) => void +} + +export interface IDeleteDirectoryResult { + directoryDeleted: boolean +} + export interface IRenameFileProps { oldFilename: string newFilename: string @@ -403,18 +412,30 @@ export function useFileManagement({ const fileExists = localFiles?.some((file) => file.path === filename) if (!fileExists) { onError(new Error("File does not exist")) - return { - fileDeleted: false, - } + return { fileDeleted: false } } const updatedFiles = localFiles.filter((file) => file.path !== filename) setLocalFiles(updatedFiles) onFileSelect( updatedFiles.filter((file) => !isHiddenFile(file.path))[0]?.path || "", ) - return { - fileDeleted: true, - } + return { fileDeleted: true } + } + + const deleteDirectory = ({ + directoryPath, + onError, + }: IDeleteDirectoryProps): IDeleteDirectoryResult => { + const normalizedDir = directoryPath.replace(/\/+$/, "") + "/" + const updatedFiles = localFiles.filter( + (file) => + file.path !== directoryPath && !file.path.startsWith(normalizedDir), + ) + setLocalFiles(updatedFiles) + onFileSelect( + updatedFiles.filter((f) => !isHiddenFile(f.path))[0]?.path || "", + ) + return { directoryDeleted: true } } const renameFile = ({ @@ -628,6 +649,7 @@ export function useFileManagement({ createFile, priorityFileFetched, deleteFile, + deleteDirectory, renameFile, saveFiles, localFiles, diff --git a/src/lib/utils/transformFilesToTreeData.tsx b/src/lib/utils/transformFilesToTreeData.tsx index 27e3b6cef..f9b842843 100644 --- a/src/lib/utils/transformFilesToTreeData.tsx +++ b/src/lib/utils/transformFilesToTreeData.tsx @@ -3,6 +3,7 @@ import type { TreeDataItem } from "@/components/ui/tree-view" import type { IRenameFileProps, IDeleteFileProps, + IDeleteDirectoryProps, } from "@/hooks/useFileManagement" import { isHiddenFile } from "@/components/ViewPackagePage/utils/is-hidden-file" import { File, Folder, MoreVertical, Pencil, Trash2 } from "lucide-react" @@ -25,6 +26,9 @@ interface TransformFilesToTreeDataProps { renamingFile: string | null handleRenameFile: (props: IRenameFileProps) => { fileRenamed: boolean } handleDeleteFile: (props: IDeleteFileProps) => { fileDeleted: boolean } + handleDeleteDirectory: (props: IDeleteDirectoryProps) => { + directoryDeleted: boolean + } setRenamingFile: (filename: string | null) => void onFileSelect: (filename: FileName) => void onFolderSelect: (folderPath: string) => void @@ -41,6 +45,7 @@ export const transformFilesToTreeData = ({ renamingFile, handleRenameFile, handleDeleteFile, + handleDeleteDirectory, setRenamingFile, onFileSelect, onFolderSelect, @@ -162,17 +167,28 @@ export const transformFilesToTreeData = ({ )} { - const { fileDeleted } = handleDeleteFile({ - filename: itemId, - onError: (error) => { - toast({ - title: `Error deleting file ${itemId}`, - description: error.message, - }) - }, - }) - if (fileDeleted) { - setErrorMessage("") + if (isLeafNode) { + const { fileDeleted } = handleDeleteFile({ + filename: itemId, + onError: (error) => { + toast({ + title: `Error deleting file ${itemId}`, + description: error.message, + }) + }, + }) + if (fileDeleted) setErrorMessage("") + } else { + const { directoryDeleted } = handleDeleteDirectory({ + directoryPath: itemId, + onError: (error) => { + toast({ + title: `Error deleting directory ${itemId}`, + description: error.message, + }) + }, + }) + if (directoryDeleted) setErrorMessage("") } setOpenDropdownId(null) }}