From eddd12df06c5e23b05bd321b2bfbb55e282c9a1b Mon Sep 17 00:00:00 2001 From: Kai Dederichs Date: Wed, 15 Jan 2025 17:06:16 +0100 Subject: [PATCH] feat: allow user to attach actions to properties in details --- assets/css/easyadmin-theme/detail-page.css | 5 +++++ src/Config/Actions.php | 10 +++++++--- src/Dto/ActionDto.php | 11 +++++++++++ src/Dto/FieldDto.php | 12 ++++++++++++ src/Factory/ActionFactory.php | 13 ++++++++++++- templates/crud/detail.html.twig | 14 ++++++++++++-- 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/assets/css/easyadmin-theme/detail-page.css b/assets/css/easyadmin-theme/detail-page.css index 6ba4549c51..e3f98b55b4 100644 --- a/assets/css/easyadmin-theme/detail-page.css +++ b/assets/css/easyadmin-theme/detail-page.css @@ -52,6 +52,11 @@ min-inline-size: 66%; } +.ea-detail .field-group .field-actions { + flex: 1; + min-inline-size: 66%; +} + .ea-detail .field-group.field-textarea .field-value, .ea-detail .field-group.field-text_editor .field-value { max-block-size: 350px; diff --git a/src/Config/Actions.php b/src/Config/Actions.php index a91ab961b8..a49b004a70 100644 --- a/src/Config/Actions.php +++ b/src/Config/Actions.php @@ -25,9 +25,9 @@ public static function new(): self return new self($dto); } - public function add(string $pageName, Action|string $actionNameOrObject): self + public function add(string $pageName, Action|string $actionNameOrObject, ?string $property = null): self { - return $this->doAddAction($pageName, $actionNameOrObject); + return $this->doAddAction($pageName, $actionNameOrObject, false, $property); } public function addBatchAction(Action|string $actionNameOrObject): self @@ -220,7 +220,7 @@ private function createBuiltInAction(string $pageName, string $actionName): Acti throw new \InvalidArgumentException(sprintf('The "%s" action is not a built-in action, so you can\'t add or configure it via its name. Either refer to one of the built-in actions or create a custom action called "%s".', $actionName, $actionName)); } - private function doAddAction(string $pageName, Action|string $actionNameOrObject, bool $isBatchAction = false): self + private function doAddAction(string $pageName, Action|string $actionNameOrObject, bool $isBatchAction = false, ?string $property = null): self { $actionName = \is_string($actionNameOrObject) ? $actionNameOrObject : (string) $actionNameOrObject; $action = \is_string($actionNameOrObject) ? $this->createBuiltInAction($pageName, $actionNameOrObject) : $actionNameOrObject; @@ -234,6 +234,10 @@ private function doAddAction(string $pageName, Action|string $actionNameOrObject $actionDto->setType(Action::TYPE_BATCH); } + if (Crud::PAGE_DETAIL === $pageName) { + $actionDto->setProperty($property); + } + if (Crud::PAGE_INDEX === $pageName && Action::DELETE === $actionName) { $this->dto->prependAction($pageName, $actionDto); } else { diff --git a/src/Dto/ActionDto.php b/src/Dto/ActionDto.php index e4c026463b..2efa7efcbb 100644 --- a/src/Dto/ActionDto.php +++ b/src/Dto/ActionDto.php @@ -28,6 +28,7 @@ final class ActionDto private $url; private array $translationParameters = []; private $displayCallable; + private ?string $property = null; public function getType(): string { @@ -311,4 +312,14 @@ public function getAsConfigObject(): Action return $action; } + + public function getProperty(): ?string + { + return $this->property; + } + + public function setProperty(?string $property): void + { + $this->property = $property; + } } diff --git a/src/Dto/FieldDto.php b/src/Dto/FieldDto.php index 70417d5c3d..60b086d613 100644 --- a/src/Dto/FieldDto.php +++ b/src/Dto/FieldDto.php @@ -2,6 +2,7 @@ namespace EasyCorp\Bundle\EasyAdminBundle\Dto; +use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore; use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaFormFieldsetType; @@ -56,6 +57,7 @@ final class FieldDto private $uniqueId; private KeyValueStore $displayedOn; private array $htmlAttributes = []; + private ?ActionCollection $actions = null; public function __construct() { @@ -517,4 +519,14 @@ public function setHtmlAttribute(string $attribute, mixed $value): self return $this; } + + public function getActions(): ?ActionCollection + { + return $this->actions; + } + + public function setActions(?ActionCollection $actions): void + { + $this->actions = $actions; + } } diff --git a/src/Factory/ActionFactory.php b/src/Factory/ActionFactory.php index aa6cc298a8..3bd376920c 100644 --- a/src/Factory/ActionFactory.php +++ b/src/Factory/ActionFactory.php @@ -36,6 +36,7 @@ public function processEntityActions(EntityDto $entityDto, ActionConfigDto $acti { $currentPage = $this->adminContextProvider->getContext()->getCrud()->getCurrentPage(); $entityActions = []; + $propertyActions = []; foreach ($actionsDto->getActions()->all() as $actionDto) { if (!$actionDto->isEntityAction()) { continue; @@ -65,10 +66,20 @@ public function processEntityActions(EntityDto $entityDto, ActionConfigDto $acti $actionDto->setCssClass($actionDto->getCssClass().' '.$addedCssClass); } - $entityActions[$actionDto->getName()] = $this->processAction($currentPage, $actionDto, $entityDto); + if (!$actionDto->getProperty()) { + $entityActions[$actionDto->getName()] = $this->processAction($currentPage, $actionDto, $entityDto); + } else { + if (!isset($propertyActions[$actionDto->getProperty()])) { + $propertyActions[$actionDto->getProperty()] = []; + } + $propertyActions[$actionDto->getProperty()][$actionDto->getName()] = $this->processAction($currentPage, $actionDto, $entityDto); + } } $entityDto->setActions(ActionCollection::new($entityActions)); + foreach ($propertyActions as $property => $actions) { + $entityDto->getFields()->getByProperty($property)?->setActions(ActionCollection::new($actions)); + } } public function processGlobalActions(?ActionConfigDto $actionsDto = null): ActionCollection diff --git a/templates/crud/detail.html.twig b/templates/crud/detail.html.twig index 896819f593..d75281d1d1 100644 --- a/templates/crud/detail.html.twig +++ b/templates/crud/detail.html.twig @@ -83,8 +83,18 @@ {% endif %} -
- {{ include(field.templatePath, { field: field, entity: entity }, with_context = false) }} +
+
+ {{ include(field.templatePath, { field: field, entity: entity }, with_context = false) }} +
+ + {% if field.actions is not null %} +
+ {% for action in field.actions %} + {{ include(action.templatePath, { action: action }, with_context = false) }} + {% endfor %} +
+ {% endif %}
{% endmacro %}