Add sorting to participant list
continuous-integration/drone/push Build was killed Details

This commit is contained in:
philipp lang 2024-12-12 01:26:22 +01:00
parent 70e085a49e
commit a3ecfa756d
6 changed files with 83 additions and 3 deletions

View File

@ -20,7 +20,7 @@ class UpdateParticipantSearchIndexAction
[ [
'filterableAttributes' => [...$form->getFields()->filterables()->getKeys(), 'parent-id'], 'filterableAttributes' => [...$form->getFields()->filterables()->getKeys(), 'parent-id'],
'searchableAttributes' => $form->getFields()->searchables()->getKeys(), 'searchableAttributes' => $form->getFields()->searchables()->getKeys(),
'sortableAttributes' => [], 'sortableAttributes' => $form->getFields()->sortables()->getKeys(),
'displayedAttributes' => [...$form->getFields()->filterables()->getKeys(), ...$form->getFields()->searchables()->getKeys(), 'id'], 'displayedAttributes' => [...$form->getFields()->filterables()->getKeys(), ...$form->getFields()->searchables()->getKeys(), 'id'],
'pagination' => [ 'pagination' => [
'maxTotalHits' => 1000000, 'maxTotalHits' => 1000000,

View File

@ -124,6 +124,11 @@ class FieldCollection extends Collection
return $this; return $this;
} }
public function sortables(): self
{
return $this;
}
public function filterables(): self public function filterables(): self
{ {
return $this->filter(fn ($field) => $field instanceof Filterable); return $this->filter(fn ($field) => $field instanceof Filterable);

View File

@ -8,6 +8,7 @@ use App\Form\Data\FieldCollection;
use App\Form\Data\FormConfigData; use App\Form\Data\FormConfigData;
use App\Lib\Editor\Condition; use App\Lib\Editor\Condition;
use App\Lib\Editor\EditorData; use App\Lib\Editor\EditorData;
use App\Lib\Sorting;
use Cviebrock\EloquentSluggable\Sluggable; use Cviebrock\EloquentSluggable\Sluggable;
use Database\Factories\Form\Models\FormFactory; use Database\Factories\Form\Models\FormFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -182,4 +183,9 @@ class Form extends Model implements HasMedia
{ {
return config('scout.prefix') . 'forms_' . $this->id . '_participants'; return config('scout.prefix') . 'forms_' . $this->id . '_participants';
} }
public function defaultSorting(): Sorting
{
return Sorting::by(data_get($this->meta, 'active_columns.0'));
}
} }

View File

@ -4,8 +4,8 @@ namespace App\Form\Scopes;
use App\Form\Models\Form; use App\Form\Models\Form;
use App\Form\Models\Participant; use App\Form\Models\Participant;
use App\Lib\Filter;
use App\Lib\ScoutFilter; use App\Lib\ScoutFilter;
use App\Lib\Sorting;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Laravel\Scout\Builder; use Laravel\Scout\Builder;
use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapInputName;
@ -31,7 +31,8 @@ class ParticipantFilterScope extends ScoutFilter
public array $data = [], public array $data = [],
public string $search = '', public string $search = '',
public array $options = [], public array $options = [],
public ?int $parent = null public ?int $parent = null,
public ?Sorting $sort = null
) { ) {
} }
@ -59,6 +60,8 @@ class ParticipantFilterScope extends ScoutFilter
$options['filter'] = $filter->map(fn ($expression) => "($expression)")->implode(' AND '); $options['filter'] = $filter->map(fn ($expression) => "($expression)")->implode(' AND ');
$options['sort'] = $this->sort->toMeilisearch();
return $engine->search($query, [...$this->options, ...$options]); return $engine->search($query, [...$this->options, ...$options]);
})->within($this->form->participantsSearchableAs()); })->within($this->form->participantsSearchableAs());
} }
@ -67,6 +70,10 @@ class ParticipantFilterScope extends ScoutFilter
{ {
$this->form = $form; $this->form = $form;
if (is_null($this->sort)) {
$this->sort = $this->form->defaultSorting();
}
foreach ($form->getFields() as $field) { foreach ($form->getFields() as $field) {
if (!Arr::has($this->data, $field->key)) { if (!Arr::has($this->data, $field->key)) {
data_set($this->data, $field->key, static::$nan); data_set($this->data, $field->key, static::$nan);

25
app/Lib/Sorting.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace App\Lib;
use Spatie\LaravelData\Data;
class Sorting extends Data
{
public static function by(string $by): self
{
return static::factory()->withoutMagicalCreation()->from(['by' => $by]);
}
public function __construct(public string $by, public bool $direction = false)
{
}
/**
* @return array<int, string>
*/
public function toMeilisearch(): array
{
return [$this->by . ':' . ($this->direction ? 'desc' : 'asc')];
}
}

View File

@ -239,3 +239,40 @@ it('testItShowsPreventionState', function () {
->assertJsonPath('data.0.prevention_items.0.value', false) ->assertJsonPath('data.0.prevention_items.0.value', false)
->assertJsonPath('data.0.prevention_items.0.tooltip', 'erweitertes Führungszeugnis nicht vorhanden'); ->assertJsonPath('data.0.prevention_items.0.tooltip', 'erweitertes Führungszeugnis nicht vorhanden');
}); });
it('test it orders participants by value', function (array $values, array $sorting, array $expected) {
list($key, $direction) = $sorting;
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()
->fields([
$this->textField('vorname')->name('Vorname'),
$this->checkboxesField('select')->options(['Wölflinge', 'Pfadfinder']),
]);
foreach ($values as $value) {
$form = $form->has(Participant::factory()->data(['vorname' => 'Max', 'select' => 'Pfadfinder', $key => $value]));
}
$form = $form->create();
sleep(2);
$response = $this->callFilter('form.participant.index', ['sort' => ['by' => $key, 'direction' => $direction]], ['form' => $form]);
foreach ($expected as $index => $value) {
$response->assertJsonPath("data.{$index}.{$key}", $value);
}
})->with([
[
['Anna', 'Sarah', 'Ben'],
['vorname', false],
['Anna', 'Ben', 'Sarah'],
],
[
['Anna', 'Sarah', 'Ben'],
['vorname', true],
['Sarah', 'Ben', 'Anna'],
],
[
['Wölflinge', 'Pfadfinder'],
['select', false],
['Pfadfinder', 'Wölflinge'],
]
]);