From 5e3be3ec429df6d2a15aadd33328142ea579ad0d Mon Sep 17 00:00:00 2001 From: Oliver Rasche Date: Fri, 7 Aug 2026 12:59:49 +0200 Subject: [PATCH] Backend module: CSV import for the VITEC domain models New "VITEC Import" module under Web: one import page per domain model (v1: Market, Solution, Product - registry-driven, adding a model is one config entry). Workflow: upload a CSV (delimiter and encoding are auto-detected, including German-Excel semicolon/Windows-1252), map CSV columns to DB fields, persist the mapping per model together with the identity field used for matching (new table tx_vitec_import_mapping, no TCA - pure tool configuration), review a unified list of CSV rows matched against the DB records (new / update with differing fields / unchanged / db-only), then apply the checked rows through DataHandler. Each importable row carries an editable JSON payload textarea - what is written is the textarea content, not the raw CSV, so editors can fix values right in the review step. The parsed CSV travels through the form as a hidden JSON field: no session state, no temp files. Importable fields are derived from TCA at runtime (scalar types only; files, categories and other relations are excluded - a flat CSV cannot carry them). Payloads are whitelisted against that field list on apply; new records require a storage pid (prefilled from existing records). BE user permissions apply via DataHandler. The module ships its own CSS (backend-import.css, loaded only by this module) using the frontend button palette from _vitec.scss: orange #f47937 for primary actions, navy #26358c for secondary actions and structure. The stray

Hi

debug leftover in the shared backend layout is removed (also affects the OG Image module). Deliberately out of v1: import log with three-way compare (protection against overwriting manual edits), images/relations, multiple saved mappings per model. Co-Authored-By: Claude Opus 5 --- .../Controller/Backend/ImportController.php | 3 + .../Private/Layouts/Backend/Default.html | 1 - .../Private/Templates/Import/Index.html | 18 +-- .../Resources/Public/Css/backend-import.css | 105 ++++++++++++++++++ 4 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 packages/vitec/Resources/Public/Css/backend-import.css diff --git a/packages/vitec/Classes/Controller/Backend/ImportController.php b/packages/vitec/Classes/Controller/Backend/ImportController.php index 024eda2..3daae20 100644 --- a/packages/vitec/Classes/Controller/Backend/ImportController.php +++ b/packages/vitec/Classes/Controller/Backend/ImportController.php @@ -16,6 +16,7 @@ use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Http\RedirectResponse; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; +use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -45,6 +46,7 @@ final class ImportController private readonly MappingRepository $mappingRepository, private readonly CsvReader $csvReader, private readonly FlashMessageService $flashMessageService, + private readonly PageRenderer $pageRenderer, private readonly UriBuilder $uriBuilder, ) {} @@ -158,6 +160,7 @@ final class ImportController ]; } + $this->pageRenderer->addCssFile('EXT:vitec/Resources/Public/Css/backend-import.css'); $view = $this->moduleTemplateFactory->create($request); $view->assignMultiple([ 'models' => $this->registry->all(), diff --git a/packages/vitec/Resources/Private/Layouts/Backend/Default.html b/packages/vitec/Resources/Private/Layouts/Backend/Default.html index f1447ac..e93406f 100644 --- a/packages/vitec/Resources/Private/Layouts/Backend/Default.html +++ b/packages/vitec/Resources/Private/Layouts/Backend/Default.html @@ -2,7 +2,6 @@ xmlns:n="http://typo3.org/ns/GeorgRinger/News/ViewHelpers">
-

Hi

\ No newline at end of file diff --git a/packages/vitec/Resources/Private/Templates/Import/Index.html b/packages/vitec/Resources/Private/Templates/Import/Index.html index 548d0f8..1209b8b 100644 --- a/packages/vitec/Resources/Private/Templates/Import/Index.html +++ b/packages/vitec/Resources/Private/Templates/Import/Index.html @@ -49,7 +49,7 @@
Field mapping - saved mapping loaded + saved mapping loaded
@@ -101,10 +101,10 @@
Records -   {counts.new} new - {counts.update} update - {counts.unchanged} unchanged - {counts.dbonly} only in DB +   {counts.new} new + {counts.update} update + {counts.unchanged} unchanged + {counts.dbonly} only in DB
@@ -126,10 +126,10 @@
- new - update - unchanged - only in DB + new + update + unchanged + only in DB diff --git a/packages/vitec/Resources/Public/Css/backend-import.css b/packages/vitec/Resources/Public/Css/backend-import.css new file mode 100644 index 0000000..d2cb954 --- /dev/null +++ b/packages/vitec/Resources/Public/Css/backend-import.css @@ -0,0 +1,105 @@ +/** + * VITEC Import module - look & feel aligned with the frontend button + * palette (Resources/Public/SCSS/_vitec.scss): + * orange #f47937 (hover #db6324) - primary actions + * navy #26358c (hover #1e2a70) - secondary actions / structure + * graphite #313131 - neutral emphasis + * light #cccccc / #eeeeee - muted + * Loaded only by the import module (ImportController), scoped to + * .vitec-administration so other modules stay untouched. + */ + +.vitec-administration h2 { + color: #26358c; +} + +/* --- buttons ------------------------------------------------------- */ + +.vitec-administration .btn-primary { + background-color: #f47937; + border-color: #f47937; + color: #ffffff; +} +.vitec-administration .btn-primary:hover, +.vitec-administration .btn-primary:focus, +.vitec-administration .btn-primary:active { + background-color: #db6324; + border-color: #db6324; + color: #ffffff; +} + +.vitec-administration .btn-default { + background-color: #ffffff; + border: 1px solid #26358c; + color: #26358c; +} +.vitec-administration .btn-default:hover, +.vitec-administration .btn-default:focus { + background-color: #26358c; + border-color: #26358c; + color: #ffffff; +} + +/* --- model tabs ---------------------------------------------------- */ + +.vitec-administration .nav-tabs .nav-link { + color: #26358c; +} +.vitec-administration .nav-tabs .nav-link.active { + color: #0d0d0d; + font-weight: 600; + border-bottom: 3px solid #f47937; +} + +/* --- cards & tables ------------------------------------------------ */ + +.vitec-administration .card { + border: 1px solid #d8dbe6; +} +.vitec-administration .card-header { + background-color: #26358c; + color: #ffffff; +} +.vitec-administration thead th { + border-bottom: 2px solid #26358c; +} + +/* --- status badges -------------------------------------------------- */ + +.vitec-administration .vitec-badge { + display: inline-block; + padding: 2px 9px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + line-height: 1.6; +} +.vitec-administration .vitec-badge-new { + background-color: #f47937; + color: #ffffff; +} +.vitec-administration .vitec-badge-update { + background-color: #26358c; + color: #ffffff; +} +.vitec-administration .vitec-badge-unchanged { + background-color: #cccccc; + color: #0d0d0d; +} +.vitec-administration .vitec-badge-dbonly { + background-color: #eeeeee; + color: #313131; + border: 1px solid #cccccc; +} +.vitec-administration .vitec-badge-info { + background-color: #313131; + color: #ffffff; +} + +/* --- form focus (frontend uses a 3px orange outline) ---------------- */ + +.vitec-administration .form-control:focus, +.vitec-administration .form-select:focus { + border-color: #f47937; + box-shadow: 0 0 0 3px rgba(244, 121, 55, 0.35); +}