Components

ImportWizard

Wizard multi-step per l'importazione massiva di dati CSV/Excel/JSON.

Panoramica

ImportWizard è il componente di alto livello che orchestra l'intero workflow di importazione. Espone un Dialog con uno Stepper lineare a 4 step:

  1. Carica File — drag & drop o file picker, validazione lato client, opzioni CSV se applicabili
  2. Mapping Campi — auto-suggest + tabella interattiva per associare colonne sorgente a campi destinazione
  3. Anteprima — dry-run lato server (POST /api/import/test) con tabella errori/warning
  4. Importa — esecuzione effettiva, sincrona o asincrona (con ImportStatusTracker e 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

PropTipoDefaultDescrizione
visiblebooleanVisibilità del dialog (v-model)
baseUrlstringURL base dei microservizi import/export
risorsastringundefinedCodice risorsa target (es. 'anagrafica'). Se omesso, va impostato dall'utente prima dell'upload
apiImportExportClientundefinedClient custom (interfaccia, non classe) — utile per testing, mock o backend alternativi. Se omesso, viene istanziato new ImportExportApi(baseUrl). Vedi Client interfaces

Emits

EventoPayloadDescrizione
update:visiblebooleanRichiesta apertura/chiusura dialog (v-model)
importCompleted{ righeImportate: number; righeScartate: number }Import completato (stato === 'completato' || 'parziale')
errorErrorErrore propagato dall'ErrorBoundary interno

Comportamento

  • Reset alla chiusura: alla hide del dialog viene chiamato reset() di useImport e il ResetBoundary interno 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 che reset() ha azzerato il valore interno).
  • Auto-upload: se al select-file la risorsa è 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 — executeImport riceve un importId e useImportStatus avvia il polling. Il valore è override-abile passando useImport(api, { asyncThreshold: 1000 }) quando si usano i singoli step manualmente.
  • Navigazione: lo Stepper è linear — è possibile tornare indietro tramite il pulsante "Indietro", ma goToStep rifiuta 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>

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

I sotto-componenti del wizard usano useApi() per recuperare l'istanza condivisa:

// All'interno di ImportWizard:
const apiInstance = props.api ?? new ImportExportApi(props.baseUrl)
provide(IMPORT_EXPORT_API_KEY, apiInstance)

IMPORT_EXPORT_API_KEY è tipizzato come InjectionKey<ImportExportClient> — quindi qualsiasi oggetto che soddisfi le 3 interfacce IImportClient/IExportClient/ITemplateClient può essere iniettato (mock, GraphQL adapter, SDK custom).

Note

  • Il dialog ha maxWidth: 56rem — adatto a desktop. Su mobile occupa tutta la larghezza disponibile.
  • L'ErrorBoundary interno cattura errori di render e invocazione e mostra una fallback UI con pulsante "Chiudi".
  • Il file picker accetta solo .csv,.xlsx,.xls,.json ed è limitato a 50 MB lato client.