From b7f361b87cea33c426f5f3119079beb9ab870e1f Mon Sep 17 00:00:00 2001 From: DevEnv nis2-agile Date: Sun, 31 May 2026 14:37:22 +0200 Subject: [PATCH] [FEAT] Supply chain UI: i18n sp.* IT/EN + import mostra errors[] dettaglio righe scartate - public/js/i18n.js: +38 chiavi sp.* (IT+EN) per pulsanti header, categorie, template, import. - supply-chain.html: data-i18n sui 4 pulsanti header; l'import CSV ora mostra il dettaglio delle righe scartate (d.errors[] dal backend) in un
e tiene aperta la modale se ci sono errori (prima si chiudeva sempre, errori invisibili). - version 1.10.1. Inline JS validato (node --check). File statici -> live via nginx. Co-Authored-By: Claude Opus 4.8 --- public/js/i18n.js | 45 ++++++++++++++++++++++++++++++++++++++++ public/supply-chain.html | 18 ++++++++++------ public/version.json | 2 +- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/public/js/i18n.js b/public/js/i18n.js index b0897f0..eed2541 100644 --- a/public/js/i18n.js +++ b/public/js/i18n.js @@ -384,6 +384,51 @@ const I18n = (function () { 'feedback.notif_open': { it: 'Segnalazione registrata. Il team la prenderà in carico.', en: 'Report registered. The team will handle it.' }, }); + // ── Supply Chain / Fornitori (modulo questionari Fase 1) ──────────── + addTranslations({ + 'sp.import_btn': { it: 'Importa', en: 'Import' }, + 'sp.categories_btn': { it: 'Categorie', en: 'Categories' }, + 'sp.templates_btn': { it: 'Template', en: 'Templates' }, + 'sp.new_supplier': { it: '+ Nuovo Fornitore', en: '+ New Supplier' }, + 'sp.category_field': { it: 'Categoria fornitore', en: 'Supplier category' }, + 'sp.category_none': { it: '— Nessuna —', en: '— None —' }, + 'sp.category_hint': { it: 'Classifica il fornitore (es. Cloud Provider). Gestisci le categorie dal pulsante "Categorie".', en: 'Classify the supplier (e.g. Cloud Provider). Manage categories from the "Categories" button.' }, + // Categorie + 'sp.cat_title': { it: 'Categorie fornitore', en: 'Supplier categories' }, + 'sp.cat_new': { it: '+ Nuova categoria', en: '+ New category' }, + 'sp.cat_preset': { it: 'Preset', en: 'Preset' }, + 'sp.cat_custom': { it: 'Personalizzata', en: 'Custom' }, + 'sp.cat_not_editable': { it: 'non modificabile', en: 'not editable' }, + 'sp.cat_name': { it: 'Nome categoria', en: 'Category name' }, + 'sp.cat_desc': { it: 'Descrizione', en: 'Description' }, + 'sp.cat_preset_note': { it: 'Le categorie preset sono fornite dal sistema e non sono modificabili. Puoi creare categorie personalizzate per la tua organizzazione.', en: 'Preset categories are provided by the system and cannot be modified. You can create custom categories for your organization.' }, + 'sp.cat_name_required': { it: 'Il nome della categoria è obbligatorio.', en: 'Category name is required.' }, + 'sp.cat_created': { it: 'Categoria creata.', en: 'Category created.' }, + 'sp.cat_updated': { it: 'Categoria aggiornata.', en: 'Category updated.' }, + 'sp.cat_deleted': { it: 'Categoria eliminata.', en: 'Category deleted.' }, + 'sp.cat_delete_confirm': { it: 'Eliminare la categoria?', en: 'Delete this category?' }, + 'sp.cat_in_use': { it: 'Impossibile eliminare (categoria in uso?).', en: 'Cannot delete (category in use?).' }, + // Template + 'sp.tpl_title': { it: 'Template questionari', en: 'Questionnaire templates' }, + 'sp.tpl_empty': { it: 'Nessun template questionario per questa organizzazione.', en: 'No questionnaire template for this organization.' }, + 'sp.tpl_active': { it: 'Attivo', en: 'Active' }, + 'sp.tpl_default': { it: 'Default', en: 'Default' }, + 'sp.tpl_view_questions': { it: 'Vedi domande', en: 'View questions' }, + 'sp.tpl_back': { it: '← Torna ai template', en: '← Back to templates' }, + 'sp.tpl_readonly': { it: "Sola lettura. L'editor delle domande sarà disponibile in una prossima versione.", en: 'Read-only. The question editor will be available in a future version.' }, + 'sp.tpl_required': { it: 'Obbligatoria', en: 'Required' }, + 'sp.tpl_high_crit': { it: 'Solo alta criticità', en: 'High criticality only' }, + 'sp.tpl_weight': { it: 'Peso', en: 'Weight' }, + 'sp.tpl_questions': { it: 'domande', en: 'questions' }, + // Import + 'sp.import_title': { it: 'Importa fornitori', en: 'Import suppliers' }, + 'sp.import_run': { it: 'Importa', en: 'Import' }, + 'sp.import_no_rows': { it: 'Nessuna riga valida (serve intestazione + almeno un fornitore con "name").', en: 'No valid rows (header + at least one supplier with "name" required).' }, + 'sp.import_too_many': { it: 'Troppi record (max 1000).', en: 'Too many records (max 1000).' }, + 'sp.import_done': { it: 'Completato: creati {created}, aggiornati {updated}, saltati {skipped}.', en: 'Done: {created} created, {updated} updated, {skipped} skipped.' }, + 'sp.conn_error': { it: 'Errore di connessione.', en: 'Connection error.' }, + }); + return { init, getLang, setLang, t, applyTranslations, addTranslations }; })(); diff --git a/public/supply-chain.html b/public/supply-chain.html index 10a2db8..a5f8533 100644 --- a/public/supply-chain.html +++ b/public/supply-chain.html @@ -370,10 +370,10 @@

