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.
|
* 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.
|
* 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 {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("");
|
const [text, setText] = useState("");
|
||||||
/**
|
/**
|
||||||
* Store a reference to the text area object
|
* 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">
|
<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
|
<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>
|
className="font-mono text-black bg-gray-300 p-1 rounded-md">{path}</span></h2>
|
||||||
<textarea
|
{loading && <ContentLoading/>}
|
||||||
onKeyDown={handleKeyPress}
|
{loading ||
|
||||||
tabIndex={-1}
|
<textarea
|
||||||
ref={textareaRef}
|
onKeyDown={handleKeyPress}
|
||||||
onInput={updateText}
|
tabIndex={-1}
|
||||||
value={text}
|
ref={textareaRef}
|
||||||
className="border-1 border-gray-300 rounded-md w-full h-9/10 p-1 resize-none text-sm font-mono">
|
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>
|
</textarea>
|
||||||
|
}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<button
|
<button
|
||||||
title="Exit without saving"
|
title="Exit without saving"
|
||||||
|
|||||||
@ -30,6 +30,7 @@ export default function Dashboard() {
|
|||||||
const [editing, setEditing] = useState("");
|
const [editing, setEditing] = useState("");
|
||||||
const [childrenLoading, setChildrenLoading] = useState(false);
|
const [childrenLoading, setChildrenLoading] = useState(false);
|
||||||
const [downloadLoading, setDownloadLoading] = useState(false);
|
const [downloadLoading, setDownloadLoading] = useState(false);
|
||||||
|
const [contentLoading, setContentLoading] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
||||||
@ -232,10 +233,9 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
// Send request to server to update the file. This will return nothing
|
// Send request to server to update the file. This will return nothing
|
||||||
// so no need for any promise handling.
|
// so no need for any promise handling.
|
||||||
updateContent(editing, newContent);
|
updateContent(editing, newContent).finally(() => {
|
||||||
|
setEditing("");
|
||||||
// Set editing back to nothing to hide the modal
|
});
|
||||||
setEditing("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -259,6 +259,7 @@ export default function Dashboard() {
|
|||||||
return await resp.json();
|
return await resp.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setContentLoading(true);
|
||||||
// Prevent running when nothing is being edited. Also prevents a call on mount.
|
// Prevent running when nothing is being edited. Also prevents a call on mount.
|
||||||
if (editing) {
|
if (editing) {
|
||||||
// Fetch the data and handle errors accordingly
|
// Fetch the data and handle errors accordingly
|
||||||
@ -270,6 +271,8 @@ export default function Dashboard() {
|
|||||||
setEditing("");
|
setEditing("");
|
||||||
setError(data.error);
|
setError(data.error);
|
||||||
}
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
setContentLoading(false)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +290,8 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
{error && <Error error={error} clear={clearError}/>}
|
{error && <Error error={error} clear={clearError}/>}
|
||||||
{(editing !== "" && !error) &&
|
{(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}
|
<PathDisplay path={path} updatePath={updatePath} backHome={backHome} backArrow={backArrow}
|
||||||
enabled={path.length > defaultPath.length}/>
|
enabled={path.length > defaultPath.length}/>
|
||||||
|
|||||||
Reference in New Issue
Block a user