mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-24 18:58:46 +02:00
Implemented the basics for a parametric search
This commit is contained in:
parent
4d78f8d4e8
commit
9ed953d1b2
8 changed files with 253 additions and 7 deletions
|
@ -103,12 +103,20 @@ export default class extends Controller {
|
|||
}
|
||||
|
||||
deleteElement(event) {
|
||||
bootbox.confirm(this.deleteMessageValue, (result) => {
|
||||
if(result) {
|
||||
const target = event.target;
|
||||
//Remove the row element from the table
|
||||
target.closest("tr").remove();
|
||||
}
|
||||
});
|
||||
const del = () => {
|
||||
const target = event.target;
|
||||
//Remove the row element from the table
|
||||
target.closest("tr").remove();
|
||||
}
|
||||
|
||||
if(this.deleteMessageValue) {
|
||||
bootbox.confirm(this.deleteMessageValue, (result) => {
|
||||
if (result) {
|
||||
del();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
del();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\DataTables\Filters;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
trait CompoundFilterTrait
|
||||
|
@ -23,6 +24,15 @@ trait CompoundFilterTrait
|
|||
if($value instanceof FilterInterface) {
|
||||
$filters[$property->getName()] = $value;
|
||||
}
|
||||
|
||||
//Add filters in collections
|
||||
if ($value instanceof Collection) {
|
||||
foreach ($value as $key => $filter) {
|
||||
if($filter instanceof FilterInterface) {
|
||||
$filters[$property->getName() . '.' . (string) $key] = $filter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
|
|
116
src/DataTables/Filters/Constraints/Part/ParameterConstraint.php
Normal file
116
src/DataTables/Filters/Constraints/Part/ParameterConstraint.php
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace App\DataTables\Filters\Constraints\Part;
|
||||
|
||||
use App\DataTables\Filters\Constraints\AbstractConstraint;
|
||||
use App\Entity\Parameters\PartParameter;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class ParameterConstraint extends AbstractConstraint
|
||||
{
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/** @var string */
|
||||
protected $symbol;
|
||||
|
||||
/** @var string */
|
||||
protected $unit;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("parts.parameters");
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
//Create a new qb to build the subquery
|
||||
$subqb = new QueryBuilder($queryBuilder->getEntityManager());
|
||||
|
||||
//The alias has to be uniq for each subquery, so generate a random one
|
||||
$alias = uniqid('param_', false);
|
||||
|
||||
$subqb->select('COUNT(' . $alias . ')')
|
||||
->from(PartParameter::class, $alias)
|
||||
->where($alias . '.element = part');
|
||||
|
||||
if (!empty($this->name)) {
|
||||
$paramName = $this->generateParameterIdentifier('params.name');
|
||||
$subqb->andWhere($alias . '.name = :' . $paramName);
|
||||
$queryBuilder->setParameter($paramName, $this->name);
|
||||
}
|
||||
|
||||
if (!empty($this->symbol)) {
|
||||
$paramName = $this->generateParameterIdentifier('params.symbol');
|
||||
$subqb->andWhere($alias . '.symbol = :' . $paramName);
|
||||
$queryBuilder->setParameter($paramName, $this->symbol);
|
||||
}
|
||||
|
||||
if (!empty($this->unit)) {
|
||||
$paramName = $this->generateParameterIdentifier('params.unit');
|
||||
$subqb->andWhere($alias . '.unit = :' . $paramName);
|
||||
$queryBuilder->setParameter($paramName, $this->unit);
|
||||
}
|
||||
|
||||
$queryBuilder->andWhere('(' . $subqb->getDQL() . ') > 0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setName(string $name): ParameterConstraint
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $symbol
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setSymbol(string $symbol): ParameterConstraint
|
||||
{
|
||||
$this->symbol = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUnit(): string
|
||||
{
|
||||
return $this->unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unit
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setUnit(string $unit): ParameterConstraint
|
||||
{
|
||||
$this->unit = $unit;
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use App\DataTables\Filters\Constraints\DateTimeConstraint;
|
|||
use App\DataTables\Filters\Constraints\EntityConstraint;
|
||||
use App\DataTables\Filters\Constraints\IntConstraint;
|
||||
use App\DataTables\Filters\Constraints\NumberConstraint;
|
||||
use App\DataTables\Filters\Constraints\Part\ParameterConstraint;
|
||||
use App\DataTables\Filters\Constraints\Part\TagsConstraint;
|
||||
use App\DataTables\Filters\Constraints\TextConstraint;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
|
@ -18,6 +19,7 @@ use App\Entity\Parts\MeasurementUnit;
|
|||
use App\Entity\Parts\Storelocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Services\Trees\NodesListBuilder;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class PartFilter implements FilterInterface
|
||||
|
@ -112,6 +114,9 @@ class PartFilter implements FilterInterface
|
|||
/** @var TextConstraint */
|
||||
protected $attachmentName;
|
||||
|
||||
/** @var ArrayCollection<int, ParameterConstraint> */
|
||||
protected $parameters;
|
||||
|
||||
public function __construct(NodesListBuilder $nodesListBuilder)
|
||||
{
|
||||
$this->name = new TextConstraint('part.name');
|
||||
|
@ -153,6 +158,8 @@ class PartFilter implements FilterInterface
|
|||
$this->attachmentName = new TextConstraint('attachments.name');
|
||||
|
||||
$this->orderdetailsCount = new IntConstraint('COUNT(orderdetails)');
|
||||
|
||||
$this->parameters = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
|
@ -372,5 +379,14 @@ class PartFilter implements FilterInterface
|
|||
return $this->amountSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function getParameters(): ArrayCollection
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
37
src/Form/Filters/Constraints/ParameterConstraintType.php
Normal file
37
src/Form/Filters/Constraints/ParameterConstraintType.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Filters\Constraints;
|
||||
|
||||
use App\DataTables\Filters\Constraints\Part\ParameterConstraint;
|
||||
use Svg\Tag\Text;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SearchType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class ParameterConstraintType extends AbstractType
|
||||
{
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'compound' => true,
|
||||
'data_class' => ParameterConstraint::class,
|
||||
]);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->add('name', TextType::class, [
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$builder->add('unit', SearchType::class, [
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$builder->add('symbol', SearchType::class, [
|
||||
'required' => false
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -13,11 +13,13 @@ use App\Form\Filters\Constraints\BooleanConstraintType;
|
|||
use App\Form\Filters\Constraints\ChoiceConstraintType;
|
||||
use App\Form\Filters\Constraints\DateTimeConstraintType;
|
||||
use App\Form\Filters\Constraints\NumberConstraintType;
|
||||
use App\Form\Filters\Constraints\ParameterConstraintType;
|
||||
use App\Form\Filters\Constraints\StructuralEntityConstraintType;
|
||||
use App\Form\Filters\Constraints\TagsConstraintType;
|
||||
use App\Form\Filters\Constraints\TextConstraintType;
|
||||
use Svg\Tag\Text;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ResetType;
|
||||
|
@ -209,6 +211,14 @@ class PartFilterType extends AbstractType
|
|||
'label' => 'part.filter.attachmentName',
|
||||
]);
|
||||
|
||||
$builder->add('parameters', CollectionType::class, [
|
||||
'label' => 'parameter.label',
|
||||
'entry_type' => ParameterConstraintType::class,
|
||||
'allow_delete' => true,
|
||||
'allow_add' => true,
|
||||
'reindex_enable' => false,
|
||||
]);
|
||||
|
||||
$builder->add('submit', SubmitType::class, [
|
||||
'label' => 'filter.submit',
|
||||
]);
|
||||
|
|
|
@ -38,4 +38,21 @@
|
|||
|
||||
{% block choice_constraint_widget %}
|
||||
{{ block('text_constraint_widget') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block parameter_constraint_widget %}
|
||||
{% import 'components/collection_type.macro.html.twig' as collection %}
|
||||
<tr {{ stimulus_controller('pages/parameters_autocomplete', {"url": url('typeahead_parameters', {"query": "__QUERY__", "type": "part"}) }) }} >
|
||||
<td>{{ form_widget(form.name, {"attr": {"data-pages--parameters-autocomplete-target": "name"}}) }}</td>
|
||||
<td {{ stimulus_controller('pages/latex_preview') }}>{{ form_widget(form.symbol, {"attr": {"data-pages--parameters-autocomplete-target": "symbol", "data-pages--latex-preview-target": "input"}}) }}<span {{ stimulus_target('pages/latex_preview', 'preview') }}></span></td>
|
||||
<td></td>
|
||||
<td {{ stimulus_controller('pages/latex_preview') }}>{{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit", "data-pages--latex-preview-target": "input"}}) }}<span {{ stimulus_target('pages/latex_preview', 'preview') }}></span></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger btn-sm" {{ collection.delete_btn() }} title="{% trans %}orderdetail.delete{% endtrans %}">
|
||||
<i class="fas fa-trash-alt fa-fw"></i>
|
||||
</button>
|
||||
{{ form_errors(form) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endblock %}
|
|
@ -20,6 +20,9 @@
|
|||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="filter-orderdetails-tab" data-bs-toggle="tab" data-bs-target="#filter-orderdetails"><i class="fas fa-shopping-cart fa-fw"></i> {% trans %}part.edit.tab.orderdetails{% endtrans %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="filter-parameters-tab" data-bs-toggle="tab" data-bs-target="#filter-parameters"><i class="fas fa-atlas fa-fw"></i> {% trans %}part.edit.tab.specifications{% endtrans %}</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ form_start(filterForm, {"attr": {"data-controller": "helpers--form-cleanup", "data-action": "helpers--form-cleanup#submit"}}) }}
|
||||
|
@ -72,6 +75,35 @@
|
|||
{{ form_row(filterForm.orderdetailsCount) }}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane pt-3" id="filter-parameters" role="tabpanel" aria-labelledby="filter-parameters-tab" tabindex="0">
|
||||
{% import 'components/collection_type.macro.html.twig' as collection %}
|
||||
|
||||
<div {{ collection.controller(filterForm.parameters) }}>
|
||||
<table class="table table-striped table-sm" id="lots_table" {{ collection.target() }}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}specifications.property{% endtrans %}</th>
|
||||
<th>{% trans %}specifications.symbol{% endtrans %}</th>
|
||||
<th>{% trans %}specifications.value{% endtrans %}</th>
|
||||
<th>{% trans %}specifications.unit{% endtrans %}</th>
|
||||
<th>{% trans %}specifications.text{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for param in filterForm.parameters %}
|
||||
{{ form_widget(param) }}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button type="button" class="btn btn-success" {{ collection.create_btn() }}>
|
||||
<i class="fas fa-plus-square fa-fw"></i>
|
||||
{% trans %}part_lot.create{% endtrans %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue