From 74d069f4bdd5d2d5c87e9cb43da07fba42ff301a Mon Sep 17 00:00:00 2001 From: buchmann Date: Tue, 7 Oct 2025 08:21:31 +0200 Subject: [PATCH] Add tags input field to action bar --- .../elements/datatables/parts_controller.js | 32 ++++++++++++---- src/Controller/PartListsController.php | 2 +- src/Controller/SelectAPIController.php | 37 +++++++++++-------- .../components/datatables.macro.html.twig | 11 ++++-- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/assets/controllers/elements/datatables/parts_controller.js b/assets/controllers/elements/datatables/parts_controller.js index 1fe11a20..5d644228 100644 --- a/assets/controllers/elements/datatables/parts_controller.js +++ b/assets/controllers/elements/datatables/parts_controller.js @@ -27,7 +27,7 @@ import * as bootbox from "bootbox"; */ export default class extends DatatablesController { - static targets = ['dt', 'selectPanel', 'selectIDs', 'selectCount', 'selectTargetPicker']; + static targets = ['dt', 'selectPanel', 'selectIDs', 'selectCount', 'selectTargetPicker', 'selectTargetPickerTags']; _confirmed = false; @@ -58,6 +58,7 @@ export default class extends DatatablesController { ).join(","); this.selectIDsTarget.value = selected_ids_string; + //updateTargetPicker(e, items); // to enable automatic update of tags that belong to the currently selected parts } updateOptions(select_element, json) @@ -67,7 +68,19 @@ export default class extends DatatablesController { //$(select_element).selectpicker('destroy'); //Retrieve the select controller instance - const select_controller = this.application.getControllerForElementAndIdentifier(select_element, 'elements--structural-entity-select'); + var select_controller; + if (false && select_element.classList.contains('tagsinput')) + { + select_controller = this.application.getControllerForElementAndIdentifier(select_element, 'elements--tagsinput'); + const selectPanel = this.selectPanelTarget; + selectPanel.querySelector('.tagsinput').classList.remove('d-none'); + } + else + { + select_controller = this.application.getControllerForElementAndIdentifier(select_element, 'elements--structural-entity-select'); + select_element.nextElementSibling.classList.remove('d-none'); + } + /** @var {TomSelect} tom_select */ const tom_select = select_controller.getTomSelect(); @@ -81,20 +94,24 @@ export default class extends DatatablesController { tom_select.setValue(json[0].value); } - select_element.nextElementSibling.classList.remove('d-none'); //$(select_element).selectpicker('show'); - + } - updateTargetPicker(event) { + updateTargetPicker(event, items) { const element = event.target; //Extract the url from the selected option const selected_option = element.options[element.options.selectedIndex]; const url = selected_option.dataset.url; - const select_target = this.selectTargetPickerTarget; + var select_target; + if (url && url.endsWith('tag')){ + select_target = this.selectTargetPickerTagsTarget; + } + else + select_target = this.selectTargetPickerTarget; if (url) { fetch(url) @@ -104,8 +121,9 @@ export default class extends DatatablesController { }); }); } else { - //Hide the select element (the tomselect button is the sibling of the select element) + //Hide the select elements (the tomselect button is the sibling of the select element) select_target.nextElementSibling.classList.add('d-none'); + this.selectPanelTarget.querySelector('.tagsinput').classList.add('d-none'); } //If the selected option has a data-turbo attribute, set it to the form diff --git a/src/Controller/PartListsController.php b/src/Controller/PartListsController.php index 171d1999..8b70f0d7 100644 --- a/src/Controller/PartListsController.php +++ b/src/Controller/PartListsController.php @@ -78,7 +78,7 @@ class PartListsController extends AbstractController $errors = []; $parts = $actionHandler->idStringToArray($ids); - $redirectResponse = $actionHandler->handleAction($action, $parts, $target ? $target : null, $redirect, $errors); + $redirectResponse = $actionHandler->handleAction($action, $parts, $target !== '' ? $target : null, $redirect, $errors); //Save changes $this->entityManager->flush(); diff --git a/src/Controller/SelectAPIController.php b/src/Controller/SelectAPIController.php index 14a3a6d2..8910b935 100644 --- a/src/Controller/SelectAPIController.php +++ b/src/Controller/SelectAPIController.php @@ -32,8 +32,8 @@ use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\StorageLocation; use App\Entity\ProjectSystem\Project; use App\Form\Type\Helper\StructuralEntityChoiceHelper; +use App\Services\Tools\TagFinder; use App\Services\Trees\NodesListBuilder; -use App\ApiPlatform\Filter\TagFilter; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; @@ -50,20 +50,6 @@ class SelectAPIController extends AbstractController { } - #[Route(path: '/tag', name: 'select_tag')] - public function tag(): Response - { - $tags = [ - 'text' => 'test', - 'value' => 'test', - ]; - $this->addEmptyNode($tags); - // pseudocode: - // for each part in selection - // use TagFilter to find tags - // dedupe - return $this->json($tags); - #[Route(path: '/category', name: 'select_category')] public function category(): Response { @@ -150,6 +136,27 @@ class SelectAPIController extends AbstractController return $this->json($nodes); } + + #[Route(path: '/tag', name: 'select_tag')] + public function getResponseForTags(EntityManagerInterface $entityManager): Response + { + $tf = new TagFinder($entityManager, ['min_keyword_length' => 2, 'query_limit' => 250]); + $list = $tf->listTags('__'); // return every tag with at least two characters! + + $entries = []; + + foreach($list as $d) + { + + //if ($entries[$d] === null) + $entries[$d['tags']] = $d['tags']; + } + + return $this->json(array_map(static fn($key, $value) => [ + 'text' => $value, + 'value' => $key, + ], array_keys($entries), $entries)); + } protected function getResponseForClass(string $class, bool $include_empty = false): Response { diff --git a/templates/components/datatables.macro.html.twig b/templates/components/datatables.macro.html.twig index d790ffe5..568cc965 100644 --- a/templates/components/datatables.macro.html.twig +++ b/templates/components/datatables.macro.html.twig @@ -41,10 +41,6 @@ {# This is left empty, as this will be filled by Javascript #} + + {# This is left empty, as this will be filled by Javascript #} +