diff --git a/config/config.yaml b/config/config.yaml index 7c22d5d..282cee8 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,3 +1,4 @@ imports: - { resource: "./config/sylius_grid.yaml" } - { resource: "./config/sylius_resource.yaml" } + - { resource: "./config/twig_hooks.yaml" } diff --git a/config/config/sylius_grid.yaml b/config/config/sylius_grid.yaml index 566261b..fbd72c8 100644 --- a/config/config/sylius_grid.yaml +++ b/config/config/sylius_grid.yaml @@ -2,6 +2,7 @@ sylius_grid: templates: action: export: '@SyliusGridImportExport\admin\import_export\grid\action\export.html.twig' + download: '@SyliusGridImportExport\admin\import_export\grid\action\download.html.twig' bulk_action: export: '@SyliusGridImportExport\admin\import_export\grid\bulk_action\export.html.twig' @@ -14,24 +15,32 @@ sylius_grid: sorting: createdAt: desc fields: - uuid: - type: string - label: sylius.ui.id - sortable: ~ + createdAt: + type: datetime + label: sylius.ui.created_at type: - type: string + type: twig label: sylius.ui.type + options: + template: '@SyliusGridImportExport\admin\import_export\grid\field\type.html.twig' resource: type: string - label: sylius.ui.resource + label: sylius_grid_import_export.ui.resource status: - type: string + type: twig label: sylius.ui.status - createdAt: - type: datetime - label: sylius.ui.created_at + options: + template: '@SyliusGridImportExport\admin\import_export\grid\field\status.html.twig' actions: item: + download: + type: download + label: sylius_grid_import_export.ui.download + options: + link: + route: sylius_grid_import_export_admin_process_download + parameters: + uuid: resource.uuid show: type: show delete: diff --git a/config/config/twig_hooks.yaml b/config/config/twig_hooks.yaml new file mode 100644 index 0000000..dfb7760 --- /dev/null +++ b/config/config/twig_hooks.yaml @@ -0,0 +1,47 @@ +sylius_twig_hooks: + hooks: + 'sylius_grid_import_export.admin.process.show.content': + sections: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections.html.twig' + priority: 0 + + 'sylius_grid_import_export.admin.process.show.content.sections': + general: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general.html.twig' + priority: 0 + + 'sylius_grid_import_export.admin.process.show.content.sections.general': + header: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/header.html.twig' + priority: 100 + table: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/table.html.twig' + priority: 0 + + 'sylius_grid_import_export.admin.process.show.content.sections.general.header': + title: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/header/title.html.twig' + priority: 0 + + 'sylius_grid_import_export.admin.process.show.content.sections.general.table': + uuid: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/uuid.html.twig' + priority: 500 + type: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/type.html.twig' + priority: 400 + resource: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/resource.html.twig' + priority: 300 + format: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/format.html.twig' + priority: 200 + status: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/status.html.twig' + priority: 150 + output: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/output.html.twig' + priority: 100 + timestamps: + template: '@SyliusGridImportExport/admin/import_export/show/content/sections/general/timestamps.html.twig' + priority: 0 diff --git a/config/doctrine/Process.orm.xml b/config/doctrine/Process.orm.xml index 898ca09..e37e86d 100644 --- a/config/doctrine/Process.orm.xml +++ b/config/doctrine/Process.orm.xml @@ -13,6 +13,7 @@ + diff --git a/config/routes/admin.yaml b/config/routes/admin.yaml index e5e6e4a..8fc5eb3 100644 --- a/config/routes/admin.yaml +++ b/config/routes/admin.yaml @@ -15,9 +15,6 @@ sylius_grid_import_export_admin_process: redirect: index grid: sylius_grid_import_export_admin_process permission: true - vars: - all: - hook_prefix: 'sylius_b2b.admin.import_export.process' type: sylius.resource sylius_grid_import_export_admin_process_show: @@ -30,4 +27,13 @@ sylius_grid_import_export_admin_process_show: template: '@SyliusAdmin/shared/crud/show.html.twig' permission: true vars: - hook_prefix: 'sylius_b2b.admin.import_export.process' + hook_prefix: 'sylius_grid_import_export.admin.process' + +sylius_grid_import_export_admin_process_download: + path: /import-export/processes/{uuid}/download + methods: [ GET ] + defaults: + _controller: sylius_import_export.controller.download_export_action + _sylius: + section: admin + permission: true diff --git a/config/services.xml b/config/services.xml index c44ec90..ce319aa 100644 --- a/config/services.xml +++ b/config/services.xml @@ -54,6 +54,12 @@ + + + + + + diff --git a/src/Controller/DownloadExportAction.php b/src/Controller/DownloadExportAction.php new file mode 100644 index 0000000..49dbace --- /dev/null +++ b/src/Controller/DownloadExportAction.php @@ -0,0 +1,67 @@ + $processRepository + */ + public function __construct( + private RepositoryInterface $processRepository, + ) { + } + + public function __invoke(string $uuid): Response + { + $process = $this->processRepository->find($uuid); + + if (null === $process) { + throw new NotFoundHttpException(sprintf('Export process "%s" not found', $uuid)); + } + + if ('success' !== $process->getStatus()) { + throw new NotFoundHttpException('Export file is not ready for download'); + } + + $filePath = $process->getOutput(); + if (empty($filePath)) { + throw new NotFoundHttpException('No output file available for this export'); + } + + if (!file_exists($filePath)) { + throw new NotFoundHttpException(sprintf('Export file "%s" does not exist', basename($filePath))); + } + + $response = new BinaryFileResponse($filePath); + + // Sanitize filename by removing invalid characters + $sanitizedResource = str_replace(['/', '\\', '.'], '_', $process->getResource()); + $sanitizedUuid = str_replace(['/', '\\'], '_', $process->getUuid()); + + $response->setContentDisposition( + ResponseHeaderBag::DISPOSITION_ATTACHMENT, + sprintf('export_%s_%s.%s', $sanitizedResource, $sanitizedUuid, $process->getFormat()), + ); + + return $response; + } +} diff --git a/src/Controller/ExportAction.php b/src/Controller/ExportAction.php index 5da76f4..80b251e 100644 --- a/src/Controller/ExportAction.php +++ b/src/Controller/ExportAction.php @@ -22,6 +22,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Messenger\MessageBusInterface; final class ExportAction @@ -69,6 +70,10 @@ public function __invoke(Request $request, string $grid): Response parameters: $parameters, )); + /** @var Session $session */ + $session = $request->getSession(); + $session->getFlashBag()->add('success', 'sylius_grid_import_export.export_started'); + return new RedirectResponse($request->headers->get('referer') ?? '/'); } } diff --git a/src/Entity/Process.php b/src/Entity/Process.php index 03561c3..4ef6095 100644 --- a/src/Entity/Process.php +++ b/src/Entity/Process.php @@ -33,6 +33,8 @@ class Process implements ProcessInterface protected string $output; + protected ?string $errorMessage = null; + public function getId(): string { return $this->uuid; @@ -107,4 +109,14 @@ public function setOutput(string $output): void { $this->output = $output; } + + public function getErrorMessage(): ?string + { + return $this->errorMessage; + } + + public function setErrorMessage(?string $errorMessage): void + { + $this->errorMessage = $errorMessage; + } } diff --git a/src/Entity/ProcessInterface.php b/src/Entity/ProcessInterface.php index 9ee7796..f6e48d0 100644 --- a/src/Entity/ProcessInterface.php +++ b/src/Entity/ProcessInterface.php @@ -49,4 +49,8 @@ public function setResourceIds(array $resourceIds): void; public function getOutput(): string; public function setOutput(string $output): void; + + public function getErrorMessage(): ?string; + + public function setErrorMessage(?string $errorMessage): void; } diff --git a/src/Messenger/Handler/ExportCommandHandler.php b/src/Messenger/Handler/ExportCommandHandler.php index 2da4f34..b3b0748 100644 --- a/src/Messenger/Handler/ExportCommandHandler.php +++ b/src/Messenger/Handler/ExportCommandHandler.php @@ -14,7 +14,6 @@ namespace Sylius\GridImportExport\Messenger\Handler; use Sylius\GridImportExport\Entity\ProcessInterface; -use Sylius\GridImportExport\Exception\ExportFailedException; use Sylius\GridImportExport\Factory\ProcessFactoryInterface; use Sylius\GridImportExport\Messenger\Command\ExportCommand; use Sylius\GridImportExport\Provider\Registry\ResourceDataProviderRegistryInterface; @@ -56,9 +55,9 @@ public function __invoke(ExportCommand $command): void $process->setStatus('success'); $process->setOutput($outputPath); - } catch (ExportFailedException $e) { + } catch (\Throwable $e) { $process->setStatus('failed'); - $process->setOutput($e->getTraceAsString()); + $process->setErrorMessage($e->getMessage()); } } } diff --git a/templates/admin/import_export/grid/action/download.html.twig b/templates/admin/import_export/grid/action/download.html.twig new file mode 100644 index 0000000..acfaf6c --- /dev/null +++ b/templates/admin/import_export/grid/action/download.html.twig @@ -0,0 +1,5 @@ +{% if data.status == 'success' and data.output %} + + {{ ux_icon(action.icon|default('tabler:download')) }} + +{% endif %} diff --git a/templates/admin/import_export/grid/field/status.html.twig b/templates/admin/import_export/grid/field/status.html.twig new file mode 100644 index 0000000..d7be31c --- /dev/null +++ b/templates/admin/import_export/grid/field/status.html.twig @@ -0,0 +1,10 @@ +{% + set viewOptions = { + failed: { color: 'bg-red-lt' }, + success: { color: 'bg-green-lt' }, + } +%} + + + {{ data }} + diff --git a/templates/admin/import_export/grid/field/type.html.twig b/templates/admin/import_export/grid/field/type.html.twig new file mode 100644 index 0000000..c5e4631 --- /dev/null +++ b/templates/admin/import_export/grid/field/type.html.twig @@ -0,0 +1,3 @@ + + {{ ('sylius_grid_import_export.ui.type.' ~ data)|trans }} + diff --git a/templates/admin/import_export/grid/show/content/sections.html.twig b/templates/admin/import_export/grid/show/content/sections.html.twig new file mode 100644 index 0000000..80a99c8 --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections.html.twig @@ -0,0 +1 @@ +{% hook 'sylius_grid_import_export.admin.process.show.content.sections' %} diff --git a/templates/admin/import_export/grid/show/content/sections/general.html.twig b/templates/admin/import_export/grid/show/content/sections/general.html.twig new file mode 100644 index 0000000..7cc0446 --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general.html.twig @@ -0,0 +1,9 @@ +
+

