fix: allow js/css/txt extensions and limit upload concurrency to 6

This commit is contained in:
Tianyang 2026-08-01 19:38:09 +08:00
parent c6cc9b7146
commit 7386b215e2
2 changed files with 54 additions and 45 deletions

View File

@ -11,7 +11,12 @@ logger = logging.getLogger(__name__)
def _natural_sort_key(name: str) -> list:
return [int(part) if part.isdigit() else part for part in re.split(r"(\d+)", name)]
ALLOWED_UPLOAD_EXTENSIONS = {".md", ".html", ".htm", ".png", ".jpg", ".jpeg", ".gif", ".webp"}
ALLOWED_UPLOAD_EXTENSIONS = {
".md", ".html", ".htm",
".js", ".ts", ".css",
".json", ".yaml", ".yml", ".toml", ".xml", ".csv", ".txt",
".png", ".jpg", ".jpeg", ".gif", ".webp",
}
MAX_UPLOAD_SIZE_BYTES = 10 * 1024 * 1024

View File

@ -7,6 +7,37 @@ interface UploadButtonProps {
onUploaded: (result: UploadDocumentResponse) => void;
}
const CONCURRENCY = 6;
async function uploadQueue(
entries: FileWithRelativePath[],
path: string,
onDone: (result: UploadDocumentResponse) => void,
onError: (msg: string) => void,
) {
let i = 0;
async function next() {
if (i >= entries.length) return;
const entry = entries[i++];
const name = entry.relativePath ?? entry.file.name;
try {
const result = await (entry.relativePath
? uploadDocument(entry.file, path, entry.relativePath)
: uploadDocument(entry.file, path));
onDone(result);
} catch (err) {
onError(`${name}${err instanceof Error ? err.message : '上传失败'}`);
}
await next();
}
await Promise.all(Array.from({ length: Math.min(CONCURRENCY, entries.length) }, next));
}
interface UploadButtonProps {
path: string;
onUploaded: (result: UploadDocumentResponse) => void;
}
export default function UploadButton({ path, onUploaded }: UploadButtonProps) {
const [isOpen, setIsOpen] = useState(false);
const [isDragOver, setIsDragOver] = useState(false);
@ -16,52 +47,29 @@ export default function UploadButton({ path, onUploaded }: UploadButtonProps) {
function setFolderInputRef(node: HTMLInputElement | null) {
folderInputRef.current = node;
if (node) {
node.setAttribute('webkitdirectory', '');
}
if (node) node.setAttribute('webkitdirectory', '');
}
function openModal() {
setIsOpen(true);
}
function openModal() { setIsOpen(true); }
function closeModal() { setIsOpen(false); setIsDragOver(false); setUploadError(null); }
function closeModal() {
setIsOpen(false);
setIsDragOver(false);
function runQueue(entries: FileWithRelativePath[]) {
setUploadError(null);
}
function uploadOne(entry: FileWithRelativePath) {
setUploadError(null);
const promise = entry.relativePath
? uploadDocument(entry.file, path, entry.relativePath)
: uploadDocument(entry.file, path);
promise
.then((result) => {
onUploaded(result);
})
.catch((err) => {
setUploadError(err instanceof Error ? err.message : '上传失败');
});
}
function uploadFiles(files: FileList | File[]) {
Array.from(files).forEach((file) => uploadOne({ file }));
uploadQueue(entries, path, onUploaded, setUploadError);
}
function handleFileInputChange(event: React.ChangeEvent<HTMLInputElement>) {
if (event.target.files) {
uploadFiles(event.target.files);
}
if (event.target.files)
runQueue(Array.from(event.target.files).map((file) => ({ file })));
event.target.value = '';
}
function handleFolderInputChange(event: React.ChangeEvent<HTMLInputElement>) {
if (event.target.files) {
Array.from(event.target.files).forEach((file) =>
uploadOne({ file, relativePath: file.webkitRelativePath || file.name }),
);
}
if (event.target.files)
runQueue(Array.from(event.target.files).map((file) => ({
file,
relativePath: file.webkitRelativePath || file.name,
})));
event.target.value = '';
}
@ -69,14 +77,12 @@ export default function UploadButton({ path, onUploaded }: UploadButtonProps) {
event.preventDefault();
setIsDragOver(false);
const items = event.dataTransfer.items;
if (items && items.length > 0 && typeof items[0]?.webkitGetAsEntry === 'function') {
const entries = await readFileEntries(items);
entries.forEach(uploadOne);
if (items?.length > 0 && typeof items[0]?.webkitGetAsEntry === 'function') {
runQueue(await readFileEntries(items));
return;
}
if (event.dataTransfer.files) {
uploadFiles(event.dataTransfer.files);
}
if (event.dataTransfer.files)
runQueue(Array.from(event.dataTransfer.files).map((file) => ({ file })));
}
function handleDragOver(event: React.DragEvent<HTMLDivElement>) {
@ -84,9 +90,7 @@ export default function UploadButton({ path, onUploaded }: UploadButtonProps) {
setIsDragOver(true);
}
function handleDragLeave() {
setIsDragOver(false);
}
function handleDragLeave() { setIsDragOver(false); }
return (
<>