Add file rename functionality and improve preview handling

- Implement file/folder rename feature with dialog and API endpoint
- Add rename button to file browser with keyboard shortcuts
- Switch PDF preview from object to embed tag for better compatibility
- Fix CORS issues by fetching preview files as blobs with object URLs
- Add proper cleanup for object URLs to prevent memory leaks
- Add renameObject utility function for MinIO operations
This commit is contained in:
2025-06-04 18:14:00 +02:00
parent 673b6c6748
commit bac1bb2b5e
4 changed files with 317 additions and 16 deletions

View File

@@ -136,7 +136,13 @@ export const getDownloadUrl = async (fileName: string, expiry: number = 60 * 60)
const bucketName = useRuntimeConfig().minio.bucketName;
// Extract just the filename from the full path
const filename = fileName.split('/').pop() || fileName;
let filename = fileName.split('/').pop() || fileName;
// Remove timestamp prefix if present (e.g., "1234567890-filename.pdf" -> "filename.pdf")
const timestampMatch = filename.match(/^\d{10,}-(.+)$/);
if (timestampMatch) {
filename = timestampMatch[1];
}
// Force download with Content-Disposition header
const responseHeaders = {
@@ -220,3 +226,74 @@ export const getPreviewUrl = async (fileName: string, contentType: string) => {
return await client.presignedGetObject(bucketName, fileName, 60 * 60, responseHeaders);
};
// Rename file (copy and delete)
export const renameFile = async (oldPath: string, newPath: string) => {
const client = getMinioClient();
const bucketName = useRuntimeConfig().minio.bucketName;
try {
// Copy the object to the new name
await client.copyObject(
bucketName,
newPath,
`/${bucketName}/${oldPath}`
);
// Delete the old object
await client.removeObject(bucketName, oldPath);
return true;
} catch (error) {
console.error('Error renaming file:', error);
throw error;
}
};
// Rename folder (copy all contents and delete)
export const renameFolder = async (oldPath: string, newPath: string) => {
const client = getMinioClient();
const bucketName = useRuntimeConfig().minio.bucketName;
// Ensure paths end with /
const oldPrefix = oldPath.endsWith('/') ? oldPath : oldPath + '/';
const newPrefix = newPath.endsWith('/') ? newPath : newPath + '/';
// List all objects in the folder
const objectsList: string[] = [];
return new Promise((resolve, reject) => {
const stream = client.listObjectsV2(bucketName, oldPrefix, true);
stream.on('data', (obj) => {
if (obj && obj.name) {
objectsList.push(obj.name);
}
});
stream.on('error', reject);
stream.on('end', async () => {
try {
// Copy all objects to new location
for (const objectName of objectsList) {
const newObjectName = objectName.replace(oldPrefix, newPrefix);
await client.copyObject(
bucketName,
newObjectName,
`/${bucketName}/${objectName}`
);
}
// Delete all old objects
if (objectsList.length > 0) {
await client.removeObjects(bucketName, objectsList);
}
resolve(true);
} catch (error) {
reject(error);
}
});
});
};