{{ 'sylius.ui.general_info'|trans }}

+ + + + {% sylius_hook 'sylius_grid_import_export.admin.process.show.content.sections.general' %} + +
+
diff --git a/templates/admin/import_export/grid/show/content/sections/general/format.html.twig b/templates/admin/import_export/grid/show/content/sections/general/format.html.twig new file mode 100644 index 0000000..0130dde --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/format.html.twig @@ -0,0 +1,4 @@ + + {{ 'sylius_grid_import_export.ui.format'|trans }} + {{ resource.format }} + diff --git a/templates/admin/import_export/grid/show/content/sections/general/resource.html.twig b/templates/admin/import_export/grid/show/content/sections/general/resource.html.twig new file mode 100644 index 0000000..a3d6b7d --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/resource.html.twig @@ -0,0 +1,4 @@ + + {{ 'sylius_grid_import_export.ui.resource'|trans }} + {{ resource.resource }} + diff --git a/templates/admin/import_export/grid/show/content/sections/general/status.html.twig b/templates/admin/import_export/grid/show/content/sections/general/status.html.twig new file mode 100644 index 0000000..9f769e4 --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/status.html.twig @@ -0,0 +1,4 @@ + + {{ 'sylius.ui.status'|trans }} + {% include '@SyliusGridImportExport/admin/import_export/grid/field/status.html.twig' with {'data': resource.status} %} + diff --git a/templates/admin/import_export/grid/show/content/sections/general/timestamps.html.twig b/templates/admin/import_export/grid/show/content/sections/general/timestamps.html.twig new file mode 100644 index 0000000..6a323d5 --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/timestamps.html.twig @@ -0,0 +1,11 @@ + + {{ 'sylius.ui.created_at'|trans }} + {{ resource.createdAt|date('Y-m-d H:i:s') }} + + +{% if resource.updatedAt %} + + {{ 'sylius.ui.updated_at'|trans }} + {{ resource.updatedAt|date('Y-m-d H:i:s') }} + +{% endif %} diff --git a/templates/admin/import_export/grid/show/content/sections/general/type.html.twig b/templates/admin/import_export/grid/show/content/sections/general/type.html.twig new file mode 100644 index 0000000..c63598f --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/type.html.twig @@ -0,0 +1,4 @@ + + {{ 'sylius.ui.type'|trans }} + {{ resource.type }} + diff --git a/templates/admin/import_export/grid/show/content/sections/general/uuid.html.twig b/templates/admin/import_export/grid/show/content/sections/general/uuid.html.twig new file mode 100644 index 0000000..746eaaa --- /dev/null +++ b/templates/admin/import_export/grid/show/content/sections/general/uuid.html.twig @@ -0,0 +1,4 @@ + + {{ 'sylius.ui.id'|trans }} + {{ resource.uuid }} + diff --git a/templates/admin/import_export/show/content/sections.html.twig b/templates/admin/import_export/show/content/sections.html.twig new file mode 100644 index 0000000..dd834c5 --- /dev/null +++ b/templates/admin/import_export/show/content/sections.html.twig @@ -0,0 +1,5 @@ +
+
+ {% hook 'sections' %} +
+
diff --git a/templates/admin/import_export/show/content/sections/general.html.twig b/templates/admin/import_export/show/content/sections/general.html.twig new file mode 100644 index 0000000..0bdff4f --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general.html.twig @@ -0,0 +1,3 @@ +
+ {% hook 'general' %} +
diff --git a/templates/admin/import_export/show/content/sections/general/format.html.twig b/templates/admin/import_export/show/content/sections/general/format.html.twig new file mode 100644 index 0000000..4654e6f --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/format.html.twig @@ -0,0 +1,6 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius_grid_import_export.ui.format'|trans }}
+
{{ resource.format }}
+
diff --git a/templates/admin/import_export/show/content/sections/general/header.html.twig b/templates/admin/import_export/show/content/sections/general/header.html.twig new file mode 100644 index 0000000..623fb6c --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/header.html.twig @@ -0,0 +1,5 @@ +
+
+ {% hook 'header' %} +
+
diff --git a/templates/admin/import_export/show/content/sections/general/header/title.html.twig b/templates/admin/import_export/show/content/sections/general/header/title.html.twig new file mode 100644 index 0000000..6eb52e2 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/header/title.html.twig @@ -0,0 +1 @@ +{{ 'sylius_grid_import_export.ui.process'|trans }} {{ 'sylius.ui.details'|trans }} diff --git a/templates/admin/import_export/show/content/sections/general/output.html.twig b/templates/admin/import_export/show/content/sections/general/output.html.twig new file mode 100644 index 0000000..d1017a0 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/output.html.twig @@ -0,0 +1,29 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius_grid_import_export.ui.output_file'|trans }}
+
+ {% if resource.status == 'success' and resource.output %} + + + {{ resource.output|split('/')|last }} + + {% elseif resource.status == 'failed' %} + + + {{ 'sylius_grid_import_export.ui.export_failed'|trans }} + {% if resource.errorMessage %} +
+ {{ resource.errorMessage }} + {% endif %} +
+ {% elseif resource.status == 'processing' %} + + + {{ 'sylius_grid_import_export.ui.processing'|trans }} + + {% else %} + {{ 'sylius_grid_import_export.ui.no_output'|trans }} + {% endif %} +
+
diff --git a/templates/admin/import_export/show/content/sections/general/resource.html.twig b/templates/admin/import_export/show/content/sections/general/resource.html.twig new file mode 100644 index 0000000..59a607e --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/resource.html.twig @@ -0,0 +1,6 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius_grid_import_export.ui.resource'|trans }}
+
{{ resource.resource }}
+
diff --git a/templates/admin/import_export/show/content/sections/general/status.html.twig b/templates/admin/import_export/show/content/sections/general/status.html.twig new file mode 100644 index 0000000..e8bdb49 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/status.html.twig @@ -0,0 +1,6 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius.ui.status'|trans }}
+
{% include '@SyliusGridImportExport/admin/import_export/grid/field/status.html.twig' with {'data': resource.status} %}
+
diff --git a/templates/admin/import_export/show/content/sections/general/table.html.twig b/templates/admin/import_export/show/content/sections/general/table.html.twig new file mode 100644 index 0000000..4013bab --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/table.html.twig @@ -0,0 +1,5 @@ +
+
+ {% hook 'table' %} +
+
diff --git a/templates/admin/import_export/show/content/sections/general/timestamps.html.twig b/templates/admin/import_export/show/content/sections/general/timestamps.html.twig new file mode 100644 index 0000000..d9a1669 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/timestamps.html.twig @@ -0,0 +1,13 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius.ui.created_at'|trans }}
+
{{ resource.createdAt|date('Y-m-d H:i:s') }}
+
+ +{% if resource.updatedAt %} +
+
{{ 'sylius.ui.updated_at'|trans }}
+
{{ resource.updatedAt|date('Y-m-d H:i:s') }}
+
+{% endif %} diff --git a/templates/admin/import_export/show/content/sections/general/type.html.twig b/templates/admin/import_export/show/content/sections/general/type.html.twig new file mode 100644 index 0000000..bae57d5 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/type.html.twig @@ -0,0 +1,6 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius.ui.type'|trans }}
+
{{ resource.type }}
+
diff --git a/templates/admin/import_export/show/content/sections/general/uuid.html.twig b/templates/admin/import_export/show/content/sections/general/uuid.html.twig new file mode 100644 index 0000000..1161bd9 --- /dev/null +++ b/templates/admin/import_export/show/content/sections/general/uuid.html.twig @@ -0,0 +1,6 @@ +{% set resource = hookable_metadata.context.resource %} + +
+
{{ 'sylius.ui.id'|trans }}
+
{{ resource.uuid }}
+
diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 06388b4..e975da8 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -7,3 +7,16 @@ sylius_grid_import_export: export: "Export" import_export: "Import / export" processes: "Processes" + resource: "Resource" + format: "Format" + process: "Process" + output_file: "Output File" + no_output: "No Output" + file_not_ready: "File not ready for download" + export_failed: "Export failed" + processing: "Processing..." + download: "Download export file" + type: + export: "Export" + import: "Import" + export_started: "Export started and will be processed in the background. You can check the status in the Import/Export processes list."