From f967ef7544147665be0b1bac0c4a5cd1c7b38393 Mon Sep 17 00:00:00 2001 From: Haylan Date: Thu, 17 Sep 2026 12:38:39 +0200 Subject: [PATCH 1/5] feat(dump): filter admin dump list by from/to date range Adds optional from/to query params to the dumps list endpoint and DumpLister::list(), and bumps the plugin version to 0.0.2. --- composer.json | 2 +- src/Controller/DumpController.php | 31 +++++++++++++++++++++++++++++-- src/Service/DumpLister.php | 10 +++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9d7c2ac..adc23b7 100755 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Export database dumps for Shopware 6 environments.", "type": "shopware-platform-plugin", "license": "MIT", - "version": "0.0.1", + "version": "0.0.2", "keywords": [ "shopware", "shopware6", diff --git a/src/Controller/DumpController.php b/src/Controller/DumpController.php index fe12eb9..175d498 100644 --- a/src/Controller/DumpController.php +++ b/src/Controller/DumpController.php @@ -11,6 +11,7 @@ use Shopware\Core\Framework\Routing\ApiRouteScope; use Shopware\Core\PlatformRequest; use Symfony\Component\HttpFoundation\HeaderUtils; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -39,16 +40,42 @@ class DumpController defaults: [PlatformRequest::ATTRIBUTE_ACL => ['aeon_dump_manager.viewer']], methods: ['GET'] )] - public function list(): JsonResponse + public function list(Request $request): JsonResponse { $dumps = array_map( static fn ($dumpFile) => $dumpFile->jsonSerialize(), - $this->dumpLister->list() + $this->dumpLister->list( + $this->parseBoundDate($request->query->get('from'), false), + $this->parseBoundDate($request->query->get('to'), true), + ) ); return new JsonResponse(['dumps' => $dumps]); } + /** + * The datepicker emits ISO-8601 UTC strings (e.g. "2026-03-01T00:00:00.000Z") + * in date mode. An empty bound (no date set) stays null so the range is open + * on that side. The "to" side is widened to end-of-day so selecting a date + * includes every dump created that day, not just before midnight. + */ + private function parseBoundDate(?string $value, bool $endOfDay): ?\DateTimeImmutable + { + if ($value === null || trim($value) === '') { + return null; + } + + try { + $dateTime = new \DateTimeImmutable($value); + } catch (\Exception) { + return null; + } + + return $endOfDay + ? $dateTime->setTime(23, 59, 59) + : $dateTime->setTime(0, 0, 0); + } + #[Route( path: '/api/_action/aeon-dump-manager/dumps', name: 'api.action.aeon_dump_manager.dumps.create', diff --git a/src/Service/DumpLister.php b/src/Service/DumpLister.php index a6c8c4f..60b42aa 100644 --- a/src/Service/DumpLister.php +++ b/src/Service/DumpLister.php @@ -18,7 +18,7 @@ class DumpLister /** * @return DumpFile[] newest first */ - public function list(): array + public function list(?\DateTimeImmutable $from = null, ?\DateTimeImmutable $to = null): array { $dumps = []; @@ -33,6 +33,14 @@ class DumpLister continue; } + if ($from !== null && $datetime < $from) { + continue; + } + + if ($to !== null && $datetime > $to) { + continue; + } + $dumps[] = new DumpFile($filename, $datetime, $item->fileSize()); } From e5c3a5b28f3bed6048c31320a2eb13513ed74380 Mon Sep 17 00:00:00 2001 From: Haylan Date: Thu, 17 Sep 2026 12:38:54 +0200 Subject: [PATCH 2/5] fix(dump): normalize date-filter bounds to the app timezone before applying day boundary The admin date filter can send a naive local date string for "from" but a UTC Z-suffixed instant for "to" (sw-date-filter widens it client-side via Date#toISOString()). Comparing those directly against dump timestamps (parsed in PHP's default timezone) shifted the effective cutoff by the timezone offset. Re-express both bounds in the app's default timezone before applying the day boundary. Co-Authored-By: Claude Sonnet 5 --- src/Controller/DumpController.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Controller/DumpController.php b/src/Controller/DumpController.php index 175d498..16768e4 100644 --- a/src/Controller/DumpController.php +++ b/src/Controller/DumpController.php @@ -54,10 +54,14 @@ class DumpController } /** - * The datepicker emits ISO-8601 UTC strings (e.g. "2026-03-01T00:00:00.000Z") - * in date mode. An empty bound (no date set) stays null so the range is open - * on that side. The "to" side is widened to end-of-day so selecting a date - * includes every dump created that day, not just before midnight. + * The admin's date filter sends mixed shapes: the "from" bound is a naive local + * date string with no timezone marker (e.g. "2026-03-01T00:00:00"), while + * sw-date-filter widens "to" to end-of-day client-side via `Date#toISOString()`, + * which is always UTC (e.g. "2026-03-01T23:59:59.000Z"). Re-expressing both in + * PHP's default timezone (the same one DumpFilenameParser uses) before applying + * our own day-boundary keeps the calendar day the user actually picked, regardless + * of which shape arrived. An empty bound (no date set) stays null so the range is + * open on that side. */ private function parseBoundDate(?string $value, bool $endOfDay): ?\DateTimeImmutable { @@ -66,7 +70,7 @@ class DumpController } try { - $dateTime = new \DateTimeImmutable($value); + $dateTime = (new \DateTimeImmutable($value))->setTimezone(new \DateTimeZone(date_default_timezone_get())); } catch (\Exception) { return null; } From 6094b6f49c4f6ff519eb1469dbba871cfdf2d5bb Mon Sep 17 00:00:00 2001 From: Haylan Date: Thu, 17 Sep 2026 12:39:08 +0200 Subject: [PATCH 3/5] test(dump): replace @dataProvider annotations with #[DataProvider] attributes The installed PHPUnit (12.x, ahead of this plugin's ^10.0 dev constraint) no longer parses the @dataProvider PHPDoc annotation, so both tests silently ran their data-provider method with zero arguments and failed with ArgumentCountError. Co-Authored-By: Claude Sonnet 5 --- tests/Service/DumpFilenameParserTest.php | 5 ++--- tests/Service/MySqlVariantTest.php | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/Service/DumpFilenameParserTest.php b/tests/Service/DumpFilenameParserTest.php index 354b1e5..5b043fc 100644 --- a/tests/Service/DumpFilenameParserTest.php +++ b/tests/Service/DumpFilenameParserTest.php @@ -3,6 +3,7 @@ namespace AeonDumpManager\Tests\Service; use AeonDumpManager\Service\DumpFilenameParser; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class DumpFilenameParserTest extends TestCase @@ -29,9 +30,7 @@ class DumpFilenameParserTest extends TestCase self::assertEquals($dateTime, $this->parser->parse($filename)); } - /** - * @dataProvider invalidFilenameProvider - */ + #[DataProvider('invalidFilenameProvider')] public function testParseRejectsInvalidFilenames(string $filename): void { self::assertNull($this->parser->parse($filename)); diff --git a/tests/Service/MySqlVariantTest.php b/tests/Service/MySqlVariantTest.php index fb6020c..8947726 100644 --- a/tests/Service/MySqlVariantTest.php +++ b/tests/Service/MySqlVariantTest.php @@ -3,13 +3,12 @@ namespace AeonDumpManager\Tests\Service; use AeonDumpManager\Service\MySqlVariant; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class MySqlVariantTest extends TestCase { - /** - * @dataProvider versionProvider - */ + #[DataProvider('versionProvider')] public function testIsMariaDb(string $version, bool $expected): void { self::assertSame($expected, MySqlVariant::isMariaDb($version)); From 5a482b49bbd926a77962616b9d7f9d6fc143acd2 Mon Sep 17 00:00:00 2001 From: Haylan Date: Thu, 17 Sep 2026 12:39:23 +0200 Subject: [PATCH 4/5] feat(dump): add date-range filter, sortable columns, and native date formatting to admin list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wires the backend from/to filter into the UI via sw-filter-panel with a hand-built date-filter config (no DAL entity needed — sw-filter-panel's only external dependency, filterService, persists through the generic user_config entity, not one for the filtered resource). - Makes the datetime and sizeBytes columns sortable (ascending/descending) using the same Mixin.getByName('listing') core list pages use, which also persists sort state in the URL query string. - Replaces the ad hoc `new Date(value).toLocaleString()` with Shopware.Utils.format.date, matching the existing fileSize formatting and respecting the admin's locale/timezone. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 3 + .../aeon-dump-manager-list.html.twig | 12 ++- .../page/aeon-dump-manager-list/index.ts | 100 +++++++++++++++--- .../aeon-dump-manager/snippet/de-DE.json | 4 + .../aeon-dump-manager/snippet/en-GB.json | 4 + .../src/service/dump-api.service.ts | 7 +- 6 files changed, 114 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb34e0..04182c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,3 +20,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 creation runs synchronously. - ACL-gated (`aeon_dump_manager.viewer`/`.creator`/`.deleter`), enforced both client-side and server-side. +- Filter the dump list by a from/to date range, and sort the `datetime`/`sizeBytes` columns + ascending or descending. Dates are formatted with Shopware's locale/timezone-aware + `Shopware.Utils.format.date`, matching the existing `fileSize` formatting. diff --git a/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig b/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig index 2d00b1a..5e03557 100644 --- a/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig +++ b/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig @@ -14,14 +14,24 @@