FIX: Spinner for the editor content.
This commit is contained in:
parent
9ec4976b31
commit
cf886b8983
@ -31,7 +31,7 @@ try {
|
||||
/**
|
||||
* Invalid file extensions for the file editor.
|
||||
*/
|
||||
const INVALID_EXTS: string[] = ["exe", "dll", "obj", "lib", "bin", "dat", "pdf", "jpg", "jpeg", "png", "gif", "webm", "webp", "bmp", "mp3", "wav", "mp4", "avi", "zip", "rar", "7z", "iso", "dmg", "class", "pyc", "o", "a", "woff", "woff2", "ttf", "otf", "db", "sqlite", "mdb", "accdb", "psd", "ai", "indd", "blend", "fbx", "unitypackage", "pak", "sav", "msi", ".doc", ".docx", ".dot", ".dotx", ".docm", ".dotm", ".rtf", ".txt", ".xls", ".xlsx", ".xlsm", ".xltx", ".xltm", ".csv", ".ppt", ".pptx", ".pptm", ".potx", ".potm", ".ppsx", ".ppsm", ".mdb", ".accdb", ".accde", ".accdt", ".pst", ".ost", ".msg", ".one", ".onetoc2", ".pub", ".vsd", ".vsdx", ".vssx", ".vstx", ".odc", ".oft", ".pki"];
|
||||
const INVALID_EXTS: string[] = ["exe", "dll", "obj", "lib", "bin", "dat", "pdf", "jpg", "jpeg", "png", "gif", "webm", "webp", "bmp", "mp3", "wav", "mp4", "avi", "zip", "rar", "7z", "iso", "dmg", "class", "pyc", "o", "a", "woff", "woff2", "ttf", "otf", "db", "sqlite", "mdb", "accdb", "psd", "ai", "indd", "blend", "fbx", "unitypackage", "pak", "sav", "msi", "doc", "docx", "dot", "dotx", "docm", "dotm", "rtf", "txt", "xls", "xlsx", "xlsm", "xltx", "xltm", "csv", "ppt", "pptx", "pptm", "potx", "potm", "ppsx", "ppsm", "mdb", "accdb", "accde", "accdt", "pst", "ost", "msg", "one", "onetoc2", "pub", "vsd", "vsdx", "vssx", "vstx", "odc", "oft", "pki", "odg"];
|
||||
|
||||
/**
|
||||
* Configure cors, this should work for both production and development.
|
||||
|
||||
20
frontend/src/components/ContentLoading.jsx
Normal file
20
frontend/src/components/ContentLoading.jsx
Normal file
@ -0,0 +1,20 @@
|
||||
import "../index.css"
|
||||
|
||||
/**
|
||||
* Simple loading spinner for the text editor.
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
export default function ContentLoading() {
|
||||
return (
|
||||
<div className="h-9/10 w-full flex flex-col items-center justify-center">
|
||||
<div className="flex">
|
||||
<div
|
||||
className="animate-spin rounded-full border-blue-500 border-3 border-t-transparent size-6 mr-2 ">
|
||||
</div>
|
||||
<p className="text-lg text-black opacity-90">Content loading...</p>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 my-2">For large files, this may take a while.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import ContentLoading from "./ContentLoading.jsx";
|
||||
|
||||
export default function Editor({content, path, exit, saveExit}) {
|
||||
export default function Editor({content, path, exit, saveExit, loading}) {
|
||||
const [text, setText] = useState("");
|
||||
/**
|
||||
* Store a reference to the text area object
|
||||
@ -54,14 +55,17 @@ export default function Editor({content, path, exit, saveExit}) {
|
||||
<div className="relative z-10 bg-white p-8 rounded-lg shadow-lg w-3/4 h-5/6 border-1 border-gray-400">
|
||||
<h2 className="text-lg font-semibold mb-4 text-blue-400">Editing File: <span
|
||||
className="font-mono text-black bg-gray-300 p-1 rounded-md">{path}</span></h2>
|
||||
<textarea
|
||||
onKeyDown={handleKeyPress}
|
||||
tabIndex={-1}
|
||||
ref={textareaRef}
|
||||
onInput={updateText}
|
||||
value={text}
|
||||
className="border-1 border-gray-300 rounded-md w-full h-9/10 p-1 resize-none text-sm font-mono">
|
||||
{loading && <ContentLoading/>}
|
||||
{loading ||
|
||||
<textarea
|
||||
onKeyDown={handleKeyPress}
|
||||
tabIndex={-1}
|
||||
ref={textareaRef}
|
||||
onInput={updateText}
|
||||
value={text}
|
||||
className="border-1 border-gray-300 rounded-md w-full h-9/10 p-1 resize-none text-sm font-mono">
|
||||
</textarea>
|
||||
}
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
title="Exit without saving"
|
||||
|
||||
@ -30,6 +30,7 @@ export default function Dashboard() {
|
||||
const [editing, setEditing] = useState("");
|
||||
const [childrenLoading, setChildrenLoading] = useState(false);
|
||||
const [downloadLoading, setDownloadLoading] = useState(false);
|
||||
const [contentLoading, setContentLoading] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
@ -232,10 +233,9 @@ export default function Dashboard() {
|
||||
|
||||
// Send request to server to update the file. This will return nothing
|
||||
// so no need for any promise handling.
|
||||
updateContent(editing, newContent);
|
||||
|
||||
// Set editing back to nothing to hide the modal
|
||||
setEditing("");
|
||||
updateContent(editing, newContent).finally(() => {
|
||||
setEditing("");
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -259,6 +259,7 @@ export default function Dashboard() {
|
||||
return await resp.json();
|
||||
};
|
||||
|
||||
setContentLoading(true);
|
||||
// Prevent running when nothing is being edited. Also prevents a call on mount.
|
||||
if (editing) {
|
||||
// Fetch the data and handle errors accordingly
|
||||
@ -270,6 +271,8 @@ export default function Dashboard() {
|
||||
setEditing("");
|
||||
setError(data.error);
|
||||
}
|
||||
}).finally(() => {
|
||||
setContentLoading(false)
|
||||
});
|
||||
}
|
||||
|
||||
@ -287,7 +290,8 @@ export default function Dashboard() {
|
||||
|
||||
{error && <Error error={error} clear={clearError}/>}
|
||||
{(editing !== "" && !error) &&
|
||||
<Editor content={editingFileContent} path={editing} exit={exitFile} saveExit={exitAndSaveFile}/>}
|
||||
<Editor content={editingFileContent} path={editing} exit={exitFile} saveExit={exitAndSaveFile}
|
||||
loading={contentLoading}/>}
|
||||
|
||||
<PathDisplay path={path} updatePath={updatePath} backHome={backHome} backArrow={backArrow}
|
||||
enabled={path.length > defaultPath.length}/>
|
||||
|
||||
Reference in New Issue
Block a user