From 07d3802baa77d0a9c4fb87072e22a854bc7f63c9 Mon Sep 17 00:00:00 2001 From: James Murdza Date: Sun, 17 Nov 2024 13:25:16 -0500 Subject: [PATCH] fix: reload the entire file list after adding or deleting files --- backend/server/src/FileManager.ts | 104 +++---------------- frontend/components/editor/index.tsx | 11 +- frontend/components/editor/sidebar/index.tsx | 3 - frontend/components/editor/sidebar/new.tsx | 16 +-- frontend/lib/utils.ts | 27 +---- 5 files changed, 20 insertions(+), 141 deletions(-) diff --git a/backend/server/src/FileManager.ts b/backend/server/src/FileManager.ts index 775313e..9568557 100644 --- a/backend/server/src/FileManager.ts +++ b/backend/server/src/FileManager.ts @@ -125,6 +125,19 @@ export class FileManager { return this.files } + private async loadLocalFiles() { + // Reload file list from the container to include template files + const result = await this.sandbox.commands.run( + `find "${this.dirName}" -type f` + ) // List all files recursively + + const localPaths = result.stdout.split("\n").filter((path) => path) // Split the output into an array and filter out empty strings + const relativePaths = localPaths.map((filePath) => + path.posix.relative(this.dirName, filePath) + ) // Convert absolute paths to relative paths + this.files = generateFileStructure(relativePaths) + } + // Initialize the FileManager async initialize() { // Download files from remote file storage @@ -146,15 +159,7 @@ export class FileManager { }) await Promise.all(promises) - // Reload file list from the container to include template files - const result = await this.sandbox.commands.run( - `find "${this.dirName}" -type f` - ) // List all files recursively - const localPaths = result.stdout.split("\n").filter((path) => path) // Split the output into an array and filter out empty strings - const relativePaths = localPaths.map((filePath) => - path.posix.relative(this.dirName, filePath) - ) // Convert absolute paths to relative paths - this.files = generateFileStructure(relativePaths) + await this.loadLocalFiles() // Make the logged in user the owner of all project files this.fixPermissions() @@ -221,77 +226,13 @@ export class FileManager { // Handle file/directory creation event if (event.type === "create") { - const folder = findFolderById( - this.files, - sandboxDirectory - ) as TFolder - const isDir = await this.isDirectory(containerFilePath) - - const newItem = isDir - ? ({ - id: sandboxFilePath, - name: event.name, - type: "folder", - children: [], - } as TFolder) - : ({ - id: sandboxFilePath, - name: event.name, - type: "file", - } as TFile) - - if (folder) { - // If the folder exists, add the new item (file/folder) as a child - folder.children.push(newItem) - } else { - // If folder doesn't exist, add the new item to the root - this.files.push(newItem) - } - - if (!isDir) { - const fileData = await this.sandbox.files.read( - containerFilePath - ) - const fileContents = - typeof fileData === "string" ? fileData : "" - this.fileData.push({ - id: sandboxFilePath, - data: fileContents, - }) - } - + await this.loadLocalFiles() console.log(`Create ${sandboxFilePath}`) } // Handle file/directory removal or rename event else if (event.type === "remove" || event.type == "rename") { - const folder = findFolderById( - this.files, - sandboxDirectory - ) as TFolder - const isDir = await this.isDirectory(containerFilePath) - - const isFileMatch = (file: TFolder | TFile | TFileData) => - file.id === sandboxFilePath || - file.id.startsWith(containerFilePath + "/") - - if (folder) { - // Remove item from its parent folder - folder.children = folder.children.filter( - (file: TFolder | TFile) => !isFileMatch(file) - ) - } else { - // Remove from the root if it's not inside a folder - this.files = this.files.filter( - (file: TFolder | TFile) => !isFileMatch(file) - ) - } - - // Also remove any corresponding file data - this.fileData = this.fileData.filter( - (file: TFileData) => !isFileMatch(file) - ) - + await this.loadLocalFiles() console.log(`Removed: ${sandboxFilePath}`) } @@ -458,17 +399,6 @@ export class FileManager { await this.sandbox.files.write(path.posix.join(this.dirName, id), "") await this.fixPermissions() - this.files.push({ - id, - name, - type: "file", - }) - - this.fileData.push({ - id, - data: "", - }) - await RemoteFileStorage.createFile(this.getRemoteFileId(id)) return true @@ -568,7 +498,6 @@ export class FileManager { if (!file) return this.files await this.sandbox.files.remove(path.posix.join(this.dirName, fileId)) - this.fileData = this.fileData.filter((f) => f.id !== fileId) await RemoteFileStorage.deleteFile(this.getRemoteFileId(fileId)) return this.updateFileStructure() @@ -583,7 +512,6 @@ export class FileManager { await Promise.all( files.map(async (file) => { await this.sandbox.files.remove(path.posix.join(this.dirName, file)) - this.fileData = this.fileData.filter((f) => f.id !== file) await RemoteFileStorage.deleteFile(this.getRemoteFileId(file)) }) ) diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx index bf7e5ec..1347c66 100644 --- a/frontend/components/editor/index.tsx +++ b/frontend/components/editor/index.tsx @@ -23,7 +23,6 @@ import { useSocket } from "@/context/SocketContext" import { parseTSConfigToMonacoOptions } from "@/lib/tsconfig" import { Sandbox, TFile, TFolder, TTab, User } from "@/lib/types" import { - addNew, cn, debounce, deepMerge, @@ -856,13 +855,7 @@ export default function CodeEditor({ } const handleDeleteFile = (file: TFile) => { - socket?.emit( - "deleteFile", - { fileId: file.id }, - (response: (TFolder | TFile)[]) => { - setFiles(response) - } - ) + socket?.emit("deleteFile", { fileId: file.id }) closeTab(file.id) } @@ -878,7 +871,6 @@ export default function CodeEditor({ "deleteFolder", { folderId: folder.id }, (response: (TFolder | TFile)[]) => { - setFiles(response) setDeletingFolderId("") } ) @@ -1047,7 +1039,6 @@ export default function CodeEditor({ handleDeleteFolder={handleDeleteFolder} socket={socket!} setFiles={setFiles} - addNew={(name, type) => addNew(name, type, setFiles, sandboxData)} deletingFolderId={deletingFolderId} toggleAIChat={toggleAIChat} isAIChatOpen={isAIChatOpen} diff --git a/frontend/components/editor/sidebar/index.tsx b/frontend/components/editor/sidebar/index.tsx index 0af1c99..6d2a2af 100644 --- a/frontend/components/editor/sidebar/index.tsx +++ b/frontend/components/editor/sidebar/index.tsx @@ -25,7 +25,6 @@ export default function Sidebar({ handleDeleteFolder, socket, setFiles, - addNew, deletingFolderId, toggleAIChat, isAIChatOpen, @@ -43,7 +42,6 @@ export default function Sidebar({ handleDeleteFolder: (folder: TFolder) => void socket: Socket setFiles: (files: (TFile | TFolder)[]) => void - addNew: (name: string, type: "file" | "folder") => void deletingFolderId: string toggleAIChat: () => void isAIChatOpen: boolean @@ -176,7 +174,6 @@ export default function Sidebar({ stopEditing={() => { setCreatingNew(null) }} - addNew={addNew} /> ) : null} diff --git a/frontend/components/editor/sidebar/new.tsx b/frontend/components/editor/sidebar/new.tsx index ca7dbc9..43334a4 100644 --- a/frontend/components/editor/sidebar/new.tsx +++ b/frontend/components/editor/sidebar/new.tsx @@ -9,12 +9,10 @@ export default function New({ socket, type, stopEditing, - addNew, }: { socket: Socket type: "file" | "folder" stopEditing: () => void - addNew: (name: string, type: "file" | "folder") => void }) { const inputRef = useRef(null) @@ -25,19 +23,9 @@ export default function New({ const valid = validateName(name, "", type) if (valid.status) { if (type === "file") { - socket.emit( - "createFile", - { name }, - ({ success }: { success: boolean }) => { - if (success) { - addNew(name, type) - } - } - ) + socket.emit("createFile", { name }) } else { - socket.emit("createFolder", { name }, () => { - addNew(name, type) - }) + socket.emit("createFolder", { name }) } } } diff --git a/frontend/lib/utils.ts b/frontend/lib/utils.ts index 7414be4..194f71b 100644 --- a/frontend/lib/utils.ts +++ b/frontend/lib/utils.ts @@ -2,7 +2,7 @@ import { type ClassValue, clsx } from "clsx" // import { toast } from "sonner" import { twMerge } from "tailwind-merge" import fileExtToLang from "./file-extension-to-language.json" -import { Sandbox, TFile, TFolder } from "./types" +import { TFile, TFolder } from "./types" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) @@ -38,31 +38,6 @@ export function validateName( return { status: true, message: "" } } -export function addNew( - name: string, - type: "file" | "folder", - setFiles: React.Dispatch>, - sandboxData: Sandbox -) { - if (type === "file") { - setFiles((prev) => [ - ...prev, - { id: `projects/${sandboxData.id}/${name}`, name, type: "file" }, - ]) - } else { - console.log("adding folder") - setFiles((prev) => [ - ...prev, - { - id: `projects/${sandboxData.id}/${name}`, - name, - type: "folder", - children: [], - }, - ]) - } -} - export function debounce void>( func: T, wait: number