Sicurezza Supply Chain

- - - - + + + +
@@ -1277,10 +1277,16 @@ const res = await api.importSuppliers(rows); if (res.success) { const d = res.data || {}; - resEl.innerHTML = `Completato: creati ${d.created||0}, aggiornati ${d.updated||0}, saltati ${d.skipped||0}.`; + let html = `Completato: creati ${d.created||0}, aggiornati ${d.updated||0}, saltati ${d.skipped||0}.`; + if (Array.isArray(d.errors) && d.errors.length) { + const items = d.errors.slice(0, 20).map(e => `
  • Riga ${(e.row != null ? e.row + 1 : '?')}: ${escapeHtml(String(e.error || ''))}
  • `).join(''); + html += `
    ${d.errors.length} riga/e scartata/e — dettagli
      ${items}
    `; + } + resEl.innerHTML = html; showNotification(`Import: ${d.created||0} creati, ${d.updated||0} aggiornati`, 'success'); loadSuppliers(); - setTimeout(() => { const m = document.getElementById('importModalDyn'); if (m) m.remove(); }, 1800); + const keepOpen = Array.isArray(d.errors) && d.errors.length > 0; + if (!keepOpen) setTimeout(() => { const m = document.getElementById('importModalDyn'); if (m) m.remove(); }, 1800); } else { resEl.innerHTML = `${res.message || 'Errore import'}`; } diff --git a/public/version.json b/public/version.json index 6bab02e..4f80a28 100644 --- a/public/version.json +++ b/public/version.json @@ -1 +1 @@ -{"version":"1.10.0","build":"2026-05-31-v1.10.0","date":"2026-05-31","changelog":"UI modulo questionari fornitori: dropdown categoria nel form fornitore, gestione categorie (preset+custom CRUD), visualizzazione template questionari con domande GV.SC e badge nis2_ref (read-only). Backend Fase 1 ora pienamente usabile dalla UI."} +{"version":"1.10.1","build":"2026-05-31-v1.10.1","date":"2026-05-31","changelog":"Supply chain UI: chiavi i18n IT/EN (sp.*) per pulsanti modulo fornitori; import CSV mostra il dettaglio delle righe scartate (errors[]) e tiene aperta la modale in caso di errori. Completamento Fase 1 modulo questionari fornitori."}