ImportWizard
Panoramica
ImportWizard è il componente di alto livello che orchestra l'intero workflow di importazione. Espone un Dialog con uno Stepper lineare a 4 step:
- Carica File — drag & drop o file picker, validazione lato client, opzioni CSV se applicabili
- Mapping Campi — auto-suggest + tabella interattiva per associare colonne sorgente a campi destinazione
- Anteprima — dry-run lato server (
POST /import/test) con tabella errori/warning - Importa — esecuzione effettiva, sincrona o asincrona (con
ImportStatusTrackere polling)
Il componente crea internamente l'istanza di ImportExportApi e la fornisce ai sotto-componenti tramite provide(IMPORT_EXPORT_API_KEY). Tutta la logica di stato è delegata a useImport.
Props
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
visible | boolean | — | Visibilità del dialog (v-model) |
baseUrl | string | — | URL base dei microservizi import/export |
risorsa | string | undefined | Codice risorsa target (es. 'anagrafica'). Se omesso, va impostato dall'utente prima dell'upload |
valoriFissi | Record<string, unknown> | undefined | Valori iniettati su ogni riga importata (es. { idlistino: 2 }). I campi corrispondenti spariscono dallo step Mapping. Dalla 0.2.5 |
api | ImportExportClient | undefined | Client custom (interfaccia, non classe) — utile per testing, mock o backend alternativi. Se omesso, viene istanziato new ImportExportApi(baseUrl). Vedi Client interfaces |
Emits
| Evento | Payload | Descrizione |
|---|---|---|
update:visible | boolean | Richiesta apertura/chiusura dialog (v-model) |
importCompleted | { righeImportate: number; righeScartate: number } | Import completato (stato === 'completato' || 'parziale') |
error | Error | Errore propagato dall'ErrorBoundary interno |
Comportamento
- Reset alla chiusura: alla
hidedel dialog viene chiamatoreset()diuseImporte ilResetBoundaryinterno viene azzerato. Lo stato non sopravvive tra una sessione e l'altra. - Sincronizzazione
risorsa: la prop viene riallineata sia al cambio prop sia all'apertura del dialog (dopo chereset()ha azzerato il valore interno). - Auto-upload: se al
select-filelarisorsaè già valorizzata, l'upload parte automaticamente (handleSelectFile). Lo step 1 → 2 avviene quando l'upload + caricamento metadati ha successo. - Soglia async: se il file ha ≥ 500 righe (
ASYNC_THRESHOLD) l'esecuzione è asincrona —executeImportriceve unimportIdeuseImportStatusavvia il polling. Il valore è override-abile passandouseImport(api, { asyncThreshold: 1000 })quando si usano i singoli step manualmente. - Valori fissi:
valoriFissiva al servizio con l'upload, nel campo multipartfixedValues(JSON), enode-excel-importlo fonde su ogni riga. I campi che contiene non compaiono nel Mapping: l'utente non li deve mappare dal file. Comerisorsa, viene riallineato a ogni apertura del dialog. - Fine dell'import: a import terminato il pulsante di sinistra passa da «Annulla» a «Chiudi». Se l'import è
completatosenza righe scartate, il wizard si chiude da solo dopo 1,5 secondi, così l'utente vede l'esito e la pagina può aggiornare la lista suimportCompleted; con righe scartate resta aperto, per rivederle. Dalla 0.2.7. - Navigazione: lo Stepper è
linear— è possibile tornare indietro tramite il pulsante "Indietro", magoToSteprifiuta salti in avanti di più di 1 step.
Esempio completo
<script setup lang="ts">
import { ref } from 'vue'
import { ImportWizard } from '@pzeta/vue-importexport'
import '@pzeta/vue-importexport/style.css'
const showImport = ref(false)
const baseUrl = import.meta.env.VITE_IMPORTEXPORT_API_URL
function onCompleted(result: { righeImportate: number; righeScartate: number }) {
console.log(`Importate ${result.righeImportate}, scartate ${result.righeScartate}`)
// ricarica lista anagrafica, mostra toast, ecc.
}
function onError(err: Error) {
console.error('Errore wizard import:', err)
}
</script>
<template>
<button @click="showImport = true">Importa anagrafica</button>
<ImportWizard
v-model:visible="showImport"
:base-url="baseUrl"
risorsa="anagrafica"
@import-completed="onCompleted"
@error="onError"
/>
</template>
Valori fissi dal contesto
Quando l'import avviene dentro un contesto che fissa già un valore (il listino aperto, l'anagrafica corrente), passalo con valoriFissi invece di chiedere all'utente una colonna nel file. Così fa il gestore dei listini di vue-prezzi, dove le righe importate appartengono tutte al listino aperto:
<ImportWizard
v-model:visible="showImportWizard"
:base-url="importBaseUrl"
risorsa="listinoprezzi"
:valori-fissi="{ idlistino }"
@import-completed="handleImportCompleted"
/>
Selezione dinamica risorsa
Se non passi risorsa come prop, il primo step deve includere un Select per farla scegliere all'utente. In tal caso bisogna ricomporre il wizard manualmente usando useImport e i singoli ImportStep* — ImportWizard da solo non espone uno slot per la selezione risorsa.
Iniezione contesto
Il wizard crea (o riceve) il client, lo passa a useImport e lo fornisce ai discendenti:
// All'interno di ImportWizard:
const apiInstance = props.api ?? new ImportExportApi(props.baseUrl)
provide(IMPORT_EXPORT_API_KEY, apiInstance)
const { /* … */ } = useImport(apiInstance)
Gli step (ImportStepUpload, ImportStepMapping, …) non usano l'iniezione: ricevono lo stato con le props. Per sostituire il backend (mock, adapter GraphQL, SDK custom) si passa un ImportExportClient alla prop api. IMPORT_EXPORT_API_KEY è interna e non esportata: per un wizard composto a mano il client va a useImport(client), vedi Wizard custom.
Note
- Il dialog ha
maxWidth: 56rem— adatto a desktop. Su mobile occupa tutta la larghezza disponibile. - L'
ErrorBoundaryinterno cattura errori di render e invocazione e mostra una fallback UI con pulsante "Chiudi". - Il file picker accetta solo
.csv,.xlsx,.xls,.jsoned è limitato a 50 MB lato client.