From 254cfa63a473d4869bdf3ac3d5da1059055c22d2 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 4 Jun 2025 17:09:28 +0200 Subject: [PATCH] Fix folder display and add validation to file listing operations - Handle folder names properly in getDisplayName by preserving trailing slash - Add validation to skip invalid objects during listing - Add default values for missing object properties (size, lastModified, etag) - Add debug logging for listObjectsV2 operations to help troubleshoot issues - Add null checks in deleteFolder to prevent errors with invalid objects --- server/api/files/list.ts | 6 ++++++ server/utils/minio.ts | 35 ++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/server/api/files/list.ts b/server/api/files/list.ts index 58397a0..87f33c0 100644 --- a/server/api/files/list.ts +++ b/server/api/files/list.ts @@ -78,6 +78,12 @@ function getFileIcon(filename: string): string { } function getDisplayName(filepath: string): string { + // Handle folders (ending with /) + if (filepath.endsWith('/')) { + const parts = filepath.slice(0, -1).split('/'); + return parts[parts.length - 1] + '/'; + } + // Get just the filename from the full path const parts = filepath.split('/'); const filename = parts[parts.length - 1]; diff --git a/server/utils/minio.ts b/server/utils/minio.ts index 5ae47ca..2b7c9d8 100644 --- a/server/utils/minio.ts +++ b/server/utils/minio.ts @@ -26,12 +26,23 @@ export const listFiles = async (prefix: string = '', recursive: boolean = false) try { const stream = client.listObjectsV2(bucketName, prefix, recursive); + console.log(`Starting listObjectsV2 with prefix: "${prefix}", recursive: ${recursive}`); + stream.on('data', (obj) => { + // Skip objects without a name + if (!obj || typeof obj.name !== 'string') { + console.log('Skipping invalid object:', obj); + return; + } + + console.log(`Object received: "${obj.name}", size: ${obj.size}, etag: ${obj.etag}`); if (!recursive) { if (prefix) { // Extract folder structure when inside a folder const relativePath = obj.name.substring(prefix.length); + if (!relativePath) return; // Skip if no relative path + const firstSlash = relativePath.indexOf('/'); if (firstSlash > -1) { @@ -42,9 +53,9 @@ export const listFiles = async (prefix: string = '', recursive: boolean = false) // This is a file in the current folder files.push({ name: obj.name, - size: obj.size, - lastModified: obj.lastModified, - etag: obj.etag, + size: obj.size || 0, + lastModified: obj.lastModified || new Date(), + etag: obj.etag || '', isFolder: false, }); } @@ -53,7 +64,7 @@ export const listFiles = async (prefix: string = '', recursive: boolean = false) const firstSlash = obj.name.indexOf('/'); if (obj.name.endsWith('/')) { - // This is a folder placeholder + // This is a folder placeholder created by createFolder folders.add(obj.name); } else if (firstSlash > -1) { // This is inside a folder, extract the folder @@ -63,9 +74,9 @@ export const listFiles = async (prefix: string = '', recursive: boolean = false) // This is a file at root files.push({ name: obj.name, - size: obj.size, - lastModified: obj.lastModified, - etag: obj.etag, + size: obj.size || 0, + lastModified: obj.lastModified || new Date(), + etag: obj.etag || '', isFolder: false, }); } @@ -75,9 +86,9 @@ export const listFiles = async (prefix: string = '', recursive: boolean = false) if (!obj.name.endsWith('/')) { files.push({ name: obj.name, - size: obj.size, - lastModified: obj.lastModified, - etag: obj.etag, + size: obj.size || 0, + lastModified: obj.lastModified || new Date(), + etag: obj.etag || '', isFolder: false, }); } @@ -154,7 +165,9 @@ export const deleteFolder = async (folderPath: string) => { const stream = client.listObjectsV2(bucketName, folderPath, true); stream.on('data', (obj) => { - objectsList.push(obj.name); + if (obj && obj.name) { + objectsList.push(obj.name); + } }); stream.on('error', reject);