diff --git a/backend/src/server.ts b/backend/src/server.ts index 1293dbb..b9bb808 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -3,7 +3,7 @@ import { Healthcheck } from "./healthcheck"; import { printEndpoints, validateHash } from "./utils"; import { LogRequestMiddleware } from "./log"; import * as fs from "node:fs"; -import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs"; +import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, existsSync } from "node:fs"; import { entry } from "./entry"; import cors from "cors"; import archiver from "archiver"; @@ -362,6 +362,42 @@ v1.post("/remove", (req: Request, res: Response): void => { res.status(201).json({ code: 201, message: `Deleted ${files.length} files.` }); }); +v1.post("/move", (req: Request, res: Response): void => { + // Get the array of paths and the root + const { oldPath, newPath } = req.body; + + try { + // Get path of new path + const newDirectory = path.dirname(newPath); + + // Ensure the directory exists + if (!existsSync(newDirectory)) { + mkdirSync(newDirectory, { recursive: true }); + console.log(`Created directory: ${newDirectory}`); + } + + // Move the file + renameSync(oldPath, newPath); + console.log(`File moved from ${oldPath} to ${newPath}`); + + res.status(200).json({ code: 200 }); + } catch (err: any) { + console.error("Error moving file:", err); + // You might want to send a more specific error message based on 'err.code' + if (err.code === 'EXDEV') { + // This specific error means moving across different file systems. + // Synchronous fallback would be more complex (read/write stream synchronously), + // which is why async is preferred here. For synchronous, you'd generally + // just fail or implement a blocking copy/delete. + res.status(500).json({ code: 500, error: "Error: Cannot move across different file systems synchronously. Try copying and deleting." }); + } else if (err.code === 'ENOENT') { + res.status(404).json({ code: 404, error: "Error: Source file or destination path not found." }); + } else { + res.status(500).json({ code: 500, error: `Failed to move file: ${err.message}` }); + } + } +}); + /** * Apply the routes to the server */ diff --git a/frontend/src/components/MoveDirectory.jsx b/frontend/src/components/MoveDirectory.jsx new file mode 100644 index 0000000..f27592e --- /dev/null +++ b/frontend/src/components/MoveDirectory.jsx @@ -0,0 +1,57 @@ +import { useState, useEffect } from "react"; + +/** + * Move a file or directory. + * @constructor + */ +export default function MoveDirectory({ close, move, path }) { + const [dirName, setDirName] = useState(""); + + useEffect(() => { + setDirName("/" + path.join("/")); + }, [path]); + + const moveDirectory = () => move(dirName); + const updateDirName = (e) => setDirName(e.target.value); + + const closeWithoutSaving = () => { + setDirName(""); + close(); + } + + return <> +
+ {/* Blured backdrop */} +
+ +
+

+ Move/Rename Directory +

+

+ Move a file or directory from the current directory to a new location. This can be used to rename files + if the base directory remains the same. +

+ + +
+ + +
+
+
+ +} diff --git a/frontend/src/components/PathDisplay.jsx b/frontend/src/components/PathDisplay.jsx index aeda4c7..ba6242c 100644 --- a/frontend/src/components/PathDisplay.jsx +++ b/frontend/src/components/PathDisplay.jsx @@ -6,7 +6,7 @@ * @returns {JSX.Element} * @constructor */ -function HomeButton({onClick, enabled}) { +function HomeButton({ onClick, enabled }) { return <> } -function BackButton({onClick, enabled}) { +function BackButton({ onClick, enabled }) { return <> } -function CreateButton({onClick}) { +function CreateButton({ onClick }) { return <> } -function DeleteButton({onClick, enabled}) { +function DeleteButton({ onClick, enabled }) { return <> } +function MoveButton({ onClick, enabled }) { + return <> + + + + +} + /** * * @param name {string} @@ -74,7 +90,7 @@ function DeleteButton({onClick, enabled}) { * @returns {JSX.Element} * @constructor */ -function PathElement({name, index, onClick}) { +function PathElement({ name, index, onClick }) { const handleClick = () => onClick(index); return <>