From c7aa730bc380026e15aaa72ee19de649d0ed573a Mon Sep 17 00:00:00 2001 From: Marcel Diegelmann Date: Thu, 3 Jul 2025 13:38:51 +0200 Subject: [PATCH] =?UTF-8?q?Baugruppen=20St=C3=BCckliste=20um=20referenzier?= =?UTF-8?q?te=20Baugruppe=20erweitern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/services.yaml | 7 +- src/Form/Type/AssemblySelectType.php | 124 ++++++++++++++++++ src/Repository/AssemblyRepository.php | 69 ++++++++++ .../Attachments/AssemblyPreviewGenerator.php | 93 +++++++++++++ templates/assemblies/info/info.html.twig | 2 +- translations/messages.cs.xlf | 18 ++- translations/messages.da.xlf | 6 - translations/messages.el.xlf | 32 ++++- translations/messages.en.xlf | 6 - translations/messages.es.xlf | 6 - translations/messages.it.xlf | 6 - translations/messages.pl.xlf | 6 - translations/messages.ru.xlf | 18 --- translations/messages.zh.xlf | 6 - translations/validators.da.xlf | 6 - translations/validators.de.xlf | 6 - translations/validators.en.xlf | 7 - translations/validators.hr.xlf | 6 - translations/validators.it.xlf | 6 - translations/validators.pl.xlf | 6 - translations/validators.ru.xlf | 6 - translations/validators.zh.xlf | 6 - 22 files changed, 332 insertions(+), 116 deletions(-) create mode 100644 src/Form/Type/AssemblySelectType.php create mode 100644 src/Repository/AssemblyRepository.php create mode 100644 src/Services/Attachments/AssemblyPreviewGenerator.php diff --git a/config/services.yaml b/config/services.yaml index 132c787d..c119d1ef 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -183,9 +183,12 @@ services: App\DataTables\Helpers\ColumnSortHelper: shared: false # Service has a state so not share it between different tables + App\DataTables\AssemblyDataTable: + arguments: + $visible_columns: '%partdb.table.assemblies.default_columns%' App\DataTables\AssemblyBomEntriesDataTable: - arguments: - $visible_columns: '%partdb.table.assemblies.default_columns%' + arguments: + $visible_columns: '%partdb.table.assemblies_bom.default_columns%' #################################################################################################################### # Label system diff --git a/src/Form/Type/AssemblySelectType.php b/src/Form/Type/AssemblySelectType.php new file mode 100644 index 00000000..10e858f2 --- /dev/null +++ b/src/Form/Type/AssemblySelectType.php @@ -0,0 +1,124 @@ +addEventListener(FormEvents::PRE_SET_DATA, function (PreSetDataEvent $event) { + $form = $event->getForm(); + $config = $form->getConfig()->getOptions(); + $data = $event->getData() ?? []; + + $config['compound'] = false; + $config['choices'] = is_iterable($data) ? $data : [$data]; + $config['error_bubbling'] = true; + + $form->add('autocomplete', EntityType::class, $config); + }); + + //After form submit, we have to add the selected element as choice, otherwise the form will not accept this element + $builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) { + $data = $event->getData(); + $form = $event->getForm(); + $options = $form->get('autocomplete')->getConfig()->getOptions(); + + + if (!isset($data['autocomplete']) || '' === $data['autocomplete'] || empty($data['autocomplete'])) { + $options['choices'] = []; + } else { + //Extract the ID from the submitted data + $id = $data['autocomplete']; + //Find the element in the database + $element = $this->em->find($options['class'], $id); + + //Add the element as choice + $options['choices'] = [$element]; + $options['error_bubbling'] = true; + $form->add('autocomplete', EntityType::class, $options); + } + }); + + $builder->setDataMapper($this); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'class' => Assembly::class, + 'choice_label' => 'name', + 'compound' => true, + 'error_bubbling' => false, + ]); + + error_log($this->urlGenerator->generate('typeahead_assemblies', ['query' => '__QUERY__'])); + + $resolver->setDefaults([ + 'attr' => [ + 'data-controller' => 'elements--assembly-select', + 'data-autocomplete' => $this->urlGenerator->generate('typeahead_assemblies', ['query' => '__QUERY__']), + 'autocomplete' => 'off', + ], + ]); + + $resolver->setDefaults([ + //Prefill the selected choice with the needed data, so the user can see it without an additional Ajax request + 'choice_attr' => ChoiceList::attr($this, function (?Assembly $assembly) { + if($assembly instanceof Assembly) { + //Determine the picture to show: + $preview_attachment = $this->previewGenerator->getTablePreviewAttachment($assembly); + if ($preview_attachment instanceof Attachment) { + $preview_url = $this->attachmentURLGenerator->getThumbnailURL($preview_attachment, + 'thumbnail_sm'); + } else { + $preview_url = ''; + } + } + + return $assembly instanceof Assembly ? [ + 'data-description' => $assembly->getDescription() ? mb_strimwidth($assembly->getDescription(), 0, 127, '...') : '', + 'data-category' => '', + 'data-footprint' => '', + 'data-image' => $preview_url, + ] : []; + }) + ]); + } + + public function mapDataToForms($data, \Traversable $forms): void + { + $form = current(iterator_to_array($forms, false)); + $form->setData($data); + } + + public function mapFormsToData(\Traversable $forms, &$data): void + { + $form = current(iterator_to_array($forms, false)); + $data = $form->getData(); + } + +} diff --git a/src/Repository/AssemblyRepository.php b/src/Repository/AssemblyRepository.php new file mode 100644 index 00000000..031e6e82 --- /dev/null +++ b/src/Repository/AssemblyRepository.php @@ -0,0 +1,69 @@ +. + */ + +declare(strict_types=1); + +/** + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace App\Repository; + +use App\Entity\AssemblySystem\Assembly; + +/** + * @template TEntityClass of Assembly + * @extends DBElementRepository + */ +class AssemblyRepository extends StructuralDBElementRepository +{ + /** + * @return Assembly[] + */ + public function autocompleteSearch(string $query, int $max_limits = 50): array + { + $qb = $this->createQueryBuilder('assembly'); + $qb->select('assembly') + ->where('ILIKE(assembly.name, :query) = TRUE') + ->orWhere('ILIKE(assembly.description, :query) = TRUE'); + + $qb->setParameter('query', '%'.$query.'%'); + + $qb->setMaxResults($max_limits); + $qb->orderBy('NATSORT(assembly.name)', 'ASC'); + + return $qb->getQuery()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Attachments/AssemblyPreviewGenerator.php b/src/Services/Attachments/AssemblyPreviewGenerator.php new file mode 100644 index 00000000..9ecbbd07 --- /dev/null +++ b/src/Services/Attachments/AssemblyPreviewGenerator.php @@ -0,0 +1,93 @@ +. + */ + +declare(strict_types=1); + +namespace App\Services\Attachments; + +use App\Entity\AssemblySystem\Assembly; +use App\Entity\Attachments\Attachment; + +class AssemblyPreviewGenerator +{ + public function __construct(protected AttachmentManager $attachmentHelper) + { + } + + /** + * Returns a list of attachments that can be used for previewing the assembly ordered by priority. + * + * @param Assembly $assembly the assembly for which the attachments should be determined + * + * @return (Attachment|null)[] + * + * @psalm-return list + */ + public function getPreviewAttachments(Assembly $assembly): array + { + $list = []; + + //Master attachment has top priority + $attachment = $assembly->getMasterPictureAttachment(); + if ($this->isAttachmentValidPicture($attachment)) { + $list[] = $attachment; + } + + //Then comes the other images of the assembly + foreach ($assembly->getAttachments() as $attachment) { + //Dont show the master attachment twice + if ($this->isAttachmentValidPicture($attachment) && $attachment !== $assembly->getMasterPictureAttachment()) { + $list[] = $attachment; + } + } + + return $list; + } + + /** + * Determines what attachment should be used for previewing a assembly (especially in assembly table). + * The returned attachment is guaranteed to be existing and be a picture. + * + * @param Assembly $assembly The assembly for which the attachment should be determined + */ + public function getTablePreviewAttachment(Assembly $assembly): ?Attachment + { + $attachment = $assembly->getMasterPictureAttachment(); + if ($this->isAttachmentValidPicture($attachment)) { + return $attachment; + } + + return null; + } + + /** + * Checks if a attachment is exising and a valid picture. + * + * @param Attachment|null $attachment the attachment that should be checked + * + * @return bool true if the attachment is valid + */ + protected function isAttachmentValidPicture(?Attachment $attachment): bool + { + return $attachment instanceof Attachment + && $attachment->isPicture() + && $this->attachmentHelper->isFileExisting($attachment); + } +} diff --git a/templates/assemblies/info/info.html.twig b/templates/assemblies/info/info.html.twig index 2ef6cf25..dbda5f7e 100644 --- a/templates/assemblies/info/info.html.twig +++ b/templates/assemblies/info/info.html.twig @@ -135,7 +135,7 @@ {% include "assemblies/info/_builds.html.twig" %}
- {% include "assemblies/info/_attachments_info.html.twig" with {"part": assembly} %} + {% include "assemblies/info/_attachments_info.html.twig" with {"assembly": assembly} %}
{% for name, parameters in assembly.groupedParameters %} diff --git a/translations/messages.cs.xlf b/translations/messages.cs.xlf index 16fb09a9..c437de98 100644 --- a/translations/messages.cs.xlf +++ b/translations/messages.cs.xlf @@ -9996,12 +9996,6 @@ Element 3 Interní číslo dílu (IPN) - - - assembly.edit.ipn - Interní číslo dílu (IPN) - - assembly.status.draft @@ -13612,6 +13606,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz Sestavy + + + assembly.referencedAssembly.labelp + Odkazované sestavy + + assembly.edit @@ -13780,6 +13780,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz Sestavit + + + assembly.build.form.referencedAssembly + Sestava "%name%" + + assembly.builds.no_stocked_builds diff --git a/translations/messages.da.xlf b/translations/messages.da.xlf index cade27c6..cee4f08c 100644 --- a/translations/messages.da.xlf +++ b/translations/messages.da.xlf @@ -10010,12 +10010,6 @@ Element 3 Internt Partnummer (IPN) - - - assembly.edit.ipn - Internt Partnummer (IPN) - - assembly.status.draft diff --git a/translations/messages.el.xlf b/translations/messages.el.xlf index 08fb7df8..7d345fbd 100644 --- a/translations/messages.el.xlf +++ b/translations/messages.el.xlf @@ -2620,6 +2620,12 @@ %value% (Μέρος) + + + part.table.name.value.for_assembly + %value% (Συναρμολόγηση) + + part.table.name.value.for_project @@ -2629,7 +2635,7 @@ assembly.edit.status - Κατάσταση + Κατάσταση συναρμολόγησης @@ -2692,6 +2698,12 @@ Συναρμολογήσεις + + + assembly.referencedAssembly.labelp + Αναφερόμενες συναρμολογήσεις + + assembly.edit @@ -2860,6 +2872,12 @@ Κατασκευή + + + assembly.build.form.referencedAssembly + Συναρμολόγηση "%name%" + + assembly.builds.no_stocked_builds @@ -2914,6 +2932,12 @@ έργο + + + assembly.bom.referencedAssembly + Συναρμολόγηση + + assembly.bom.name @@ -2950,10 +2974,10 @@ Εισαγωγή εξαρτημάτων συναρμολόγησης - + - assembly.bom.partOrProject - Εξάρτημα + assembly.bom.partOrAssembly + Μέρος ή συναρμολόγηση diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 57114e16..e541313b 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -10089,12 +10089,6 @@ Element 1 -> Element 1.2 Internal Part Number (IPN) - - - assembly.edit.ipn - Internal Part Number (IPN) - - assembly.status.draft diff --git a/translations/messages.es.xlf b/translations/messages.es.xlf index 50047268..999fd71a 100644 --- a/translations/messages.es.xlf +++ b/translations/messages.es.xlf @@ -10020,12 +10020,6 @@ Elemento 3 Número de Componente Interno (IPN) - - - assembly.edit.ipn - Número de Componente Interno (IPN) - - assembly.status.draft diff --git a/translations/messages.it.xlf b/translations/messages.it.xlf index 89c69f83..951a1bd3 100644 --- a/translations/messages.it.xlf +++ b/translations/messages.it.xlf @@ -10022,12 +10022,6 @@ Element 3 Codice interno (IPN) - - - assembly.edit.ipn - Codice interno (IPN) - - assembly.status.draft diff --git a/translations/messages.pl.xlf b/translations/messages.pl.xlf index 21ad869b..d9d4eac2 100644 --- a/translations/messages.pl.xlf +++ b/translations/messages.pl.xlf @@ -10025,12 +10025,6 @@ Element 3 Internal Part Number (IPN) - - - assembly.edit.ipn - Internal Part Number (IPN) - - assembly.status.draft diff --git a/translations/messages.ru.xlf b/translations/messages.ru.xlf index 5c4757f7..7ede4235 100644 --- a/translations/messages.ru.xlf +++ b/translations/messages.ru.xlf @@ -10029,12 +10029,6 @@ Внутренний номер компонента (IPN) - - - assembly.edit.ipn - Внутренний номер компонента (IPN) - - assembly.status.draft @@ -13116,18 +13110,6 @@ Проект - - - part.info.add_part_to_assembly - Добавить эту часть в сборку - - - - - assembly.bom.project - Проект - - assembly.bom.referencedAssembly diff --git a/translations/messages.zh.xlf b/translations/messages.zh.xlf index 08cae400..a3e44de6 100644 --- a/translations/messages.zh.xlf +++ b/translations/messages.zh.xlf @@ -10028,12 +10028,6 @@ Element 3 内部零件号 (IPN) - - - assembly.edit.ipn - 内部零件号 (IPN) - - assembly.status.draft diff --git a/translations/validators.da.xlf b/translations/validators.da.xlf index bf4125fe..f30dd211 100644 --- a/translations/validators.da.xlf +++ b/translations/validators.da.xlf @@ -251,12 +251,6 @@ Du skal vælge en komponent eller angive et navn til en ikke-komponent styklistepost! - - - validator.project.bom_entry.only_part_or_assembly_allowed - Det er kun tilladt at vælge én del eller en samling. Venligst tilpas dit valg! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.de.xlf b/translations/validators.de.xlf index fec52c8e..8e6d7f02 100644 --- a/translations/validators.de.xlf +++ b/translations/validators.de.xlf @@ -251,12 +251,6 @@ Sie müssen ein Bauteil bzw. eine Baugruppe auswählen, oder einen Namen für ein nicht-Bauteil BOM-Eintrag setzen! - - - validator.project.bom_entry.only_part_or_assembly_allowed - Es darf nur ein Bauteil oder eine Baugruppe ausgewählt werden. Bitte passen Sie Ihre Auswahl an! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.en.xlf b/translations/validators.en.xlf index 08d3f2df..8bc34a33 100644 --- a/translations/validators.en.xlf +++ b/translations/validators.en.xlf @@ -251,12 +251,6 @@ You have to select a part or assembly, or set a name for a non-component Bom entry! - - - validator.project.bom_entry.only_part_or_assembly_allowed - Only one part or assembly may be selected. Please modify your selection! - - project.bom_entry.name_already_in_bom @@ -429,7 +423,6 @@ validator.assembly.bom_entry.name_or_part_needed You must select a part or set a name for the entry! - You must select a part or set a name for the entry! diff --git a/translations/validators.hr.xlf b/translations/validators.hr.xlf index c14b86f1..485cb0e2 100644 --- a/translations/validators.hr.xlf +++ b/translations/validators.hr.xlf @@ -251,12 +251,6 @@ Morate odabrati dio za unos u BOM ili postaviti naziv za unos koji nije dio. - - - validator.project.bom_entry.only_part_or_assembly_allowed - Dozvoljeno je odabrati samo jednu komponentu ili sklop. Molimo prilagodite svoj odabir! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.it.xlf b/translations/validators.it.xlf index 7f88537c..74d3969f 100644 --- a/translations/validators.it.xlf +++ b/translations/validators.it.xlf @@ -251,12 +251,6 @@ È necessario selezionare un componente o assegnare un nome ad una voce BOM che non indica un componente! - - - validator.project.bom_entry.only_part_or_assembly_allowed - È consentito selezionare solo una parte o un assieme. Si prega di modificare la selezione! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.pl.xlf b/translations/validators.pl.xlf index 060de0e1..9916178c 100644 --- a/translations/validators.pl.xlf +++ b/translations/validators.pl.xlf @@ -251,12 +251,6 @@ Należy wybrać część dla wpisu BOM części lub ustawić nazwę dla wpisu BOM niebędącego częścią. - - - validator.project.bom_entry.only_part_or_assembly_allowed - Można wybrać tylko jedną część lub zespół. Proszę dostosować swój wybór! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.ru.xlf b/translations/validators.ru.xlf index e4a3199f..b8029e47 100644 --- a/translations/validators.ru.xlf +++ b/translations/validators.ru.xlf @@ -251,12 +251,6 @@ Вам необходимо выбрать компонент или задать имя для BOM, не относящейся к компоненту! - - - validator.project.bom_entry.only_part_or_assembly_allowed - Можно выбрать только деталь или сборку. Пожалуйста, измените ваш выбор! - - project.bom_entry.name_already_in_bom diff --git a/translations/validators.zh.xlf b/translations/validators.zh.xlf index 1844351e..6e4fc056 100644 --- a/translations/validators.zh.xlf +++ b/translations/validators.zh.xlf @@ -251,12 +251,6 @@ 您必须为 BOM 条目选择部件,或为非部件 BOM 条目设置名称。 - - - validator.project.bom_entry.only_part_or_assembly_allowed - 只能选择一个零件或组件。请修改您的选择! - - project.bom_entry.name_already_in_bom