From 0903c8282f424371998a52a96144200987d0570e Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 26 Aug 2026 10:46:11 +0200 Subject: [PATCH 1/3] refactor: use EasyAdmin badge and icon components in admin templates --- templates/EasyAdminBundle/Fields/advisories.html.twig | 2 +- .../EasyAdminBundle/Fields/advisory_count.html.twig | 2 +- .../EasyAdminBundle/Fields/affected_sites.html.twig | 2 +- templates/EasyAdminBundle/Fields/changes.html.twig | 4 ++-- templates/EasyAdminBundle/Fields/cloned_by.html.twig | 6 +++--- templates/EasyAdminBundle/Fields/code.html.twig | 2 +- templates/EasyAdminBundle/Fields/db_version.html.twig | 4 ++-- templates/EasyAdminBundle/Fields/domain.html.twig | 2 +- templates/EasyAdminBundle/Fields/eol.html.twig | 8 ++++---- .../EasyAdminBundle/Fields/hosting_provider.html.twig | 10 +++++----- .../EasyAdminBundle/Fields/latest-status.html.twig | 10 +++++----- templates/EasyAdminBundle/Fields/server_type.html.twig | 10 +++++----- templates/EasyAdminBundle/Fields/site.html.twig | 6 +++--- templates/EasyAdminBundle/Fields/ssh_link.html.twig | 4 +--- templates/EasyAdminBundle/Fields/text_mono.html.twig | 2 +- templates/EasyAdminBundle/Fields/version.html.twig | 6 +++--- templates/EasyAdminBundle/Fields/warning.html.twig | 4 ++-- .../EasyAdminBundle/crud/field/association.html.twig | 8 ++++---- 18 files changed, 45 insertions(+), 47 deletions(-) diff --git a/templates/EasyAdminBundle/Fields/advisories.html.twig b/templates/EasyAdminBundle/Fields/advisories.html.twig index cfe1bbac..292cbfac 100644 --- a/templates/EasyAdminBundle/Fields/advisories.html.twig +++ b/templates/EasyAdminBundle/Fields/advisories.html.twig @@ -29,5 +29,5 @@ {% endif %} {% elseif field.formattedValue != 0 %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/advisory_count.html.twig b/templates/EasyAdminBundle/Fields/advisory_count.html.twig index 1b34775e..e3b03daa 100644 --- a/templates/EasyAdminBundle/Fields/advisory_count.html.twig +++ b/templates/EasyAdminBundle/Fields/advisory_count.html.twig @@ -2,5 +2,5 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue != 0 %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/affected_sites.html.twig b/templates/EasyAdminBundle/Fields/affected_sites.html.twig index a2eb5e38..32631181 100644 --- a/templates/EasyAdminBundle/Fields/affected_sites.html.twig +++ b/templates/EasyAdminBundle/Fields/affected_sites.html.twig @@ -29,5 +29,5 @@ None {% endif %} {% else %} - {{ sites|length }} + {{ sites|length }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/changes.html.twig b/templates/EasyAdminBundle/Fields/changes.html.twig index 06d19b93..a928d4f9 100644 --- a/templates/EasyAdminBundle/Fields/changes.html.twig +++ b/templates/EasyAdminBundle/Fields/changes.html.twig @@ -2,7 +2,7 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue == 0 %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/cloned_by.html.twig b/templates/EasyAdminBundle/Fields/cloned_by.html.twig index 157c2d87..f47deea0 100644 --- a/templates/EasyAdminBundle/Fields/cloned_by.html.twig +++ b/templates/EasyAdminBundle/Fields/cloned_by.html.twig @@ -2,9 +2,9 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue == 'unknown' %} - ? + ? {% elseif field.formattedValue starts with 'ssh' %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/code.html.twig b/templates/EasyAdminBundle/Fields/code.html.twig index 28a08e70..b2b8143b 100644 --- a/templates/EasyAdminBundle/Fields/code.html.twig +++ b/templates/EasyAdminBundle/Fields/code.html.twig @@ -2,7 +2,7 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue is null %} - {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} + {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} {% else %} {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/db_version.html.twig b/templates/EasyAdminBundle/Fields/db_version.html.twig index c192aebb..0f757b01 100644 --- a/templates/EasyAdminBundle/Fields/db_version.html.twig +++ b/templates/EasyAdminBundle/Fields/db_version.html.twig @@ -2,7 +2,7 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue is null %} - {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} + {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/domain.html.twig b/templates/EasyAdminBundle/Fields/domain.html.twig index accac032..233a7acd 100644 --- a/templates/EasyAdminBundle/Fields/domain.html.twig +++ b/templates/EasyAdminBundle/Fields/domain.html.twig @@ -4,7 +4,7 @@ {# NOTE: the rel="noopener" attr is needed to avoid performance and security issues (see https://web.dev/external-anchors-use-rel-noopener/) #} {% if field.formattedValue == 'unknown' %} - ? + ? {% elseif ea().crud.currentAction == 'detail' %} {{ field.value }} {% else %} diff --git a/templates/EasyAdminBundle/Fields/eol.html.twig b/templates/EasyAdminBundle/Fields/eol.html.twig index 91efa116..fcb9e5e3 100644 --- a/templates/EasyAdminBundle/Fields/eol.html.twig +++ b/templates/EasyAdminBundle/Fields/eol.html.twig @@ -11,11 +11,11 @@ {% endif %} {% if field.formattedValue is empty %} - ? + ? {% elseif 'Expired' in field.formattedValue %} - {{ outputValue }} + {{ outputValue }} {% elseif date('01/' ~ slicedDate) < date('+180days') %} - {{ outputValue }} + {{ outputValue }} {% else %} - {{ outputValue }} + {{ outputValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/hosting_provider.html.twig b/templates/EasyAdminBundle/Fields/hosting_provider.html.twig index cc1d7ab3..d4c63f75 100644 --- a/templates/EasyAdminBundle/Fields/hosting_provider.html.twig +++ b/templates/EasyAdminBundle/Fields/hosting_provider.html.twig @@ -2,13 +2,13 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue is empty %} - ? + ? {% elseif field.formattedValue == constant('App\\Types\\HostingProviderType::AZURE') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.formattedValue == constant('App\\Types\\HostingProviderType::IT_RELATION') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.formattedValue == constant('App\\Types\\HostingProviderType::DBC') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/latest-status.html.twig b/templates/EasyAdminBundle/Fields/latest-status.html.twig index 5ace6a73..c145cc9b 100644 --- a/templates/EasyAdminBundle/Fields/latest-status.html.twig +++ b/templates/EasyAdminBundle/Fields/latest-status.html.twig @@ -2,13 +2,13 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue == 'unknown' %} - ? + ? {% elseif field.formattedValue == 'up-to-date' %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.formattedValue == 'semver-safe-update' %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.formattedValue == 'update-possible' %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/server_type.html.twig b/templates/EasyAdminBundle/Fields/server_type.html.twig index 52369c6a..c9afaba4 100644 --- a/templates/EasyAdminBundle/Fields/server_type.html.twig +++ b/templates/EasyAdminBundle/Fields/server_type.html.twig @@ -2,13 +2,13 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.value is empty %} - ? + ? {% elseif field.value == constant('App\\Types\\ServerTypeType::PROD') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.value == constant('App\\Types\\ServerTypeType::STG') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.value == constant('App\\Types\\ServerTypeType::DEVOPS') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/site.html.twig b/templates/EasyAdminBundle/Fields/site.html.twig index 6bc1a587..eae8d9a1 100644 --- a/templates/EasyAdminBundle/Fields/site.html.twig +++ b/templates/EasyAdminBundle/Fields/site.html.twig @@ -2,9 +2,9 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue == constant('App\\Types\\SiteType::NGINX') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% elseif field.formattedValue == constant('App\\Types\\SiteType::DOCKER') %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/ssh_link.html.twig b/templates/EasyAdminBundle/Fields/ssh_link.html.twig index 11e692b8..8dbc74d3 100644 --- a/templates/EasyAdminBundle/Fields/ssh_link.html.twig +++ b/templates/EasyAdminBundle/Fields/ssh_link.html.twig @@ -5,9 +5,7 @@
{{ field.formattedValue }}
- - - +
diff --git a/templates/EasyAdminBundle/Fields/text_mono.html.twig b/templates/EasyAdminBundle/Fields/text_mono.html.twig index dab826df..65cc0651 100644 --- a/templates/EasyAdminBundle/Fields/text_mono.html.twig +++ b/templates/EasyAdminBundle/Fields/text_mono.html.twig @@ -2,7 +2,7 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue is null %} - {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} + {{ 'label.null'|trans(domain: 'EasyAdminBundle') }} {% else %} {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/version.html.twig b/templates/EasyAdminBundle/Fields/version.html.twig index 40c514ab..185621ba 100644 --- a/templates/EasyAdminBundle/Fields/version.html.twig +++ b/templates/EasyAdminBundle/Fields/version.html.twig @@ -2,9 +2,9 @@ {# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #} {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if field.formattedValue == 'unknown' %} - ? + ? {% elseif field.formattedValue starts with '${' %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% else %} - {{ field.formattedValue }} + {{ field.formattedValue }} {% endif %} diff --git a/templates/EasyAdminBundle/Fields/warning.html.twig b/templates/EasyAdminBundle/Fields/warning.html.twig index 27adefc0..7b91650e 100644 --- a/templates/EasyAdminBundle/Fields/warning.html.twig +++ b/templates/EasyAdminBundle/Fields/warning.html.twig @@ -5,10 +5,10 @@ {{ field.formattedValue|raw|nl2br }} {% else %} {% if field.formattedValue is null %} - + {% else %} - + {% endif %} {% endif %} diff --git a/templates/bundles/EasyAdminBundle/crud/field/association.html.twig b/templates/bundles/EasyAdminBundle/crud/field/association.html.twig index 7d5393a7..6fd3fd98 100644 --- a/templates/bundles/EasyAdminBundle/crud/field/association.html.twig +++ b/templates/bundles/EasyAdminBundle/crud/field/association.html.twig @@ -3,9 +3,9 @@ {# @var entity \EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto #} {% if 'toMany' == field.customOptions.get('associationType') %} {% if field.value.count == 0 %} - None + None {% elseif not has_display(field.value[0]) and ea().crud.currentAction != 'detail' %} - {{ field.value|length }} + {{ field.value|length }} {% else %} {% for value in field.value %} {% if ea().crud.currentAction == 'detail' %} @@ -13,10 +13,10 @@ {% elseif has_display(value) %} {{ entity_display(value, ea().crud.currentAction) }} {% else %} - None + None {% endif %} {% else %} - None + None {% endfor %} {% endif %} {% else %} From 356cbe31b8e681a7a88a5231c49e173188407369 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 26 Aug 2026 10:46:11 +0200 Subject: [PATCH 2/3] refactor: drop the AutoBadge menu item classes --- src/EasyAdmin/Config/AutoBadgeMenuItem.php | 31 ------------ .../Config/Menu/AutoBadgeCrudMenuItem.php | 50 ------------------- 2 files changed, 81 deletions(-) delete mode 100644 src/EasyAdmin/Config/AutoBadgeMenuItem.php delete mode 100644 src/EasyAdmin/Config/Menu/AutoBadgeCrudMenuItem.php diff --git a/src/EasyAdmin/Config/AutoBadgeMenuItem.php b/src/EasyAdmin/Config/AutoBadgeMenuItem.php deleted file mode 100644 index fec38b36..00000000 --- a/src/EasyAdmin/Config/AutoBadgeMenuItem.php +++ /dev/null @@ -1,31 +0,0 @@ -crudMenuItem = new CrudMenuItem($label, $icon, $entityFqcn); - } - - public function __call(string $name, array $arguments): mixed - { - return $this->crudMenuItem->$name(...$arguments); - } - - public static function __callStatic(string $name, array $arguments): never - { - throw new \BadMethodCallException(sprintf('Static method %s not implemented', $name)); - } - - public function setBadge(\Stringable|string|int|float|bool|null $content, string $style = 'secondary', array $htmlAttributes = []): self - { - if (!is_int($content)) { - throw new \InvalidArgumentException('The badge content must be an integer'); - } - - if ($content > 0) { - $this->crudMenuItem->setBadge($content, $style, $htmlAttributes); - } - - return $this; - } - - public function getAsDto(): MenuItemDto - { - return $this->crudMenuItem->getAsDto(); - } -} From 6bf01ae7c6d8d06ad98b4fcdc8d5a2414bc30c23 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 26 Aug 2026 10:55:11 +0200 Subject: [PATCH 3/3] fix: restore ITK admin styling and hide the zero-count badge --- CHANGELOG.md | 10 ++++++ assets/styles/app.css | 12 +++----- src/Controller/Admin/DashboardController.php | 32 +++++++++++++++----- webpack.config.js | 4 +++ 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db4f6367..5cc35d1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [#94](https://github.com/itk-dev/devops_itksites/pull/94) + Use EasyAdmin's own components in the admin templates + - Replace hand-rolled badge and icon markup with `` and + ``, so the admin follows EasyAdmin's theming + - Drop the unused `AutoBadgeMenuItem`/`AutoBadgeCrudMenuItem` pair: EasyAdmin + hides a badge whose content is null + - Set the ITK blue with the theme API instead of overriding EasyAdmin's + colour variables one by one + - Load the admin stylesheet again: it was added as `css/admin.css`, a file + deleted in #81, so every admin page carried a 404 and no ITK styling - [#93](https://github.com/itk-dev/devops_itksites/pull/93) Update composer dependencies, clearing 15 security advisories - `api-platform/core` 4.3.7 → 4.3.17, `easycorp/easyadmin-bundle` 5.0.11 → 5.5.1, diff --git a/assets/styles/app.css b/assets/styles/app.css index 8218dc7f..4181884e 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -1,17 +1,15 @@ +/* EasyAdmin overrides. The ITK blue is set with the theme API in + DashboardController; what is left here is what that API cannot express. */ :root { --body-max-width: 100%; --sidebar-bg: #fff; - /* make the base font size smaller */ - --button-primary-bg: rgb(0, 123, 166); - --pagination-active-bg: rgb(0, 123, 166); - --link-color: rgb(0, 123, 166); - --sidebar-menu-active-item-color: rgb(0, 123, 166); - --badge-boolean-true-bg: rgb(0, 123, 166); + /* ITK red, for a false boolean badge and for danger states */ --badge-boolean-false-bg: rgb(228, 73, 48); --badge-boolean-false-color: var(--white); + --bs-danger-rgb: 228, 73, 48; + /* the theme API only takes named gray ramps, not an arbitrary gray */ --sidebar-menu-color: rgb(66, 66, 66); --text-color-dark: rgb(66, 66, 66); - --bs-danger-rgb: 228, 73, 48; } /* Grouped dropdown group styling for index pages */ diff --git a/src/Controller/Admin/DashboardController.php b/src/Controller/Admin/DashboardController.php index 7044546d..d64f2c9a 100644 --- a/src/Controller/Admin/DashboardController.php +++ b/src/Controller/Admin/DashboardController.php @@ -10,6 +10,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; +use EasyCorp\Bundle\EasyAdminBundle\Config\Theme; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; use Symfony\Component\HttpFoundation\Response; @@ -39,7 +40,12 @@ public function configureDashboard(): Dashboard return Dashboard::new() ->setTitle('ITK sites logo') ->setFaviconPath('img/favicon.ico') - ->renderContentMaximized(); + ->renderContentMaximized() + // ITK blue. Since EasyAdmin 5.4 one primary colour drives buttons, + // links, the active sidebar item and boolean badges, and the theme + // computes the text colour that sits on top of it — which the + // stylesheet used to approximate variable by variable. + ->setTheme(Theme::new()->primaryColor('#007ba6')); } #[\Override] @@ -56,7 +62,9 @@ public function configureMenuItems(): iterable yield MenuItem::section('Dependencies'); yield MenuItem::linkTo(PackageCrudController::class, 'Packages', 'fas fa-cube'); yield MenuItem::linkTo(PackageVersionCrudController::class, 'Package Versions', 'fas fa-cubes'); - yield MenuItem::linkTo(AdvisoryCrudController::class, 'Advisories', 'fas fa-skull-crossbones')->setBadge($this->advisoryRepository->count([]), 'dark'); + // `?: null` because EasyAdmin hides a badge whose content is null but + // renders a literal "0" for a zero count, which is noise on a menu item. + yield MenuItem::linkTo(AdvisoryCrudController::class, 'Advisories', 'fas fa-skull-crossbones')->setBadge($this->advisoryRepository->count([]) ?: null, 'dark'); yield MenuItem::linkTo(ModuleCrudController::class, 'Modules', 'fas fa-cube'); yield MenuItem::linkTo(ModuleVersionCrudController::class, 'Modules Versions', 'fas fa-cubes'); yield MenuItem::linkTo(DockerImageCrudController::class, 'Docker Images', 'fas fa-cube'); @@ -67,6 +75,20 @@ public function configureMenuItems(): iterable yield MenuItem::linkTo(DetectionResultCrudController::class, 'Detection Results', 'fas fa-upload'); } + /** + * The admin styles reach admin pages only from here. + * + * EasyAdmin renders its own layout rather than templates/base.html.twig, so + * neither `importmap()` nor that template's Encore tags apply to it. Until + * now this method added `css/admin.css`, a file deleted in #81, so every + * admin page carried a 404 and none of the ITK styling below it. + */ + #[\Override] + public function configureAssets(): Assets + { + return Assets::new()->addWebpackEncoreEntry('admin'); + } + #[\Override] public function configureCrud(): Crud { @@ -77,10 +99,4 @@ public function configureCrud(): Crud ->setPageTitle('detail', '%entity_label_singular%: %entity_as_string%') ; } - - #[\Override] - public function configureAssets(): Assets - { - return Assets::new()->addCssFile('css/admin.css'); - } } diff --git a/webpack.config.js b/webpack.config.js index ea5ec277..f48bb67d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -22,6 +22,10 @@ Encore */ .addEntry("easyadmin", "./assets/easyadmin.js") + // CSS-only entry, loaded by DashboardController for every admin page. The + // stylesheet is EasyAdmin-specific despite living at styles/app.css. + .addStyleEntry("admin", "./assets/styles/app.css") + // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks()