useAttachments
Panoramica
useAttachments è il composable di alto livello: combina un AttachmentAdapter (axios, GraphQL, mock, ...) con uno state reattivo per esporre lista, loading, errori, progress di upload e i metodi di rete.
L'adapter è risolto con priorità:
options.adapteresplicitoinject(ATTACHMENT_ADAPTER_KEY)fornito daVueAttachmentPlugin- Errore al primo metodo invocato
inject viene chiamato a setup-time, ma la verifica dell'adapter avviene solo al primo metodo di rete. Se passi attachments via prop a un componente presentational, il composable può girare senza alcun adapter (utile per demo/SSR).Firma
function useAttachments(options: UseAttachmentsOptions): {
attachments: Ref<Attachment[]>
isLoading: Ref<boolean>
error: Ref<string | null>
uploadProgress: Ref<number>
totalSize: ComputedRef<number>
hasAttachments: ComputedRef<boolean>
fetchAttachments: () => Promise<void>
uploadFile: (file: File) => Promise<Attachment>
downloadFile: (id: string, disposition?: 'inline' | 'attachment') => Promise<Blob>
deleteFile: (id: string) => Promise<void>
deleteMultiple: (ids: string[]) => Promise<void>
}
Opzioni
interface UseAttachmentsOptions {
/** Adapter esplicito; se omesso, viene risolto via inject del plugin. */
adapter?: AttachmentAdapter
/** Reference key dell'entità owner (es. 'tickets'/'idticket'/123). */
referenceTable?: string
referenceColumn?: string
referenceValue?: string | number
/** Path storage su MinIO/S3 (override del default del plugin). */
storagePath?: string
}
referenceTable e referenceValue sono valorizzati, il composable lancia fetchAttachments() automaticamente. Altrimenti devi chiamarlo esplicitamente. Niente watch reattivo: cambiare referenceValue dopo il setup non re-fetcha — usa il pattern key sul componente padre o chiama fetchAttachments() manualmente.Esempio base (con plugin)
<script setup lang="ts">
import { useAttachments } from '@pzeta/vue-attachment'
const {
attachments,
isLoading,
fetchAttachments,
uploadFile,
deleteFile
} = useAttachments({
// adapter omesso → inject dal VueAttachmentPlugin
referenceTable: 'tickets',
referenceColumn: 'idticket',
referenceValue: 42
})
async function handleUpload(file: File) {
await uploadFile(file)
// attachments si aggiorna automaticamente
}
</script>
<template>
<div v-if="isLoading">Caricamento...</div>
<ul v-else>
<li v-for="a in attachments" :key="a.id">
{{ a.fileName }}
<button @click="deleteFile(a.id)">Elimina</button>
</li>
</ul>
</template>
Esempio: adapter esplicito (no plugin)
Per scenari di test, multi-tenant o componenti isolati che non passano dal plugin globale:
import axios from 'axios'
import { createAxiosAdapter, useAttachments } from '@pzeta/vue-attachment'
const adapter = createAxiosAdapter(axios.create({ baseURL: '/api/storage' }))
const { attachments, fetchAttachments } = useAttachments({
adapter,
referenceTable: 'tickets',
referenceColumn: 'idticket',
referenceValue: 42
})
Download
downloadFile ritorna il Blob ma triggera automaticamente il save dialog del browser usando attachment.fileName:
const { downloadFile } = useAttachments({ /* ... */ })
await downloadFile('abc123') // disposition: 'inline' (default)
await downloadFile('abc123', 'attachment') // forza Content-Disposition: attachment
Upload progress
uploadProgress è un Ref<number> (0–100) aggiornato durante l'upload. L'adapter axios di default non popola attualmente questo valore via onUploadProgress — è disponibile come hook per adapter custom.
Gestione errori
const { error } = useAttachments({ /* ... */ })
watch(error, (msg) => {
if (msg) toast.error(msg)
})
Tutti i metodi catturano gli errori e popolano error.value. La Promise rilancia comunque l'eccezione, quindi puoi anche gestirla con try/catch lato consumer.
Stato reattivo
| Ref/Computed | Tipo | Descrizione |
|---|---|---|
attachments | Ref<Attachment[]> | Lista corrente |
isLoading | Ref<boolean> | True durante fetch/upload/download/delete |
error | Ref<string | null> | Ultimo errore (messaggio dell'eccezione) |
uploadProgress | Ref<number> | 0–100 (popolato solo se l'adapter lo supporta) |
totalSize | ComputedRef<number> | Somma size di tutti gli allegati (bytes) |
hasAttachments | ComputedRef<boolean> | attachments.length > 0 |