Update.
This commit is contained in:
parent
c6fb77c89d
commit
9e9907bc00
116
retoors/static/js/components/upload.js
Normal file
116
retoors/static/js/components/upload.js
Normal file
@ -0,0 +1,116 @@
|
||||
export function showUploadModal() {
|
||||
document.getElementById('upload-modal').style.display = 'block';
|
||||
// Clear previous selections and progress
|
||||
document.getElementById('selected-files-preview').innerHTML = '';
|
||||
document.getElementById('upload-progress-container').innerHTML = '';
|
||||
document.getElementById('file-input-multiple').value = ''; // Clear selected files
|
||||
document.getElementById('start-upload-btn').disabled = true;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const fileInput = document.getElementById('file-input-multiple');
|
||||
const selectedFilesPreview = document.getElementById('selected-files-preview');
|
||||
const startUploadBtn = document.getElementById('start-upload-btn');
|
||||
const uploadProgressContainer = document.getElementById('upload-progress-container');
|
||||
|
||||
let filesToUpload = [];
|
||||
|
||||
fileInput.addEventListener('change', (event) => {
|
||||
filesToUpload = Array.from(event.target.files);
|
||||
selectedFilesPreview.innerHTML = ''; // Clear previous previews
|
||||
uploadProgressContainer.innerHTML = ''; // Clear previous progress bars
|
||||
|
||||
if (filesToUpload.length > 0) {
|
||||
startUploadBtn.disabled = false;
|
||||
filesToUpload.forEach(file => {
|
||||
const fileEntry = document.createElement('div');
|
||||
fileEntry.className = 'file-entry';
|
||||
fileEntry.innerHTML = `
|
||||
<span class="file-name">${file.name}</span>
|
||||
<span class="file-size">(${(file.size / 1024 / 1024).toFixed(2)} MB)</span>
|
||||
<div class="thumbnail-preview"></div>
|
||||
`;
|
||||
selectedFilesPreview.appendChild(fileEntry);
|
||||
|
||||
// Display thumbnail for image files
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const img = document.createElement('img');
|
||||
img.src = e.target.result;
|
||||
fileEntry.querySelector('.thumbnail-preview').appendChild(img);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
startUploadBtn.disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
startUploadBtn.addEventListener('click', () => {
|
||||
if (filesToUpload.length > 0) {
|
||||
uploadFiles(filesToUpload);
|
||||
}
|
||||
});
|
||||
|
||||
async function uploadFiles(files) {
|
||||
startUploadBtn.disabled = true; // Disable button during upload
|
||||
uploadProgressContainer.innerHTML = ''; // Clear previous progress
|
||||
|
||||
const currentPath = new URLSearchParams(window.location.search).get('path') || '';
|
||||
|
||||
for (const file of files) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const progressBarContainer = document.createElement('div');
|
||||
progressBarContainer.className = 'progress-bar-container';
|
||||
progressBarContainer.innerHTML = `
|
||||
<div class="file-name">${file.name}</div>
|
||||
<div class="progress-bar-wrapper">
|
||||
<div class="progress-bar" id="progress-${file.name.replace(/\./g, '-')}" style="width: 0%;"></div>
|
||||
</div>
|
||||
<div class="progress-text" id="progress-text-${file.name.replace(/\./g, '-')}" >0%</div>
|
||||
`;
|
||||
uploadProgressContainer.appendChild(progressBarContainer);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', `/files/upload?current_path=${encodeURIComponent(currentPath)}`, true);
|
||||
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percent = (event.loaded / event.total) * 100;
|
||||
document.getElementById(`progress-${file.name.replace(/\./g, '-')}`).style.width = `${percent}%`;
|
||||
document.getElementById(`progress-text-${file.name.replace(/\./g, '-')}`).textContent = `${Math.round(percent)}%`;
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status === 200) {
|
||||
console.log(`File ${file.name} uploaded successfully.`);
|
||||
// Update progress to 100% on completion
|
||||
document.getElementById(`progress-${file.name.replace(/\./g, '-')}`).style.width = `100%`;
|
||||
document.getElementById(`progress-text-${file.name.replace(/\./g, '-')}`).textContent = `100% (Done)`;
|
||||
} else {
|
||||
console.error(`Error uploading ${file.name}: ${xhr.statusText}`);
|
||||
document.getElementById(`progress-text-${file.name.replace(/\./g, '-')}`).textContent = `Failed (${xhr.status})`;
|
||||
document.getElementById(`progress-${file.name.replace(/\./g, '-')}`).style.backgroundColor = `red`;
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
console.error(`Network error uploading ${file.name}.`);
|
||||
document.getElementById(`progress-text-${file.name.replace(/\./g, '-')}`).textContent = `Network Error`;
|
||||
document.getElementById(`progress-${file.name.replace(/\./g, '-')}`).style.backgroundColor = `red`;
|
||||
});
|
||||
|
||||
xhr.send(formData);
|
||||
}
|
||||
// After all files are sent, refresh the page to show new files
|
||||
// A small delay to allow server to process and update file list
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
50
retoors/views/upload.py
Normal file
50
retoors/views/upload.py
Normal file
@ -0,0 +1,50 @@
|
||||
from aiohttp import web
|
||||
import aiohttp_jinja2
|
||||
from aiohttp.web_response import json_response
|
||||
|
||||
from ..helpers.auth import login_required
|
||||
|
||||
class UploadView(web.View):
|
||||
@login_required
|
||||
async def post(self):
|
||||
user_email = self.request["user"]["email"]
|
||||
file_service = self.request.app["file_service"]
|
||||
# Get current path from query parameter or form data
|
||||
current_path = self.request.query.get("current_path", "")
|
||||
|
||||
try:
|
||||
reader = await self.request.multipart()
|
||||
files_uploaded = []
|
||||
errors = []
|
||||
|
||||
while True:
|
||||
field = await reader.next()
|
||||
if field is None:
|
||||
break
|
||||
|
||||
# Check if the field is a file input
|
||||
if field.name == "file": # Assuming the input field name is 'file'
|
||||
filename = field.filename
|
||||
if not filename:
|
||||
errors.append("Filename is required for one of the files.")
|
||||
continue
|
||||
|
||||
content = await field.read()
|
||||
# Construct the full file path relative to the user's base directory
|
||||
full_file_path_for_service = f"{current_path}/{filename}" if current_path else filename
|
||||
|
||||
success = await file_service.upload_file(user_email, full_file_path_for_service, content)
|
||||
if success:
|
||||
files_uploaded.append(filename)
|
||||
else:
|
||||
errors.append(f"Failed to upload file '{filename}'")
|
||||
|
||||
if errors:
|
||||
return json_response({"status": "error", "message": "Some files failed to upload", "details": errors}, status=500)
|
||||
elif files_uploaded:
|
||||
return json_response({"status": "success", "message": f"Successfully uploaded {len(files_uploaded)} files", "files": files_uploaded})
|
||||
else:
|
||||
return json_response({"status": "error", "message": "No files were uploaded"}, status=400)
|
||||
|
||||
except Exception as e:
|
||||
return json_response({"status": "error", "message": f"Upload error: {str(e)}"}, status=500)
|
||||
Loading…
Reference in New Issue
Block a user