diff --git a/.gitignore b/.gitignore index d314607..273db80 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ tests/_output/* /vendor /config /.ddev +/.php-cs-fixer.cache diff --git a/Classes/Controller/XlsimportController.php b/Classes/Controller/XlsimportController.php index 48a7b5b..c64119a 100644 --- a/Classes/Controller/XlsimportController.php +++ b/Classes/Controller/XlsimportController.php @@ -12,24 +12,28 @@ use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Worksheet\RowCellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\RowIterator; +use Psr\Http\Message\ResponseInterface; +use SUDHAUS7\Xlsimport\Property\TypeConverter\UploadedFileConverter; use SUDHAUS7\Xlsimport\Utility\AccessUtility; +use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Backend\Utility\BackendUtility; -use TYPO3\CMS\Backend\View\BackendTemplateView; use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException; use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationPathDoesNotExistException; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; +use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\DataHandling\DataHandler; +use TYPO3\CMS\Core\Http\UploadedFile; use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; -use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException; use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException; +use TYPO3\CMS\Extbase\Utility\LocalizationUtility; use TYPO3\CMS\Recordlist\Controller\AccessDeniedException; /** @@ -37,12 +41,6 @@ */ class XlsimportController extends ActionController { - /** - * Backend Template Container - * - * @var string - */ - protected $defaultViewObjectName = BackendTemplateView::class; /** * @var LanguageService */ @@ -53,21 +51,16 @@ class XlsimportController extends ActionController */ protected ResourceFactory $resourceFactory; + protected ModuleTemplateFactory $moduleTemplateFactory; + public function __construct( ResourceFactory $resourceFactory, - LanguageService $languageService + LanguageService $languageService, + ModuleTemplateFactory $moduleTemplateFactory ) { $this->resourceFactory = $resourceFactory; $this->languageService = $languageService; - } - - /** - * XlsimportController constructor. - */ - public function initializeObject(): void - { - GeneralUtility::makeInstance(PageRenderer::class) - ->loadRequireJsModule('TYPO3/CMS/Xlsimport/Importer'); + $this->moduleTemplateFactory = $moduleTemplateFactory; } /** @@ -75,8 +68,9 @@ public function initializeObject(): void * @throws ExtensionConfigurationExtensionNotConfiguredException * @throws AccessDeniedException */ - public function indexAction(): void + public function indexAction(): ResponseInterface { + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); $page = (int)GeneralUtility::_GET('id'); $minimalPage = [ 'uid' => $page, @@ -122,6 +116,21 @@ public function indexAction(): void 'allowedTables' => $allowedTables, ]; $this->view->assignMultiple($assignedValues); + $moduleTemplate + ->setTitle('S7 XLS Importer') + ->setModuleName('Importer') + ->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } + + public function initializeUploadAction(): void + { + if ($this->arguments->hasArgument('file')) { + $this->arguments + ->getArgument('file') + ->getPropertyMappingConfiguration() + ->setTypeConverter(new UploadedFileConverter()); + } } /** @@ -131,9 +140,30 @@ public function indexAction(): void * @throws DBALException * @throws AccessDeniedException */ - public function uploadAction(): void - { - $page = GeneralUtility::_GET('id'); + public function uploadAction( + string $table, + UploadedFile $file = null, + bool $deleteRecords = false, + bool $encoding = false, + bool $retry = false, + string $jsonData = '' + ): ResponseInterface { + // we didn't receive a retry and the file upload failed. Redirect to index + if ($file === null && !$retry) { + $message = GeneralUtility::makeInstance( + FlashMessage::class, + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:error.file.uploadFailed.message'), + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:error.file.uploadFailed.header'), + FlashMessage::ERROR, + true + ); + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); + $messageQueue = $flashMessageService->getMessageQueueByIdentifier(); + $messageQueue->enqueue($message); + $this->redirect('index'); + } + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $page = (int)GeneralUtility::_GET('id'); $tempPage = [ 'uid' => $page, ]; @@ -144,10 +174,7 @@ public function uploadAction(): void ); } - $deleteOldRecords = (bool)$this->request->getArgument('deleteRecords'); - $file = $this->request->getArgument('file'); - $table = $this->request->getArgument('table'); - if ($deleteOldRecords && AccessUtility::isAllowedTable($table, $page)) { + if ($deleteRecords && AccessUtility::isAllowedTable($table, $page)) { $dataHandler = GeneralUtility::makeInstance(DataHandler::class); $db = GeneralUtility::makeInstance(ConnectionPool::class); @@ -165,10 +192,6 @@ public function uploadAction(): void } } - $uploadedFile = GeneralUtility::tempnam('xlsimport'); - GeneralUtility::upload_copy_move($file['tmp_name'], $uploadedFile); - - $list = $this->getList($uploadedFile); $uidConfig = [ 'uid' => [ 'label' => 'uid', @@ -222,13 +245,35 @@ public function uploadAction(): void } unset($column); + $fields = []; + + foreach ($tca as $field => $config) { + $fields[] = [ + 'type' => $field, + 'label' => $config['label'], + ]; + } + + if (!$retry) { + $uploadedFile = GeneralUtility::tempnam('xlsimport'); + $file->moveTo($uploadedFile); + $list = $this->prepareFileForImport($uploadedFile, $encoding); + GeneralUtility::unlink_tempfile($uploadedFile); + $jsonData = json_encode($list); + $fileName = GeneralUtility::tempnam('xlsimport', '.json'); + GeneralUtility::writeFile($fileName, $jsonData); + } else { + $list = $this->loadDataFromJsonFile($jsonData); + } + $assignedValues = [ - 'fields' => $tca, - 'data' => $list['data'], + 'fields' => $fields, + 'data' => $list, + 'jsonData' => basename($fileName ?? $jsonData), 'page' => $page, 'table' => $table, 'hasPasswordField' => $hasPasswordField, - 'passwordFields' => implode(',', $passwordFields), + 'passwordFields' => $passwordFields, 'addInlineSettings' => [ 'FormEngine' => [ 'formName' => 'importData', @@ -236,6 +281,10 @@ public function uploadAction(): void ], ]; $this->view->assignMultiple($assignedValues); + $moduleTemplate + ->setTitle('S7 XLS Import', LocalizationUtility::translate('prepare', 'xlsimport')) + ->setContent($this->view->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); } /** @@ -244,38 +293,34 @@ public function uploadAction(): void * @throws JsonException * @throws \TYPO3\CMS\Core\Exception */ - public function importAction(): void - { + public function importAction( + string $table, + string $jsonData, + array $fields, + array $dataset, + bool $passwordOverride = false, + array $passwordFields = [] + ): void { $page = GeneralUtility::_GET('id'); - $table = $this->request->getArgument('table'); if (!$table || !array_key_exists($table, $GLOBALS['TCA'])) { $this->redirect('index'); exit; } - /** @var array $fields */ - $fields = $this->request->getArgument('fields'); $overrides = []; if ($this->request->hasArgument('overrides')) { $overrides = $this->request->getArgument('overrides'); } - $passwordOverride = (bool)$this->request->getArgument('passwordOverride'); - $passwordFields = GeneralUtility::trimExplode(',', $this->request->getArgument('passwordFields')); + // load saved data from JSON + $data = $this->loadDataFromJsonFile($jsonData); - /** @var array $imports */ - $imports = json_decode($this->request->getArgument('dataset'), true, 512, JSON_THROW_ON_ERROR); - $a = []; - foreach ($imports as $import) { - $s = sprintf('%s=%s', $import['name'], urlencode($import['value'])); - $temp = []; - parse_str($s, $temp); - foreach ($temp['tx_xlsimport_web_xlsimporttxxlsimport']['dataset'] as $k => $v) { - foreach ($v as $key => $value) { - $a[$k][$key] = $value; - } + // remove all data, which should not be imported + foreach ($data as $index => $value) { + if (!array_key_exists($index, $dataset) || $dataset[$index] != 1) { + unset($data[$index]); } } - $imports = $a; + $imports = array_values($data); // unset all fields not assigned to a TCA field foreach ($fields as $key => $field) { @@ -286,6 +331,31 @@ public function importAction(): void unset($fields[$key]); } } + + // if fieldlist is empty from now, return data to importer and create flashMessage + if (empty($fields)) { + $message = GeneralUtility::makeInstance( + FlashMessage::class, + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:warning.fieldlist.empty.message'), + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:warning.fieldlist.empty.header'), + FlashMessage::WARNING, + true + ); + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); + $messageQueue = $flashMessageService->getMessageQueueByIdentifier(); + $messageQueue->enqueue($message); + $this->redirect( + 'upload', + null, + null, + [ + 'retry' => true, + 'jsonData' => $jsonData, + 'table' => $table, + ] + ); + } + // get override field and take a look inside fieldlist, if defined foreach ($overrides as $key => $override) { if (empty($override) | in_array($override, $fields, true)) { @@ -307,31 +377,29 @@ public function importAction(): void $table => [], ]; foreach ($imports as $import) { - if ($import['import']) { - $insertArray = []; - $update = false; - foreach ($fields as $key => $field) { - if ($field === 'uid') { - if (!empty($import[$key])) { - $update = true; - } - } else { - $insertArray[$field] = $import[$key]; - } - if (!isset($insertArray['pid'])) { - $insertArray['pid'] = $page; + $insertArray = []; + $update = false; + foreach ($fields as $key => $field) { + if ($field === 'uid') { + if (!empty($import[$key])) { + $update = true; } + } else { + $insertArray[$field] = $import[$key]; } - foreach ($overrides as $key => $override) { - $insertArray[$key] = $override; - } - - foreach ($passwordFields as $passwordField) { - $insertArray[$passwordField] = md5(sha1(microtime())); - } + } + if (!isset($insertArray['pid'])) { + $insertArray['pid'] = $page; + } + foreach ($overrides as $key => $override) { + $insertArray[$key] = $override; + } - $inserts[$table][$update ? $import['uid'] : uniqid('NEW_', true)] = $insertArray; + foreach ($passwordFields as $passwordField) { + $insertArray[$passwordField] = md5(sha1(microtime())); } + + $inserts[$table][$update ? $import['uid'] : uniqid('NEW_', true)] = $insertArray; } if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['Hooks'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['Hooks'] as $_classRef) { @@ -345,7 +413,7 @@ public function importAction(): void $tce = GeneralUtility::makeInstance(DataHandler::class); $tce->start($inserts, []); $tce->process_datamap(); - /** @var FlashMessage $message */ + $message = GeneralUtility::makeInstance( FlashMessage::class, $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:success'), @@ -353,33 +421,29 @@ public function importAction(): void FlashMessage::OK, true ); - /** @var FlashMessageService $flashMessageService */ + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); $messageQueue = $flashMessageService->getMessageQueueByIdentifier(); $messageQueue->enqueue($message); + GeneralUtility::unlink_tempfile($this->buildJsonFileName($jsonData)); $this->redirect('index'); } /** - * @param string $fileName * @return array * @throws Exception - * @throws NoSuchArgumentException * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception */ - protected function getList(string $fileName): array - { + protected function prepareFileForImport( + string $fileName, + bool $encoding = false + ): array { $aList = []; - $aList['rows'] = 0; - $aList['cols'] = 0; - $aList['data'] = []; if (is_file($fileName)) { $inputFileType = IOFactory::identify($fileName); if ($inputFileType === 'Csv') { $oReader = new Csv(); - $encoding = (bool)$this->request->getArgument('encoding'); - if ($encoding === true) { $oReader->setInputEncoding('CP1252'); } @@ -388,7 +452,6 @@ protected function getList(string $fileName): array } if ($oReader->canRead($fileName)) { - //$oReader->getReadDataOnly(); $xls = $oReader->load($fileName); $xls->setActiveSheetIndex(0); $sheet = $xls->getActiveSheet(); @@ -396,7 +459,7 @@ protected function getList(string $fileName): array $rowcount = 1; $colcount = 1; - foreach ($rowI as $k => $row) { + foreach ($rowI as $row) { $rowcount++; $cell = new RowCellIterator($sheet, 1, 'A'); @@ -411,12 +474,9 @@ protected function getList(string $fileName): array } } - $aList['rows'] = $rowcount; - $aList['cols'] = $colcount; - for ($y = 1; $y < $rowcount; $y++) { for ($x = 1; $x <= $colcount; $x++) { - $aList['data'][$y][$x] = $sheet->getCellByColumnAndRow($x, $y)->getValue(); + $aList[$y][$x] = $sheet->getCellByColumnAndRow($x, $y)->getValue(); } } @@ -443,4 +503,30 @@ private function checkTableAndAccessAllowed(array $possibleTables, int $pid): ar return $allowedTables; } + + private function loadDataFromJsonFile(string $jsonFileName): ?array + { + $jsonFile = $this->buildJsonFileName($jsonFileName); + if (is_file($jsonFile)) { + return json_decode(file_get_contents($jsonFile), true); + } + $message = GeneralUtility::makeInstance( + FlashMessage::class, + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:error.jsonFile.message'), + $this->languageService->sL('LLL:EXT:xlsimport/Resources/Private/Language/locallang.xlf:error.jsonFile.header'), + FlashMessage::WARNING, + true + ); + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); + $messageQueue = $flashMessageService->getMessageQueueByIdentifier(); + $messageQueue->enqueue($message); + $this->redirect('index'); + return null; + } + + private function buildJsonFileName(string $jsonFileName): string + { + $temporaryPath = Environment::getVarPath() . '/transient/'; + return sprintf('%s%s', $temporaryPath, $jsonFileName); + } } diff --git a/Classes/Property/TypeConverter/UploadedFileConverter.php b/Classes/Property/TypeConverter/UploadedFileConverter.php new file mode 100644 index 0000000..507311d --- /dev/null +++ b/Classes/Property/TypeConverter/UploadedFileConverter.php @@ -0,0 +1,35 @@ + + */ + protected $sourceTypes = ['array']; + + protected $targetType = UploadedFile::class; + + protected $priority = 30; + + /** + * @inheritDoc + */ + public function convertFrom( + $source, + string $targetType, + array $convertedChildProperties = [], + PropertyMappingConfigurationInterface $configuration = null + ) { + $uploadedFile = new UploadedFile($source['tmp_name'], $source['size'], $source['error'], $source['name'], $source['type']); + + return $uploadedFile->getError() === UPLOAD_ERR_OK ? $uploadedFile : null; + } +} diff --git a/Classes/Utility/AccessUtility.php b/Classes/Utility/AccessUtility.php index 912cfbf..ced9764 100644 --- a/Classes/Utility/AccessUtility.php +++ b/Classes/Utility/AccessUtility.php @@ -23,6 +23,13 @@ public static function isAllowedTable(string $possibleTable, int $pageId): bool public static function isAllowedField(string $table, string $fieldName): bool { $allowedFields = BackendUtility::getAllowedFieldsForTable($table); + // Disallow PID, as the Backend module selects by choosing the site + // in page tree. Allowing import with PID set will cause side effects. + // Admins are allowed to do. + $pidKey = array_search('pid', $allowedFields); + if ($pidKey && !self::getBackendUser()->isAdmin()) { + unset($allowedFields[$pidKey]); + } return in_array($fieldName, $allowedFields); } private static function checkTableIsAllowedOnPage(string $tableName, int $pageId): bool diff --git a/Documentation/Configuration/Index.rst b/Documentation/Configuration/Index.rst index d01b622..3c89d2f 100644 --- a/Documentation/Configuration/Index.rst +++ b/Documentation/Configuration/Index.rst @@ -38,4 +38,5 @@ extension configuration file set" from the "Static Template Files from TYPO3 Extensions" dropdown list in your TypoScript template. -Every TCA defined table could be used. Field names are taken by locallang files, so localization is done. +Every TCA defined table could be used. Field names are taken by locallang +files, so localization is done. diff --git a/Documentation/Images/DynamicSelect.png b/Documentation/Images/DynamicSelect.png index adb6477..d690cdc 100644 Binary files a/Documentation/Images/DynamicSelect.png and b/Documentation/Images/DynamicSelect.png differ diff --git a/Documentation/Images/ImportView.png b/Documentation/Images/ImportView.png index d019624..b55a07b 100644 Binary files a/Documentation/Images/ImportView.png and b/Documentation/Images/ImportView.png differ diff --git a/Documentation/Images/SelectFile.png b/Documentation/Images/SelectFile.png index e526f53..cffd0e9 100644 Binary files a/Documentation/Images/SelectFile.png and b/Documentation/Images/SelectFile.png differ diff --git a/Documentation/Images/SelectedValues.png b/Documentation/Images/SelectedValues.png index 15c439a..bd53bb7 100644 Binary files a/Documentation/Images/SelectedValues.png and b/Documentation/Images/SelectedValues.png differ diff --git a/Documentation/Images/StandardView.png b/Documentation/Images/StandardView.png index d2e373c..f0c5c25 100644 Binary files a/Documentation/Images/StandardView.png and b/Documentation/Images/StandardView.png differ diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst index d0473e4..1aad053 100644 --- a/Documentation/Introduction/Index.rst +++ b/Documentation/Introduction/Index.rst @@ -18,7 +18,8 @@ Introduction What does it do? ^^^^^^^^^^^^^^^^ -This extension allows the import of data to every database table inside TYPO3 defined in TCA configuration. +This extension allows the import of data to every database table inside TYPO3 +defined in TCA configuration. .. _screenshots: diff --git a/Documentation/Settings.cfg b/Documentation/Settings.cfg index 0cdca78..feee389 100644 --- a/Documentation/Settings.cfg +++ b/Documentation/Settings.cfg @@ -1,8 +1,8 @@ [general] project = (Sudhaus7) Xls Import -version = 1.0 -release = 1.0 +version = 4.0 +release = 4.0 t3author = Markus Hofmann, Frank Berger, Daniel Simon copyright = 2020 diff --git a/Documentation/Usage/Index.rst b/Documentation/Usage/Index.rst index 96c4d0d..1211817 100644 --- a/Documentation/Usage/Index.rst +++ b/Documentation/Usage/Index.rst @@ -17,46 +17,56 @@ Usage The default view of the module. -Beginning from here you have to select a page inside the pagetree you want to import your data to. +Beginning from here you can select a page inside the pagetree you want to import your data to. .. figure:: ../Images/SelectFile.png :alt: Select table and file view The view for selecting table and file for importing data. -Inside this view you can select your table you want to import to. As actual supported files you can use all listed -above file types. +Inside this view you can select your table you want to import to. As actual +supported files you can use all listed above file types. -The first checkbox allows you to select if the uploaded file is CP1252 encoded. This is especially useful if you encounter problems -with empty fields after the import due to UTF-8 problems. +The first checkbox allows you to select if the uploaded file is CP1252 encoded. +This is especially useful if you encounter problems with empty fields after +the import due to UTF-8 problems. -The second checkbox allows you to delete all records in the selected table on the selected page. +The second checkbox allows you to delete all records in the selected table on +the selected page. -For getting data updated instead of added, you have to define a row with the uid of the corresponding TYPO3 record inside -your Excel sheet. If you set one column to uid, the system tries to update the existing dataset. +For getting data updated instead of added, you have to define a row with the +uid of the corresponding TYPO3 record inside your Excel sheet. If you set +one column to uid, the system tries to update the existing dataset. Use the update feature carefully. +The PID insert can only used by TYPO3 Backend Administrators, as the import +with pid will cause side effects. + .. figure:: ../Images/ImportView.png :alt: View for the pre imported data The view of the pre imported data with empty selects -You will get a preview of your data. Now you have to decide, to witch column your data has to be written. -With the checkbox in the front you can exclude data from getting imported, this is useful for -header lines and empty lines to avoid problems with the TCA import. +You will get a preview of your data. Now you have to decide, to witch column +your data has to be written. With the checkbox in the front you can exclude +data from getting imported, this is useful for header lines and empty lines +to avoid problems with the TCA import. .. figure:: ../Images/DynamicSelect.png :alt: View for imported data with opened select An opened select for selecting the data column -Select for every column to witch column inside the database this column has to be added. If you choose ignore, the -column is ignored. Selecting uid will update the dataset with the uid inside this column instead of creating a new one. -Updating a dataset won't take effect on the pid, the data is stored. If no uid is set, a new dataset is created -at the current page. This allows to mix up updating records and creating new ones with only one import. +Select for every column to witch column inside the database this column has +to be added. If you choose ignore, the column is ignored. Selecting uid will +update the dataset with the uid inside this column instead of creating a new +one. Updating a dataset won't take effect on the pid, the data is stored. If +no uid is set, a new dataset is created at the current page. This allows to +mix up updating records and creating new ones with only one import. -After a successful import you will get a success message and your data is imported. +After a successful import you will get a success message and your data is +imported. .. figure:: ../Images/ImportedData.png :alt: Table view from tt_address with imported data diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index 819d946..ebec94c 100644 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -109,6 +109,31 @@ Allowed tables Erlaubte Tabellen + + + Empty field list + Leere Feldliste + + + You didn't choose any fields to map. Please correct in dropdowns below and submit again. + Sie haben keine Felder zugeordnet. Bitte korrigieren Sie das in den Auswahlfeldern und senden das Formular erneut ab. + + + File upload failed + Datei hochladen fehlgeschlagen + + + Something went wrong during the upload. Please try again. + Beim Hochladen ist etwas schiefgelaufen. Bitte versuchen Sie es erneut. + + + Temporarily saved file not found + Temporäre Datei nicht gefunden + + + The temporarily saved file was not found. Please try again with upload your data. + Die temporär gespeicherte Datei konnte nicht geladen werden. Bitte versuchen Sie einen erneuten Upload. + diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 08b6e75..6d0e1cf 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -83,6 +83,26 @@ Allowed tables + + + Empty field list + + + You didn't choose any fields to map. Please correct in dropdowns below and submit again. + + + + File upload failed + + + Something went wrong during the upload. Please try again. + + + Temporarily saved file not found + + + The temporarily saved file was not found. Please try again with upload your data. + diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html index 3f8cbc5..9b8bfc9 100644 --- a/Resources/Private/Layouts/Default.html +++ b/Resources/Private/Layouts/Default.html @@ -5,10 +5,9 @@ lang="en" f:schemaLocation="https://fluidtypo3.org/schemas/fluid-master.xsd" data-namespace-typo3-fluid="true"> - - -

-
- -

-

- - -

-

- - -

-

- - -

-

- -

+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ + +
+
+
+
+ {f:translate(key:'upload')} +
+
+
+
diff --git a/Resources/Private/Templates/Xlsimport/Upload.html b/Resources/Private/Templates/Xlsimport/Upload.html index a8e00d7..4812c10 100644 --- a/Resources/Private/Templates/Xlsimport/Upload.html +++ b/Resources/Private/Templates/Xlsimport/Upload.html @@ -14,34 +14,36 @@

-

- +
    +
  1. {f:translate(key: 'prepareinfo_text')}
  2. +
  3. {f:translate(key: 'importinfo_text')}
  4. +
- - - - -
- {f:translate(key: 'multiple')} - - - - - - - - - - + + + + + + +
+ {f:translate(key: 'multiple')} +
+
+
: {data -> f:count()}/{data -> f:count()} @@ -60,17 +62,18 @@

-

-