diff --git a/ui/src/components/ticket/file/ImageModal.vue b/ui/src/components/ticket/file/ImageModal.vue
new file mode 100644
index 0000000..f6281f5
--- /dev/null
+++ b/ui/src/components/ticket/file/ImageModal.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
![]()
+
+
+
+
diff --git a/ui/src/components/ticket/file/TicketFiles.vue b/ui/src/components/ticket/file/TicketFiles.vue
index 8b44672..e1a08aa 100644
--- a/ui/src/components/ticket/file/TicketFiles.vue
+++ b/ui/src/components/ticket/file/TicketFiles.vue
@@ -5,6 +5,7 @@ import '@uppy/dashboard/dist/style.min.css'
import DeleteDialog from '@/components/common/DeleteDialog.vue'
import TicketPanel from '@/components/ticket/TicketPanel.vue'
import FileAddDialog from '@/components/ticket/file/FileAddDialog.vue'
+import ImageModal from '@/components/ticket/file/ImageModal.vue'
import { Button } from '@/components/ui/button'
import { useToast } from '@/components/ui/toast/use-toast'
@@ -30,6 +31,36 @@ const props = defineProps<{
files: Array | undefined
}>()
+const isImageModalOpen = ref(false)
+const selectedImageUrl = ref('')
+const selectedImageName = ref('')
+
+const isImage = (fileName: string) => {
+ const imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg']
+ const extension = fileName.split('.').pop()?.toLowerCase()
+ return extension ? imageExtensions.includes(extension) : false
+}
+
+const openImageModal = async (file: ModelFile) => {
+ if (!isImage(file.name)) return
+ try {
+ const response = await fetch(`/api/files/${file.id}/download`, {
+ headers: { Authorization: `Bearer ${authStore.token}` }
+ })
+ const blob = await response.blob()
+ selectedImageUrl.value = window.URL.createObjectURL(blob)
+ selectedImageName.value = file.name
+ isImageModalOpen.value = true
+ } catch (err) {
+ console.error('Error fetching image:', err)
+ toast({
+ title: 'Error',
+ description: 'Could not load image for preview.',
+ variant: 'destructive'
+ })
+ }
+}
+
const downloadFile = (file: any) => {
fetch(`/api/files/${file.id}/download`, {
headers: { Authorization: `Bearer ${authStore.token}` }
@@ -44,6 +75,8 @@ const downloadFile = (file: any) => {
link.download = file.name
document.body.appendChild(link)
link.click()
+ document.body.removeChild(link)
+ window.URL.revokeObjectURL(_url)
})
.catch((err) => {
console.log(err)
@@ -82,11 +115,24 @@ watch(
},
{ immediate: true }
)
+
+watch(isImageModalOpen, (isOpen) => {
+ if (!isOpen && selectedImageUrl.value) {
+ window.URL.revokeObjectURL(selectedImageUrl.value)
+ selectedImageUrl.value = ''
+ selectedImageName.value = ''
+ }
+})
+