Implement a user friendly part select element.

This commit is contained in:
Jan Böhmer 2022-12-24 14:04:46 +01:00
parent c78bc01d23
commit 670dd76ef5
5 changed files with 175 additions and 3 deletions

View file

@ -32,10 +32,12 @@ use App\Entity\Parameters\MeasurementUnitParameter;
use App\Entity\Parameters\PartParameter;
use App\Entity\Parameters\StorelocationParameter;
use App\Entity\Parameters\SupplierParameter;
use App\Entity\Parts\Part;
use App\Entity\PriceInformations\Currency;
use App\Repository\ParameterRepository;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\Attachments\BuiltinAttachmentsFinder;
use App\Services\Attachments\PartPreviewGenerator;
use App\Services\Tools\TagFinder;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -128,6 +130,45 @@ class TypeaheadController extends AbstractController
}
}
/**
* @Route("/parts/search/{query}", name="typeahead_parts")
* @param string $query
* @param EntityManagerInterface $entityManager
* @return JsonResponse
*/
public function parts(string $query, EntityManagerInterface $entityManager, PartPreviewGenerator $previewGenerator,
AttachmentURLGenerator $attachmentURLGenerator): JsonResponse
{
$this->denyAccessUnlessGranted('@parts.read');
$repo = $entityManager->getRepository(Part::class);
$parts = $repo->autocompleteSearch($query);
$data = [];
foreach ($parts as $part) {
//Determine the picture to show:
$preview_attachment = $previewGenerator->getTablePreviewAttachment($part);
if($preview_attachment !== null) {
$preview_url = $attachmentURLGenerator->getThumbnailURL($preview_attachment, 'thumbnail_sm');
} else {
$preview_url = '';
}
/** @var Part $part */
$data[] = [
'id' => $part->getID(),
'name' => $part->getName(),
'category' => $part->getCategory() ? $part->getCategory()->getName() : 'Unknown',
'footprint' => $part->getFootprint() ? $part->getFootprint()->getName() : '',
'description' => mb_strimwidth($part->getDescription(), 0, 127, '...'),
'image' => $preview_url,
];
}
return new JsonResponse($data);
}
/**
* @Route("/parameters/{type}/search/{query}", name="typeahead_parameters", requirements={"type" = ".+"})
* @param string $query

View file

@ -4,6 +4,7 @@ namespace App\Form\ProjectSystem;
use App\Entity\Parts\Part;
use App\Entity\ProjectSystem\ProjectBOMEntry;
use App\Form\Type\PartSelectType;
use Svg\Tag\Text;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
@ -23,9 +24,7 @@ class ProjectBOMEntryType extends AbstractType
'label' => 'project.bom.quantity',
])
->add('part', EntityType::class, [
'class' => Part::class,
'choice_label' => 'name',
->add('part', PartSelectType::class, [
'required' => false,
])

View file

@ -0,0 +1,54 @@
<?php
namespace App\Form\Type;
use App\Entity\Parts\Part;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\ChoiceList;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class PartSelectType extends AbstractType
{
private UrlGeneratorInterface $urlGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => Part::class,
'choice_label' => 'name',
'placeholder' => 'None'
]);
$resolver->setDefaults([
'attr' => [
'data-controller' => 'elements--part-select',
'data-autocomplete' => $this->urlGenerator->generate('typeahead_parts', ['query' => '__QUERY__']),
//Disable browser autocomplete
'autocomplete' => 'off',
],
]);
$resolver->setDefaults(['choices' => []]);
$resolver->setDefaults([
'choice_attr' => ChoiceList::attr($this, function (?Part $part) {
return $part ? [
//'data-description' => $part->getDescription(),
//'data-category' => $part->getCategory() ? $part->getCategory()->getName() : '',
] : [];
})
]);
}
public function getParent()
{
return EntityType::class;
}
}

View file

@ -66,4 +66,24 @@ class PartRepository extends NamedDBElementRepository
return (int) ($query->getSingleScalarResult() ?? 0);
}
public function autocompleteSearch(string $query, int $max_limits = 50): array
{
$qb = $this->createQueryBuilder('part');
$qb->select('part')
->leftJoin('part.category', 'category')
->where('part.name LIKE :query')
->orWhere('part.description LIKE :query')
->orWhere('category.name LIKE :query')
;
$qb->setParameter('query', '%'.$query.'%');
$qb->setMaxResults($max_limits);
$qb->orderBy('part.name', 'ASC');
return $qb->getQuery()->getResult();
}
}