/* exported importWizard -- appeles depuis les attributs HTML des templates */ // A20 phase 3 : registre Alpine.data (le build CSP ne résout pas les // globales window — probe « Undefined variable: importWizard »). document.addEventListener('alpine:init', function () { Alpine.data('importWizard', importWizard); }); function importWizard() { return { sources: [], sourceId: '', files: [], dragOver: false, mode: 'skip', busy: false, progress: 0, error: '', preview: null, report: null, mapping: {}, csrf: '', urlValue: '', urlError: '', forgeProvider: 'gitea', forgeOwner: '', forgeRepo: '', forgeState: 'all', forgeError: '', types: ['text','number','date','checkbox','email','url','phone','select','multi_select','status'], async init() { try { const r = await fetch('/api/import/sources'); this.sources = (await r.json()).sources || []; } catch { /* volontaire */ } try { const c = await fetch('/api/csrf-token'); this.csrf = (await c.json()).csrf_token; } catch { /* volontaire */ } }, humanSize(n) { return n > 1048576 ? (n/1048576).toFixed(1)+' Mo' : Math.max(1, Math.round(n/1024))+' Ko'; }, addFiles(list) { for (const f of list) this.files.push({file:f, name:f.name, size:f.size, status:'queued'}); this.preview = null; this.report = null; this.error = ''; }, onFiles(e) { this.addFiles(e.target.files); e.target.value=''; }, onDrop(e) { this.dragOver=false; this.addFiles(e.dataTransfer.files); }, buildForm(f) { const fd = new FormData(); fd.append('file', f.file); if (this.sourceId) fd.append('source', this.sourceId); fd.append('mode', this.mode); return fd; }, async doPreview() { this.busy = true; this.error=''; this.report=null; this.progress=10; try { let merged = null; for (let i=0;i (p.schema||[]).forEach(c => { this.mapping[c.name]=c.type; })); } catch { this.error = 'Erreur réseau'; } finally { this.busy = false; setTimeout(()=>{this.progress=0;},800); } }, async importOne(f) { f.status = 'running'; const fd = this.buildForm(f); if (Object.keys(this.mapping).length) fd.append('mapping', JSON.stringify(this.mapping)); const big = f.size > 5*1024*1024; try { if (big) { fd.append('async','true'); const r = await fetch('/api/import/run', {method:'POST', headers:{'X-CSRF-Token':this.csrf}, body:fd}); const d = await r.json(); if (!r.ok) { f.status='error'; f.error=d.detail||'Erreur'; return null; } return await this.pollJob(d.job_id, f); } const r = await fetch('/api/import/run', {method:'POST', headers:{'X-CSRF-Token':this.csrf}, body:fd}); const d = await r.json(); if (!r.ok) { f.status='error'; f.error=d.detail||'Erreur'; return null; } f.status = (d.status==='partial' ? 'partial' : 'done'); return d; } catch { f.status='error'; f.error='Erreur réseau'; return null; } }, async doImport() { this.busy = true; this.error=''; this.report=null; this.progress=0; const aggregate = {pages_created:0,pages_updated:0,collections_created:0,rows_created:0, attachments:0,skipped:0,warnings:[],errors:[],per_file:[]}; for (let i=0;i setTimeout(res, 700)); const r = await fetch('/api/import/jobs/'+jobId); const j = await r.json(); if (j.status === 'done') { if (f) f.status='done'; return j.report; } if (j.status === 'error') { if (f) { f.status='error'; f.error=j.error; } return null; } } if (f) { f.status='error'; f.error='Délai dépassé'; } return null; }, downloadReport() { const blob = new Blob([JSON.stringify(this.report, null, 2)], {type:'application/json'}); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'flowdeck-import-report.json'; a.click(); URL.revokeObjectURL(a.href); } }; }