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

@@ -50,16 +50,12 @@
<!-- PDF Preview -->
<div v-else-if="isPdf" class="pdf-preview-container">
<object
:data="previewUrl"
<embed
:src="previewUrl"
type="application/pdf"
width="100%"
height="100%"
@load="loading = false"
@error="handlePreviewError"
>
<p>PDF preview is not available. <a :href="previewUrl" target="_blank">Click here to view the PDF</a>.</p>
</object>
/>
</div>
</v-card-text>
@@ -86,7 +82,7 @@
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { ref, computed, watch, onUnmounted } from 'vue';
interface FileItem {
name: string;
@@ -114,6 +110,7 @@ const emit = defineEmits<Emits>();
const loading = ref(false);
const error = ref('');
const previewUrl = ref('');
const objectUrl = ref('');
// Computed property for v-model binding
const isOpen = computed({
@@ -156,19 +153,39 @@ const loadPreview = async () => {
error.value = '';
previewUrl.value = '';
// Clean up previous object URL if exists
if (objectUrl.value) {
URL.revokeObjectURL(objectUrl.value);
objectUrl.value = '';
}
try {
// For images and PDFs, use the proxy endpoint to avoid CORS issues
// For images and PDFs, fetch as blob and create object URL
if (isImage.value || isPdf.value) {
// Use the proxy endpoint that serves the file directly
const proxyUrl = `/api/files/proxy-preview?fileName=${encodeURIComponent(props.file.name)}`;
console.log('Setting preview URL to:', proxyUrl);
previewUrl.value = proxyUrl;
// The loading state will be handled by the image/iframe onload event
// Fetch the file as a blob
const response = await fetch(`/api/files/proxy-preview?fileName=${encodeURIComponent(props.file.name)}`);
if (!response.ok) {
throw new Error('Failed to fetch file');
}
const blob = await response.blob();
// Create object URL from blob
objectUrl.value = URL.createObjectURL(blob);
previewUrl.value = objectUrl.value;
console.log('Created object URL for preview:', objectUrl.value);
// Set loading to false after a short delay to allow the component to render
setTimeout(() => {
loading.value = false;
}, 100);
} else {
throw new Error('File type does not support preview');
}
} catch (err: any) {
error.value = err.data?.statusMessage || err.message || 'Failed to load preview';
error.value = err.message || 'Failed to load preview';
loading.value = false;
}
};
@@ -201,7 +218,20 @@ const closeModal = () => {
isOpen.value = false;
previewUrl.value = '';
error.value = '';
// Clean up object URL
if (objectUrl.value) {
URL.revokeObjectURL(objectUrl.value);
objectUrl.value = '';
}
};
// Clean up on unmount
onUnmounted(() => {
if (objectUrl.value) {
URL.revokeObjectURL(objectUrl.value);
}
});
</script>
<style scoped>