fix: reload the entire file list after adding or deleting files
This commit is contained in:
parent
062e8d9226
commit
07d3802baa
@ -125,6 +125,19 @@ export class FileManager {
|
|||||||
return this.files
|
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
|
// Initialize the FileManager
|
||||||
async initialize() {
|
async initialize() {
|
||||||
// Download files from remote file storage
|
// Download files from remote file storage
|
||||||
@ -146,15 +159,7 @@ export class FileManager {
|
|||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
|
|
||||||
// Reload file list from the container to include template files
|
await this.loadLocalFiles()
|
||||||
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)
|
|
||||||
|
|
||||||
// Make the logged in user the owner of all project files
|
// Make the logged in user the owner of all project files
|
||||||
this.fixPermissions()
|
this.fixPermissions()
|
||||||
@ -221,77 +226,13 @@ export class FileManager {
|
|||||||
|
|
||||||
// Handle file/directory creation event
|
// Handle file/directory creation event
|
||||||
if (event.type === "create") {
|
if (event.type === "create") {
|
||||||
const folder = findFolderById(
|
await this.loadLocalFiles()
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Create ${sandboxFilePath}`)
|
console.log(`Create ${sandboxFilePath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle file/directory removal or rename event
|
// Handle file/directory removal or rename event
|
||||||
else if (event.type === "remove" || event.type == "rename") {
|
else if (event.type === "remove" || event.type == "rename") {
|
||||||
const folder = findFolderById(
|
await this.loadLocalFiles()
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log(`Removed: ${sandboxFilePath}`)
|
console.log(`Removed: ${sandboxFilePath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,17 +399,6 @@ export class FileManager {
|
|||||||
await this.sandbox.files.write(path.posix.join(this.dirName, id), "")
|
await this.sandbox.files.write(path.posix.join(this.dirName, id), "")
|
||||||
await this.fixPermissions()
|
await this.fixPermissions()
|
||||||
|
|
||||||
this.files.push({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
type: "file",
|
|
||||||
})
|
|
||||||
|
|
||||||
this.fileData.push({
|
|
||||||
id,
|
|
||||||
data: "",
|
|
||||||
})
|
|
||||||
|
|
||||||
await RemoteFileStorage.createFile(this.getRemoteFileId(id))
|
await RemoteFileStorage.createFile(this.getRemoteFileId(id))
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -568,7 +498,6 @@ export class FileManager {
|
|||||||
if (!file) return this.files
|
if (!file) return this.files
|
||||||
|
|
||||||
await this.sandbox.files.remove(path.posix.join(this.dirName, fileId))
|
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))
|
await RemoteFileStorage.deleteFile(this.getRemoteFileId(fileId))
|
||||||
return this.updateFileStructure()
|
return this.updateFileStructure()
|
||||||
@ -583,7 +512,6 @@ export class FileManager {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
files.map(async (file) => {
|
files.map(async (file) => {
|
||||||
await this.sandbox.files.remove(path.posix.join(this.dirName, 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))
|
await RemoteFileStorage.deleteFile(this.getRemoteFileId(file))
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,6 @@ import { useSocket } from "@/context/SocketContext"
|
|||||||
import { parseTSConfigToMonacoOptions } from "@/lib/tsconfig"
|
import { parseTSConfigToMonacoOptions } from "@/lib/tsconfig"
|
||||||
import { Sandbox, TFile, TFolder, TTab, User } from "@/lib/types"
|
import { Sandbox, TFile, TFolder, TTab, User } from "@/lib/types"
|
||||||
import {
|
import {
|
||||||
addNew,
|
|
||||||
cn,
|
cn,
|
||||||
debounce,
|
debounce,
|
||||||
deepMerge,
|
deepMerge,
|
||||||
@ -856,13 +855,7 @@ export default function CodeEditor({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteFile = (file: TFile) => {
|
const handleDeleteFile = (file: TFile) => {
|
||||||
socket?.emit(
|
socket?.emit("deleteFile", { fileId: file.id })
|
||||||
"deleteFile",
|
|
||||||
{ fileId: file.id },
|
|
||||||
(response: (TFolder | TFile)[]) => {
|
|
||||||
setFiles(response)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
closeTab(file.id)
|
closeTab(file.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,7 +871,6 @@ export default function CodeEditor({
|
|||||||
"deleteFolder",
|
"deleteFolder",
|
||||||
{ folderId: folder.id },
|
{ folderId: folder.id },
|
||||||
(response: (TFolder | TFile)[]) => {
|
(response: (TFolder | TFile)[]) => {
|
||||||
setFiles(response)
|
|
||||||
setDeletingFolderId("")
|
setDeletingFolderId("")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -1047,7 +1039,6 @@ export default function CodeEditor({
|
|||||||
handleDeleteFolder={handleDeleteFolder}
|
handleDeleteFolder={handleDeleteFolder}
|
||||||
socket={socket!}
|
socket={socket!}
|
||||||
setFiles={setFiles}
|
setFiles={setFiles}
|
||||||
addNew={(name, type) => addNew(name, type, setFiles, sandboxData)}
|
|
||||||
deletingFolderId={deletingFolderId}
|
deletingFolderId={deletingFolderId}
|
||||||
toggleAIChat={toggleAIChat}
|
toggleAIChat={toggleAIChat}
|
||||||
isAIChatOpen={isAIChatOpen}
|
isAIChatOpen={isAIChatOpen}
|
||||||
|
@ -25,7 +25,6 @@ export default function Sidebar({
|
|||||||
handleDeleteFolder,
|
handleDeleteFolder,
|
||||||
socket,
|
socket,
|
||||||
setFiles,
|
setFiles,
|
||||||
addNew,
|
|
||||||
deletingFolderId,
|
deletingFolderId,
|
||||||
toggleAIChat,
|
toggleAIChat,
|
||||||
isAIChatOpen,
|
isAIChatOpen,
|
||||||
@ -43,7 +42,6 @@ export default function Sidebar({
|
|||||||
handleDeleteFolder: (folder: TFolder) => void
|
handleDeleteFolder: (folder: TFolder) => void
|
||||||
socket: Socket
|
socket: Socket
|
||||||
setFiles: (files: (TFile | TFolder)[]) => void
|
setFiles: (files: (TFile | TFolder)[]) => void
|
||||||
addNew: (name: string, type: "file" | "folder") => void
|
|
||||||
deletingFolderId: string
|
deletingFolderId: string
|
||||||
toggleAIChat: () => void
|
toggleAIChat: () => void
|
||||||
isAIChatOpen: boolean
|
isAIChatOpen: boolean
|
||||||
@ -176,7 +174,6 @@ export default function Sidebar({
|
|||||||
stopEditing={() => {
|
stopEditing={() => {
|
||||||
setCreatingNew(null)
|
setCreatingNew(null)
|
||||||
}}
|
}}
|
||||||
addNew={addNew}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
@ -9,12 +9,10 @@ export default function New({
|
|||||||
socket,
|
socket,
|
||||||
type,
|
type,
|
||||||
stopEditing,
|
stopEditing,
|
||||||
addNew,
|
|
||||||
}: {
|
}: {
|
||||||
socket: Socket
|
socket: Socket
|
||||||
type: "file" | "folder"
|
type: "file" | "folder"
|
||||||
stopEditing: () => void
|
stopEditing: () => void
|
||||||
addNew: (name: string, type: "file" | "folder") => void
|
|
||||||
}) {
|
}) {
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
@ -25,19 +23,9 @@ export default function New({
|
|||||||
const valid = validateName(name, "", type)
|
const valid = validateName(name, "", type)
|
||||||
if (valid.status) {
|
if (valid.status) {
|
||||||
if (type === "file") {
|
if (type === "file") {
|
||||||
socket.emit(
|
socket.emit("createFile", { name })
|
||||||
"createFile",
|
|
||||||
{ name },
|
|
||||||
({ success }: { success: boolean }) => {
|
|
||||||
if (success) {
|
|
||||||
addNew(name, type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
socket.emit("createFolder", { name }, () => {
|
socket.emit("createFolder", { name })
|
||||||
addNew(name, type)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { type ClassValue, clsx } from "clsx"
|
|||||||
// import { toast } from "sonner"
|
// import { toast } from "sonner"
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge"
|
||||||
import fileExtToLang from "./file-extension-to-language.json"
|
import fileExtToLang from "./file-extension-to-language.json"
|
||||||
import { Sandbox, TFile, TFolder } from "./types"
|
import { TFile, TFolder } from "./types"
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs))
|
||||||
@ -38,31 +38,6 @@ export function validateName(
|
|||||||
return { status: true, message: "" }
|
return { status: true, message: "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addNew(
|
|
||||||
name: string,
|
|
||||||
type: "file" | "folder",
|
|
||||||
setFiles: React.Dispatch<React.SetStateAction<(TFolder | TFile)[]>>,
|
|
||||||
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<T extends (...args: any[]) => void>(
|
export function debounce<T extends (...args: any[]) => void>(
|
||||||
func: T,
|
func: T,
|
||||||
wait: number
|
wait: number
|
||||||
|
Loading…
x
Reference in New Issue
Block a user