mirror of
https://github.com/open-webui/open-webui
synced 2025-04-27 01:32:43 +00:00
enh: support non chrome browsers
This commit is contained in:
parent
a909aa1c20
commit
9f812e7022
@ -129,13 +129,30 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const uploadDirectoryHandler = async () => {
|
const uploadDirectoryHandler = async () => {
|
||||||
|
// Check if File System Access API is supported
|
||||||
|
const isFileSystemAccessSupported = 'showDirectoryPicker' in window;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get directory handle through picker
|
if (isFileSystemAccessSupported) {
|
||||||
|
// Modern browsers (Chrome, Edge) implementation
|
||||||
|
await handleModernBrowserUpload();
|
||||||
|
} else {
|
||||||
|
// Firefox fallback
|
||||||
|
await handleFirefoxUpload();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
handleUploadError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to check if a path contains hidden folders
|
||||||
|
const hasHiddenFolder = (path) => {
|
||||||
|
return path.split('/').some((part) => part.startsWith('.'));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modern browsers implementation using File System Access API
|
||||||
|
const handleModernBrowserUpload = async () => {
|
||||||
const dirHandle = await window.showDirectoryPicker();
|
const dirHandle = await window.showDirectoryPicker();
|
||||||
|
|
||||||
console.log(typeof dirHandle);
|
|
||||||
console.log(dirHandle);
|
|
||||||
|
|
||||||
let totalFiles = 0;
|
let totalFiles = 0;
|
||||||
let uploadedFiles = 0;
|
let uploadedFiles = 0;
|
||||||
|
|
||||||
@ -148,57 +165,129 @@
|
|||||||
// Recursive function to count all files excluding hidden ones
|
// Recursive function to count all files excluding hidden ones
|
||||||
async function countFiles(dirHandle) {
|
async function countFiles(dirHandle) {
|
||||||
for await (const entry of dirHandle.values()) {
|
for await (const entry of dirHandle.values()) {
|
||||||
if (entry.name.startsWith('.')) continue; // Skip hidden files and directories
|
// Skip hidden files and directories
|
||||||
|
if (entry.name.startsWith('.')) continue;
|
||||||
|
|
||||||
if (entry.kind === 'file') {
|
if (entry.kind === 'file') {
|
||||||
totalFiles++;
|
totalFiles++;
|
||||||
} else if (entry.kind === 'directory') {
|
} else if (entry.kind === 'directory') {
|
||||||
|
// Only process non-hidden directories
|
||||||
|
if (!entry.name.startsWith('.')) {
|
||||||
await countFiles(entry);
|
await countFiles(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Recursive function to process directories excluding hidden files
|
// Recursive function to process directories excluding hidden files and folders
|
||||||
async function processDirectory(dirHandle, path = '') {
|
async function processDirectory(dirHandle, path = '') {
|
||||||
for await (const entry of dirHandle.values()) {
|
for await (const entry of dirHandle.values()) {
|
||||||
if (entry.name.startsWith('.')) continue; // Skip hidden files and directories
|
// Skip hidden files and directories
|
||||||
|
if (entry.name.startsWith('.')) continue;
|
||||||
|
|
||||||
const entryPath = path ? `${path}/${entry.name}` : entry.name;
|
const entryPath = path ? `${path}/${entry.name}` : entry.name;
|
||||||
|
|
||||||
|
// Skip if the path contains any hidden folders
|
||||||
|
if (hasHiddenFolder(entryPath)) continue;
|
||||||
|
|
||||||
if (entry.kind === 'file') {
|
if (entry.kind === 'file') {
|
||||||
// Get file from handle
|
|
||||||
const file = await entry.getFile();
|
const file = await entry.getFile();
|
||||||
// Create a new file with the path information
|
|
||||||
const fileWithPath = new File([file], entryPath, { type: file.type });
|
const fileWithPath = new File([file], entryPath, { type: file.type });
|
||||||
|
|
||||||
await uploadFileHandler(fileWithPath);
|
await uploadFileHandler(fileWithPath);
|
||||||
uploadedFiles++;
|
uploadedFiles++;
|
||||||
updateProgress();
|
updateProgress();
|
||||||
} else if (entry.kind === 'directory') {
|
} else if (entry.kind === 'directory') {
|
||||||
// Recursively process subdirectories
|
// Only process non-hidden directories
|
||||||
|
if (!entry.name.startsWith('.')) {
|
||||||
await processDirectory(entry, entryPath);
|
await processDirectory(entry, entryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// First count all files excluding hidden ones
|
|
||||||
await countFiles(dirHandle);
|
await countFiles(dirHandle);
|
||||||
updateProgress();
|
updateProgress();
|
||||||
|
|
||||||
// Start processing from root directory
|
|
||||||
if (totalFiles > 0) {
|
if (totalFiles > 0) {
|
||||||
await processDirectory(dirHandle);
|
await processDirectory(dirHandle);
|
||||||
} else {
|
} else {
|
||||||
console.log('No files to upload.');
|
console.log('No files to upload.');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Firefox fallback implementation using traditional file input
|
||||||
|
const handleFirefoxUpload = async () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Create hidden file input
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.webkitdirectory = true;
|
||||||
|
input.directory = true;
|
||||||
|
input.multiple = true;
|
||||||
|
input.style.display = 'none';
|
||||||
|
|
||||||
|
// Add input to DOM temporarily
|
||||||
|
document.body.appendChild(input);
|
||||||
|
|
||||||
|
input.onchange = async () => {
|
||||||
|
try {
|
||||||
|
const files = Array.from(input.files)
|
||||||
|
// Filter out files from hidden folders
|
||||||
|
.filter((file) => !hasHiddenFolder(file.webkitRelativePath));
|
||||||
|
|
||||||
|
let totalFiles = files.length;
|
||||||
|
let uploadedFiles = 0;
|
||||||
|
|
||||||
|
// Function to update the UI with the progress
|
||||||
|
const updateProgress = () => {
|
||||||
|
const percentage = (uploadedFiles / totalFiles) * 100;
|
||||||
|
toast.info(
|
||||||
|
`Upload Progress: ${uploadedFiles}/${totalFiles} (${percentage.toFixed(2)}%)`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateProgress();
|
||||||
|
|
||||||
|
// Process all files
|
||||||
|
for (const file of files) {
|
||||||
|
// Skip hidden files (additional check)
|
||||||
|
if (!file.name.startsWith('.')) {
|
||||||
|
const relativePath = file.webkitRelativePath || file.name;
|
||||||
|
const fileWithPath = new File([file], relativePath, { type: file.type });
|
||||||
|
|
||||||
|
await uploadFileHandler(fileWithPath);
|
||||||
|
uploadedFiles++;
|
||||||
|
updateProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
document.body.removeChild(input);
|
||||||
|
resolve();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
input.onerror = (error) => {
|
||||||
|
document.body.removeChild(input);
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger file picker
|
||||||
|
input.click();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Error handler
|
||||||
|
const handleUploadError = (error) => {
|
||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
toast.info('Directory selection was cancelled');
|
toast.info('Directory selection was cancelled');
|
||||||
} else {
|
} else {
|
||||||
toast.error('Error accessing directory');
|
toast.error('Error accessing directory');
|
||||||
console.error('Directory access error:', error);
|
console.error('Directory access error:', error);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to maintain file paths within zip
|
// Helper function to maintain file paths within zip
|
||||||
|
Loading…
Reference in New Issue
Block a user