`;
-
+
// Add to toast container or create one
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
@@ -298,15 +298,15 @@ function showErrorMessage(message) {
toastContainer.style.zIndex = '1055';
document.body.appendChild(toastContainer);
}
-
+
toastContainer.appendChild(toast);
-
+
// Show toast
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
-
+
// Remove toast element after it's hidden
- toast.addEventListener('hidden.bs.toast', function() {
+ toast.addEventListener('hidden.bs.toast', function () {
toast.remove();
});
}
@@ -318,7 +318,7 @@ function showSuccessMessage(message) {
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomic', 'true');
-
+
toast.innerHTML = `
@@ -328,7 +328,7 @@ function showSuccessMessage(message) {
`;
-
+
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
@@ -337,13 +337,13 @@ function showSuccessMessage(message) {
toastContainer.style.zIndex = '1055';
document.body.appendChild(toastContainer);
}
-
+
toastContainer.appendChild(toast);
-
+
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
-
- toast.addEventListener('hidden.bs.toast', function() {
+
+ toast.addEventListener('hidden.bs.toast', function () {
toast.remove();
});
}
@@ -351,13 +351,13 @@ function showSuccessMessage(message) {
// Format bytes for display
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
-
+
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
-
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
-
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
@@ -380,7 +380,7 @@ function confirmAction(message, callback) {
}
// Global error handler
-window.addEventListener('error', function(e) {
+window.addEventListener('error', function (e) {
console.error('Global error:', e.error);
showErrorMessage('An unexpected error occurred.');
});
@@ -392,7 +392,7 @@ window.Dashboard = {
formatBytes,
formatNumber,
confirmAction
-};
+};
// Initialize event handlers
function initializeEventHandlers() {
@@ -403,13 +403,13 @@ function initializeEventHandlers() {
}
// Delete bucket buttons
- document.addEventListener('click', function(e) {
+ document.addEventListener('click', function (e) {
if (e.target.closest('.delete-bucket-btn')) {
const button = e.target.closest('.delete-bucket-btn');
const bucketName = button.getAttribute('data-bucket-name');
confirmDeleteBucket(bucketName);
}
-
+
// Quota management buttons
if (e.target.closest('.quota-btn')) {
const button = e.target.closest('.quota-btn');
@@ -429,7 +429,7 @@ function initializeEventHandlers() {
// Enable quota checkbox for create bucket form
const enableQuotaCheckbox = document.getElementById('enableQuota');
if (enableQuotaCheckbox) {
- enableQuotaCheckbox.addEventListener('change', function() {
+ enableQuotaCheckbox.addEventListener('change', function () {
const quotaSettings = document.getElementById('quotaSettings');
if (this.checked) {
quotaSettings.style.display = 'block';
@@ -442,7 +442,7 @@ function initializeEventHandlers() {
// Enable quota checkbox for quota modal
const quotaEnabledCheckbox = document.getElementById('quotaEnabled');
if (quotaEnabledCheckbox) {
- quotaEnabledCheckbox.addEventListener('change', function() {
+ quotaEnabledCheckbox.addEventListener('change', function () {
const quotaSizeSettings = document.getElementById('quotaSizeSettings');
if (this.checked) {
quotaSizeSettings.style.display = 'block';
@@ -467,7 +467,7 @@ function setupFormValidation() {
// Handle create bucket form submission
async function handleCreateBucket(event) {
event.preventDefault();
-
+
const form = event.target;
const formData = new FormData(form);
const bucketData = {
@@ -492,14 +492,14 @@ async function handleCreateBucket(event) {
if (response.ok) {
// Success
showAlert('success', `Bucket "${bucketData.name}" created successfully!`);
-
+
// Close modal
const modal = bootstrap.Modal.getInstance(document.getElementById('createBucketModal'));
modal.hide();
-
+
// Reset form
form.reset();
-
+
// Refresh the page after a short delay
setTimeout(() => {
location.reload();
@@ -519,7 +519,7 @@ function validateBucketName(event) {
const input = event.target;
const value = input.value;
const isValid = /^[a-z0-9.-]+$/.test(value) && value.length >= 3 && value.length <= 63;
-
+
if (value.length > 0 && !isValid) {
input.setCustomValidity('Bucket name must contain only lowercase letters, numbers, dots, and hyphens (3-63 characters)');
} else {
@@ -531,7 +531,7 @@ function validateBucketName(event) {
function confirmDeleteBucket(bucketName) {
bucketToDelete = bucketName;
document.getElementById('deleteBucketName').textContent = bucketName;
-
+
const modal = new bootstrap.Modal(document.getElementById('deleteBucketModal'));
modal.show();
}
@@ -552,11 +552,11 @@ async function deleteBucket() {
if (response.ok) {
// Success
showAlert('success', `Bucket "${bucketToDelete}" deleted successfully!`);
-
+
// Close modal
const modal = bootstrap.Modal.getInstance(document.getElementById('deleteBucketModal'));
modal.hide();
-
+
// Refresh the page after a short delay
setTimeout(() => {
location.reload();
@@ -588,7 +588,7 @@ function exportBucketList() {
const data = rows.map(row => {
const cells = row.querySelectorAll('td');
if (cells.length < 5) return null; // Skip empty state row
-
+
return {
name: cells[0].textContent.trim(),
created: cells[1].textContent.trim(),
@@ -639,7 +639,7 @@ function showAlert(type, message) {
min-width: 300px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
`;
-
+
alert.innerHTML = `
${message}
@@ -684,9 +684,9 @@ function exportVolumeServers() {
showErrorMessage('No volume servers data to export');
return;
}
-
+
let csv = 'Server ID,Address,Data Center,Rack,Volumes,Capacity,Usage\n';
-
+
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
@@ -703,7 +703,7 @@ function exportVolumeServers() {
csv += rowData.join(',') + '\n';
}
});
-
+
downloadCSV(csv, 'seaweedfs-volume-servers.csv');
}
@@ -714,7 +714,7 @@ function exportVolumes() {
showErrorMessage('No volumes data to export');
return;
}
-
+
// Get headers from the table (dynamically handles conditional columns)
const headerCells = table.querySelectorAll('thead th');
const headers = [];
@@ -724,9 +724,9 @@ function exportVolumes() {
headers.push(cell.textContent.trim());
}
});
-
+
let csv = headers.join(',') + '\n';
-
+
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
@@ -735,9 +735,9 @@ function exportVolumes() {
for (let i = 0; i < cells.length - 1; i++) {
rowData.push(`"${cells[i].textContent.trim().replace(/"/g, '""')}"`);
}
- csv += rowData.join(',') + '\n';
+ csv += rowData.join(',') + '\n';
});
-
+
downloadCSV(csv, 'seaweedfs-volumes.csv');
}
@@ -854,15 +854,15 @@ function exportUsers() {
showAlert('error', 'Users table not found');
return;
}
-
+
const rows = table.querySelectorAll('tbody tr');
if (rows.length === 0) {
showErrorMessage('No users to export');
return;
}
-
+
let csvContent = 'Username,Email,Access Key,Status,Created,Last Login\n';
-
+
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 6) {
@@ -872,11 +872,11 @@ function exportUsers() {
const status = cells[3].textContent.trim();
const created = cells[4].textContent.trim();
const lastLogin = cells[5].textContent.trim();
-
+
csvContent += `"${username}","${email}","${accessKey}","${status}","${created}","${lastLogin}"\n`;
}
});
-
+
downloadCSV(csvContent, 'seaweedfs-users.csv');
}
@@ -884,12 +884,12 @@ function exportUsers() {
function confirmDeleteCollection(button) {
const collectionName = button.getAttribute('data-collection-name');
document.getElementById('deleteCollectionName').textContent = collectionName;
-
+
const modal = new bootstrap.Modal(document.getElementById('deleteCollectionModal'));
modal.show();
-
+
// Set up confirm button
- document.getElementById('confirmDeleteCollection').onclick = function() {
+ document.getElementById('confirmDeleteCollection').onclick = function () {
deleteCollection(collectionName);
};
}
@@ -903,7 +903,7 @@ async function deleteCollection(collectionName) {
'Content-Type': 'application/json',
}
});
-
+
if (response.ok) {
showSuccessMessage(`Collection "${collectionName}" deleted successfully`);
// Hide modal
@@ -929,7 +929,7 @@ async function deleteCollection(collectionName) {
function downloadCSV(csvContent, filename) {
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
-
+
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
@@ -947,11 +947,11 @@ function downloadCSV(csvContent, filename) {
function toggleSelectAll() {
const selectAll = document.getElementById('selectAll');
const checkboxes = document.querySelectorAll('.file-checkbox');
-
+
checkboxes.forEach(checkbox => {
checkbox.checked = selectAll.checked;
});
-
+
updateDeleteSelectedButton();
}
@@ -959,7 +959,7 @@ function toggleSelectAll() {
function updateDeleteSelectedButton() {
const checkboxes = document.querySelectorAll('.file-checkbox:checked');
const deleteBtn = document.getElementById('deleteSelectedBtn');
-
+
if (deleteBtn) {
if (checkboxes.length > 0) {
deleteBtn.style.display = 'inline-block';
@@ -975,7 +975,7 @@ function updateSelectAllCheckbox() {
const selectAll = document.getElementById('selectAll');
const allCheckboxes = document.querySelectorAll('.file-checkbox');
const checkedCheckboxes = document.querySelectorAll('.file-checkbox:checked');
-
+
if (selectAll && allCheckboxes.length > 0) {
if (checkedCheckboxes.length === 0) {
selectAll.checked = false;
@@ -999,17 +999,17 @@ function getSelectedFilePaths() {
// Confirm delete selected files
function confirmDeleteSelected() {
const selectedPaths = getSelectedFilePaths();
-
+
if (selectedPaths.length === 0) {
showAlert('warning', 'No files selected');
return;
}
-
+
const fileNames = selectedPaths.map(path => path.split('/').pop()).join(', ');
- const message = selectedPaths.length === 1
+ const message = selectedPaths.length === 1
? `Are you sure you want to delete "${fileNames}"?`
: `Are you sure you want to delete ${selectedPaths.length} selected items?\n\n${fileNames.substring(0, 200)}${fileNames.length > 200 ? '...' : ''}`;
-
+
if (confirm(message)) {
deleteSelectedFiles(selectedPaths);
}
@@ -1021,13 +1021,13 @@ async function deleteSelectedFiles(filePaths) {
showAlert('warning', 'No files selected');
return;
}
-
+
// Disable the delete button during operation
const deleteBtn = document.getElementById('deleteSelectedBtn');
const originalText = deleteBtn.innerHTML;
deleteBtn.disabled = true;
deleteBtn.innerHTML = '
Deleting...';
-
+
try {
const response = await fetch('/api/files/delete-multiple', {
method: 'DELETE',
@@ -1039,7 +1039,7 @@ async function deleteSelectedFiles(filePaths) {
if (response.ok) {
const result = await response.json();
-
+
if (result.deleted > 0) {
if (result.failed === 0) {
showAlert('success', `Successfully deleted ${result.deleted} item(s)`);
@@ -1049,7 +1049,7 @@ async function deleteSelectedFiles(filePaths) {
console.warn('Deletion errors:', result.errors);
}
}
-
+
// Reload the page to update the file list
setTimeout(() => {
window.location.reload();
@@ -1091,31 +1091,31 @@ function uploadFile() {
async function submitCreateFolder() {
const folderName = document.getElementById('folderName').value.trim();
const currentPath = document.getElementById('currentPath').value;
-
+
if (!folderName) {
showErrorMessage('Please enter a folder name');
return;
}
-
+
// Validate folder name
if (folderName.includes('/') || folderName.includes('\\')) {
showErrorMessage('Folder names cannot contain / or \\ characters');
return;
}
-
+
// Additional validation for reserved names
const reservedNames = ['.', '..', 'CON', 'PRN', 'AUX', 'NUL'];
if (reservedNames.includes(folderName.toUpperCase())) {
showErrorMessage('This folder name is reserved and cannot be used');
return;
}
-
+
// Disable the button to prevent double submission
const submitButton = document.querySelector('#createFolderModal .btn-primary');
const originalText = submitButton.innerHTML;
submitButton.disabled = true;
submitButton.innerHTML = '
Creating...';
-
+
try {
const response = await fetch('/api/files/create-folder', {
method: 'POST',
@@ -1157,37 +1157,37 @@ async function submitCreateFolder() {
async function submitUploadFile() {
const fileInput = document.getElementById('fileInput');
const currentPath = document.getElementById('uploadPath').value;
-
+
if (!fileInput.files || fileInput.files.length === 0) {
showErrorMessage('Please select at least one file to upload');
return;
}
-
+
const files = Array.from(fileInput.files);
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
-
+
// Validate total file size (limit to 500MB for admin interface)
const maxSize = 500 * 1024 * 1024; // 500MB total
if (totalSize > maxSize) {
showErrorMessage('Total file size exceeds 500MB limit. Please select fewer or smaller files.');
return;
}
-
+
// Individual file size validation removed - no limit per file
-
+
const formData = new FormData();
files.forEach(file => {
formData.append('files', file);
});
formData.append('path', currentPath);
-
+
// Show progress bar and disable button
const progressContainer = document.getElementById('uploadProgress');
const progressBar = progressContainer.querySelector('.progress-bar');
const uploadStatus = document.getElementById('uploadStatus');
const submitButton = document.querySelector('#uploadFileModal .btn-primary');
const originalText = submitButton.innerHTML;
-
+
progressContainer.style.display = 'block';
progressBar.style.width = '0%';
progressBar.setAttribute('aria-valuenow', '0');
@@ -1195,12 +1195,12 @@ async function submitUploadFile() {
uploadStatus.textContent = `Uploading ${files.length} file(s)...`;
submitButton.disabled = true;
submitButton.innerHTML = '
Uploading...';
-
+
try {
const xhr = new XMLHttpRequest();
-
+
// Handle progress
- xhr.upload.addEventListener('progress', function(e) {
+ xhr.upload.addEventListener('progress', function (e) {
if (e.lengthComputable) {
const percentComplete = Math.round((e.loaded / e.total) * 100);
progressBar.style.width = percentComplete + '%';
@@ -1209,13 +1209,13 @@ async function submitUploadFile() {
uploadStatus.textContent = `Uploading ${files.length} file(s)... ${percentComplete}%`;
}
});
-
+
// Handle completion
- xhr.addEventListener('load', function() {
+ xhr.addEventListener('load', function () {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
-
+
if (response.uploaded > 0) {
if (response.failed === 0) {
showSuccessMessage(`Successfully uploaded ${response.uploaded} file(s)`);
@@ -1226,7 +1226,7 @@ async function submitUploadFile() {
console.warn('Upload errors:', response.errors);
}
}
-
+
// Hide modal and refresh page
const modal = bootstrap.Modal.getInstance(document.getElementById('uploadFileModal'));
modal.hide();
@@ -1256,23 +1256,23 @@ async function submitUploadFile() {
progressContainer.style.display = 'none';
}
});
-
+
// Handle errors
- xhr.addEventListener('error', function() {
+ xhr.addEventListener('error', function () {
showErrorMessage('Failed to upload files. Please check your connection and try again.');
progressContainer.style.display = 'none';
});
-
+
// Handle abort
- xhr.addEventListener('abort', function() {
+ xhr.addEventListener('abort', function () {
showErrorMessage('File upload was cancelled.');
progressContainer.style.display = 'none';
});
-
+
// Send request
xhr.open('POST', '/api/files/upload');
xhr.send(formData);
-
+
} catch (error) {
console.error('Upload error:', error);
showErrorMessage('Failed to upload files. Please try again.');
@@ -1331,16 +1331,16 @@ function downloadFile(filePath) {
async function viewFile(filePath) {
try {
const response = await fetch(`/api/files/view?path=${encodeURIComponent(filePath)}`);
-
+
if (!response.ok) {
const error = await response.json();
showAlert('error', `Failed to view file: ${error.error || 'Unknown error'}`);
return;
}
-
+
const data = await response.json();
showFileViewer(data);
-
+
} catch (error) {
console.error('View file error:', error);
showAlert('error', 'Failed to view file');
@@ -1351,16 +1351,16 @@ async function viewFile(filePath) {
async function showProperties(filePath) {
try {
const response = await fetch(`/api/files/properties?path=${encodeURIComponent(filePath)}`);
-
+
if (!response.ok) {
const error = await response.json();
showAlert('error', `Failed to get file properties: ${error.error || 'Unknown error'}`);
return;
}
-
+
const properties = await response.json();
showPropertiesModal(properties);
-
+
} catch (error) {
console.error('Properties error:', error);
showAlert('error', 'Failed to get file properties');
@@ -1404,45 +1404,45 @@ function setupFileManagerEventHandlers() {
// Handle Enter key in folder name input
const folderNameInput = document.getElementById('folderName');
if (folderNameInput) {
- folderNameInput.addEventListener('keypress', function(e) {
+ folderNameInput.addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
submitCreateFolder();
}
});
}
-
+
// Handle file selection change to show preview
const fileInput = document.getElementById('fileInput');
if (fileInput) {
- fileInput.addEventListener('change', function(e) {
+ fileInput.addEventListener('change', function (e) {
updateFileListPreview();
});
}
-
+
// Setup checkbox event listeners for file selection
const checkboxes = document.querySelectorAll('.file-checkbox');
checkboxes.forEach(checkbox => {
- checkbox.addEventListener('change', function() {
+ checkbox.addEventListener('change', function () {
updateDeleteSelectedButton();
updateSelectAllCheckbox();
});
});
-
+
// Setup drag and drop for file uploads
setupDragAndDrop();
-
+
// Clear form when modals are hidden
const createFolderModal = document.getElementById('createFolderModal');
if (createFolderModal) {
- createFolderModal.addEventListener('hidden.bs.modal', function() {
+ createFolderModal.addEventListener('hidden.bs.modal', function () {
document.getElementById('folderName').value = '';
});
}
-
+
const uploadFileModal = document.getElementById('uploadFileModal');
if (uploadFileModal) {
- uploadFileModal.addEventListener('hidden.bs.modal', function() {
+ uploadFileModal.addEventListener('hidden.bs.modal', function () {
const fileInput = document.getElementById('fileInput');
const progressContainer = document.getElementById('uploadProgress');
const fileListPreview = document.getElementById('fileListPreview');
@@ -1457,32 +1457,32 @@ function setupFileManagerEventHandlers() {
function setupDragAndDrop() {
const dropZone = document.querySelector('.card-body'); // Main file listing area
const uploadModal = document.getElementById('uploadFileModal');
-
+
if (!dropZone || !uploadModal) return;
-
+
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
-
+
// Highlight drop zone when item is dragged over it
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight, false);
});
-
+
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight, false);
});
-
+
// Handle dropped files
dropZone.addEventListener('drop', handleDrop, false);
-
+
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
-
+
function highlight(e) {
dropZone.classList.add('drag-over');
// Add some visual feedback
@@ -1514,7 +1514,7 @@ function setupDragAndDrop() {
dropZone.appendChild(overlay);
}
}
-
+
function unhighlight(e) {
dropZone.classList.remove('drag-over');
const overlay = dropZone.querySelector('.drag-overlay');
@@ -1522,23 +1522,23 @@ function setupDragAndDrop() {
overlay.remove();
}
}
-
+
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
-
+
if (files.length > 0) {
// Open upload modal and set files
const fileInput = document.getElementById('fileInput');
if (fileInput) {
// Create a new FileList-like object
const fileArray = Array.from(files);
-
+
// Set files to input (this is a bit tricky with file inputs)
const dataTransfer = new DataTransfer();
fileArray.forEach(file => dataTransfer.items.add(file));
fileInput.files = dataTransfer.files;
-
+
// Update preview and show modal
updateFileListPreview();
const modal = new bootstrap.Modal(uploadModal);
@@ -1553,20 +1553,20 @@ function updateFileListPreview() {
const fileInput = document.getElementById('fileInput');
const fileListPreview = document.getElementById('fileListPreview');
const selectedFilesList = document.getElementById('selectedFilesList');
-
+
if (!fileInput.files || fileInput.files.length === 0) {
fileListPreview.style.display = 'none';
return;
}
-
+
const files = Array.from(fileInput.files);
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
-
+
let html = `
${files.length} file(s) selected
Total: ${formatBytes(totalSize)}
`;
-
+
files.forEach((file, index) => {
const fileIcon = getFileIconByName(file.name);
html += `
@@ -1577,7 +1577,7 @@ function updateFileListPreview() {
${formatBytes(file.size)}
`;
});
-
+
selectedFilesList.innerHTML = html;
fileListPreview.style.display = 'block';
}
@@ -1585,7 +1585,7 @@ function updateFileListPreview() {
// Get file icon based on file name/extension
function getFileIconByName(fileName) {
const ext = fileName.split('.').pop().toLowerCase();
-
+
switch (ext) {
case 'jpg':
case 'jpeg':
@@ -1643,14 +1643,14 @@ function getFileIconByName(fileName) {
function showQuotaModal(bucketName, currentQuotaMB, quotaEnabled) {
document.getElementById('quotaBucketName').value = bucketName;
document.getElementById('quotaEnabled').checked = quotaEnabled;
-
+
// Convert quota to appropriate unit and set values
const quotaBytes = currentQuotaMB * 1024 * 1024; // Convert MB to bytes
const { size, unit } = convertBytesToBestUnit(quotaBytes);
-
+
document.getElementById('quotaSizeMB').value = size;
document.getElementById('quotaUnitMB').value = unit;
-
+
// Show/hide quota size settings based on enabled state
const quotaSizeSettings = document.getElementById('quotaSizeSettings');
if (quotaEnabled) {
@@ -1658,7 +1658,7 @@ function showQuotaModal(bucketName, currentQuotaMB, quotaEnabled) {
} else {
quotaSizeSettings.style.display = 'none';
}
-
+
const modal = new bootstrap.Modal(document.getElementById('manageQuotaModal'));
modal.show();
}
@@ -1668,17 +1668,17 @@ function convertBytesToBestUnit(bytes) {
if (bytes === 0) {
return { size: 0, unit: 'MB' };
}
-
+
// Check if it's a clean TB value
if (bytes >= 1024 * 1024 * 1024 * 1024 && bytes % (1024 * 1024 * 1024 * 1024) === 0) {
return { size: bytes / (1024 * 1024 * 1024 * 1024), unit: 'TB' };
}
-
+
// Check if it's a clean GB value
if (bytes >= 1024 * 1024 * 1024 && bytes % (1024 * 1024 * 1024) === 0) {
return { size: bytes / (1024 * 1024 * 1024), unit: 'GB' };
}
-
+
// Default to MB
return { size: bytes / (1024 * 1024), unit: 'MB' };
}
@@ -1686,11 +1686,11 @@ function convertBytesToBestUnit(bytes) {
// Handle quota update form submission
async function handleUpdateQuota(event) {
event.preventDefault();
-
+
const form = event.target;
const formData = new FormData(form);
const bucketName = document.getElementById('quotaBucketName').value;
-
+
const quotaData = {
quota_enabled: formData.get('quota_enabled') === 'on',
quota_size: parseInt(formData.get('quota_size')) || 0,
@@ -1711,11 +1711,11 @@ async function handleUpdateQuota(event) {
if (response.ok) {
// Success
showAlert('success', `Quota for bucket "${bucketName}" updated successfully!`);
-
+
// Close modal
const modal = bootstrap.Modal.getInstance(document.getElementById('manageQuotaModal'));
modal.hide();
-
+
// Refresh the page after a short delay
setTimeout(() => {
location.reload();
@@ -1735,7 +1735,7 @@ function showFileViewer(data) {
const file = data.file;
const content = data.content || '';
const viewable = data.viewable !== false;
-
+
// Create modal HTML
const modalHtml = `
@@ -1760,20 +1760,20 @@ function showFileViewer(data) {
`;
-
+
// Remove existing modal if any
const existingModal = document.getElementById('fileViewerModal');
if (existingModal) {
existingModal.remove();
}
-
+
// Add modal to DOM
document.body.insertAdjacentHTML('beforeend', modalHtml);
-
+
// Show modal
const modal = new bootstrap.Modal(document.getElementById('fileViewerModal'));
modal.show();
-
+
// Clean up when modal is hidden
document.getElementById('fileViewerModal').addEventListener('hidden.bs.modal', function () {
this.remove();
@@ -1853,7 +1853,7 @@ function getLanguageFromMime(mime, filename) {
case 'text/sql': return 'sql';
case 'text/markdown': return 'markdown';
}
-
+
// Fallback to file extension
const ext = filename.split('.').pop().toLowerCase();
switch (ext) {
@@ -1908,20 +1908,20 @@ function showPropertiesModal(properties) {