[FEATURE] Basic System with file manager (#4)
Co-authored-by: dunemask <dunemask@gmail.com> Co-authored-by: Dunemask <dunemask@gmail.com> Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/4
This commit is contained in:
parent
8fb5b34c77
commit
4f19cf19d9
62 changed files with 5910 additions and 1190 deletions
146
src/components/files/MineclusterFiles.jsx
Normal file
146
src/components/files/MineclusterFiles.jsx
Normal file
|
@ -0,0 +1,146 @@
|
|||
import { useState, useEffect, useMemo, useRef } from "react";
|
||||
import Box from "@mui/material/Box";
|
||||
import {
|
||||
FileBrowser,
|
||||
FileContextMenu,
|
||||
FileList,
|
||||
FileNavbar,
|
||||
FileToolbar,
|
||||
setChonkyDefaults,
|
||||
ChonkyActions,
|
||||
} from "chonky";
|
||||
import { ChonkyIconFA } from "chonky-icon-fontawesome";
|
||||
|
||||
import {
|
||||
getServerFiles,
|
||||
createServerFolder,
|
||||
deleteServerItem,
|
||||
getServerItem,
|
||||
} from "@mcl/queries";
|
||||
|
||||
import "@mcl/css/header.css";
|
||||
|
||||
export default function MineclusterFiles(props) {
|
||||
// Chonky configuration
|
||||
setChonkyDefaults({ iconComponent: ChonkyIconFA });
|
||||
const fileActions = useMemo(
|
||||
() => [
|
||||
ChonkyActions.CreateFolder,
|
||||
ChonkyActions.UploadFiles,
|
||||
ChonkyActions.DownloadFiles,
|
||||
ChonkyActions.CopyFiles,
|
||||
ChonkyActions.DeleteFiles,
|
||||
],
|
||||
[],
|
||||
);
|
||||
const { server: serverName } = props;
|
||||
const inputRef = useRef(null);
|
||||
const [dirStack, setDirStack] = useState(["."]);
|
||||
const [files, setFiles] = useState([]);
|
||||
|
||||
const updateFiles = () =>
|
||||
getServerFiles(serverName, dirStack.join("/")).then((f) =>
|
||||
setFiles(f ?? []),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateFiles();
|
||||
}, [dirStack]);
|
||||
|
||||
const getFolderChain = () => {
|
||||
if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }];
|
||||
return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true }));
|
||||
};
|
||||
|
||||
const openParentFolder = () => setDirStack(dirStack.slice(0, -1));
|
||||
|
||||
function openFolder(payload) {
|
||||
const { targetFile: file } = payload;
|
||||
if (!file || !file.isDir) return;
|
||||
setDirStack([...dirStack, file.name]);
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
const name = prompt("What is the name of the new folder?");
|
||||
const path = [...dirStack, name].join("/");
|
||||
createServerFolder(serverName, path).then(updateFiles);
|
||||
}
|
||||
|
||||
function deleteItems(files) {
|
||||
Promise.all(
|
||||
files.map((f) =>
|
||||
deleteServerItem(serverName, [...dirStack, f.name].join("/"), f.isDir),
|
||||
),
|
||||
)
|
||||
.catch((e) => console.error("Error deleting some files!", e))
|
||||
.then(updateFiles);
|
||||
}
|
||||
|
||||
function uploadFileSelection(e) {
|
||||
if (!e.target.files || e.target.files.length === 0) return;
|
||||
const { files } = e.target;
|
||||
Promise.all([...files].map((f) => uploadFile(f)))
|
||||
.catch((e) => console.log("Error uploading a file", e))
|
||||
.then(updateFiles);
|
||||
}
|
||||
|
||||
async function uploadFile(file) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("name", serverName);
|
||||
formData.append("path", [...dirStack, name].join("/"));
|
||||
await fetch("/api/files/upload", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
}
|
||||
|
||||
async function downloadFiles(files) {
|
||||
Promise.all(
|
||||
files.map((f) =>
|
||||
getServerItem(serverName, f.name, [...dirStack, f.name].join("/")),
|
||||
),
|
||||
)
|
||||
.then(() => console.log("Done"))
|
||||
.catch((e) => console.error("Error Downloading files!", e));
|
||||
}
|
||||
|
||||
function fileClick(chonkyEvent) {
|
||||
const { id: clickEvent, payload } = chonkyEvent;
|
||||
console.log(chonkyEvent);
|
||||
if (clickEvent === "open_parent_folder") return openParentFolder();
|
||||
if (clickEvent === "create_folder") return createFolder();
|
||||
if (clickEvent === "upload_files") return inputRef.current.click();
|
||||
if (clickEvent === "download_files")
|
||||
return downloadFiles(chonkyEvent.state.selectedFilesForAction);
|
||||
if (clickEvent === "delete_files")
|
||||
return deleteItems(chonkyEvent.state.selectedFilesForAction);
|
||||
if (clickEvent !== "open_files") return console.log(clickEvent);
|
||||
openFolder(payload);
|
||||
}
|
||||
return (
|
||||
<Box className="minecluster-files" sx={{ height: "calc(100vh - 6rem)" }}>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={inputRef}
|
||||
style={{ display: "none" }}
|
||||
onChange={uploadFileSelection}
|
||||
multiple
|
||||
/>
|
||||
|
||||
<FileBrowser
|
||||
files={files}
|
||||
folderChain={getFolderChain()}
|
||||
onFileAction={fileClick}
|
||||
fileActions={fileActions}
|
||||
darkMode={true}
|
||||
>
|
||||
<FileNavbar />
|
||||
<FileToolbar />
|
||||
<FileList />
|
||||
<FileContextMenu />
|
||||
</FileBrowser>
|
||||
</Box>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue