Add sorting frontend for participants list
continuous-integration/drone/push Build is failing Details

This commit is contained in:
philipp lang 2024-12-12 03:07:10 +01:00
parent 44eb3719b9
commit b8d2b37057
8 changed files with 55 additions and 11 deletions

View File

@ -22,8 +22,8 @@ class FormUpdateMetaAction
return [ return [
'sorting' => 'array', 'sorting' => 'array',
'sorting.0' => 'required|string', 'sorting.by' => 'required|string',
'sorting.1' => 'required|string|in:asc,desc', 'sorting.direction' => 'required|boolean',
'active_columns' => 'array', 'active_columns' => 'array',
'active_columns.*' => ['string', Rule::in([...$form->getFields()->pluck('key')->toArray(), 'created_at', 'prevention'])] 'active_columns.*' => ['string', Rule::in([...$form->getFields()->pluck('key')->toArray(), 'created_at', 'prevention'])]
]; ];

View File

@ -160,7 +160,7 @@ class Form extends Model implements HasMedia
if (is_null(data_get($model->meta, 'active_columns'))) { if (is_null(data_get($model->meta, 'active_columns'))) {
$model->setAttribute('meta', [ $model->setAttribute('meta', [
'active_columns' => $model->getFields()->count() ? $model->getFields()->take(4)->pluck('key')->toArray() : null, 'active_columns' => $model->getFields()->count() ? $model->getFields()->take(4)->pluck('key')->toArray() : null,
'sorting' => $model->getFields()->count() ? [$model->getFields()->first()->key, 'asc'] : null, 'sorting' => Sorting::by('id'),
]); ]);
return; return;
} }
@ -186,6 +186,6 @@ class Form extends Model implements HasMedia
public function defaultSorting(): Sorting public function defaultSorting(): Sorting
{ {
return Sorting::by(data_get($this->meta, 'active_columns.0', 'id')); return Sorting::from($this->meta['sorting']);
} }
} }

View File

@ -2,6 +2,7 @@
use App\Form\Actions\UpdateParticipantSearchIndexAction; use App\Form\Actions\UpdateParticipantSearchIndexAction;
use App\Form\Models\Form; use App\Form\Models\Form;
use App\Lib\Sorting;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
return new class extends Migration return new class extends Migration
@ -16,6 +17,7 @@ return new class extends Migration
foreach ($form->participants as $participant) { foreach ($form->participants as $participant) {
$participant->searchable(); $participant->searchable();
} }
$form->update(['meta' => [...$form->meta, 'sorting' => Sorting::by('id')]]);
} }
} }

View File

@ -2,8 +2,8 @@
<th @click="$emit('update:model-value')"> <th @click="$emit('update:model-value')">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span v-text="label"></span> <span v-text="label"></span>
<ui-sprite v-if="value.by === column && value.direction === false" src="chevron" class="rotate-180 w-3 h-3 text-primaryfg ml-2">ASC</ui-sprite> <ui-sprite v-if="value.by === column && value.direction === false" src="chevron" class="w-3 h-3 text-primaryfg ml-2">ASC</ui-sprite>
<ui-sprite v-if="value.by === column && value.direction === true" src="chevron" class="w-3 h-3 text-primaryfg ml-2">DESC</ui-sprite> <ui-sprite v-if="value.by === column && value.direction === true" src="chevron" class="rotate-180 w-3 h-3 text-primaryfg ml-2">DESC</ui-sprite>
</div> </div>
</th> </th>
</template> </template>

View File

@ -186,6 +186,7 @@ const getSort = computed(() => innerFilter.value.sort);
async function setSort(column) { async function setSort(column) {
innerFilter.value.sort = getSort.value.by === column ? {by: column, direction: !getSort.value.direction} : {by: column, direction: false}; innerFilter.value.sort = getSort.value.by === column ? {by: column, direction: !getSort.value.direction} : {by: column, direction: false};
sortingConfig.value = innerFilter.value.sort;
} }
const activeColumnsConfig = computed({ const activeColumnsConfig = computed({
@ -200,6 +201,18 @@ const activeColumnsConfig = computed({
}, },
}); });
const sortingConfig = computed({
get: () => meta.value.form_meta.sorting,
set: async (v) => {
const response = await axios.patch(meta.value.links.update_form_meta, {
...meta.value.form_meta,
sorting: v,
});
meta.value.form_meta = response.data;
},
});
async function handleDelete() { async function handleDelete() {
await remove(deleting.value); await remove(deleting.value);
deleting.value = null; deleting.value = null;

View File

@ -80,6 +80,22 @@ it('testItShowsEmptyFilters', function () {
$this->callFilter('form.participant.index', ['data' => []], ['form' => $form])->assertJsonPath('meta.filter.data.check', ParticipantFilterScope::$nan); $this->callFilter('form.participant.index', ['data' => []], ['form' => $form])->assertJsonPath('meta.filter.data.check', ParticipantFilterScope::$nan);
}); });
it('sorts by active colums sorting by default', function () {
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->fields([
$this->checkboxField('check'),
$this->checkboxField('vorname'),
])->create();
$form->update(['meta' => ['active_columns' => [], 'sorting' => ['by' => 'vorname', 'direction' => true]]]);
sleep(2);
$this->callFilter('form.participant.index', [], ['form' => $form])
->assertOk()
->assertJsonPath('meta.filter.sort.by', 'vorname')
->assertJsonPath('meta.filter.sort.direction', true);
});
it('testItDisplaysHasNamiField', function () { it('testItDisplaysHasNamiField', function () {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->fields([$this->namiField('mitglieder')])->create(); $form = Form::factory()->fields([$this->namiField('mitglieder')])->create();

View File

@ -59,6 +59,19 @@ class FormStoreActionTest extends FormTestCase
$this->assertFrontendCacheCleared(); $this->assertFrontendCacheCleared();
} }
public function testItStoresDefaultSorting(): void
{
Event::fake([Succeeded::class]);
$this->login()->loginNami()->withoutExceptionHandling();
FormRequest::new()->fields([$this->textField()])->fake();
$this->postJson(route('form.store'))->assertOk();
$form = Form::latest()->first();
$this->assertEquals('id', $form->meta['sorting']['by']);
$this->assertFalse(false, $form->meta['sorting']['direction']);
}
public function testRegistrationDatesCanBeNull(): void public function testRegistrationDatesCanBeNull(): void
{ {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();

View File

@ -21,13 +21,13 @@ class FormUpdateMetaActionTest extends FormTestCase
$this->patchJson(route('form.update-meta', ['form' => $form]), [ $this->patchJson(route('form.update-meta', ['form' => $form]), [
'active_columns' => ['textone'], 'active_columns' => ['textone'],
'sorting' => ['textone', 'desc'], 'sorting' => ['by' => 'textone', 'direction' => false],
])->assertOk() ])->assertOk()
->assertJsonPath('active_columns.0', 'textone') ->assertJsonPath('active_columns.0', 'textone')
->assertJsonPath('sorting.1', 'desc'); ->assertJsonPath('sorting.by', 'textone');
$form = Form::latest()->first(); $form = Form::latest()->first();
$this->assertEquals(['textone', 'desc'], $form->meta['sorting']); $this->assertEquals(['by' => 'textone', 'direction' => false], $form->meta['sorting']);
$this->assertEquals(['textone'], $form->meta['active_columns']); $this->assertEquals(['textone'], $form->meta['active_columns']);
} }
@ -38,11 +38,11 @@ class FormUpdateMetaActionTest extends FormTestCase
$this->patchJson(route('form.update-meta', ['form' => $form]), [ $this->patchJson(route('form.update-meta', ['form' => $form]), [
'active_columns' => ['created_at'], 'active_columns' => ['created_at'],
'sorting' => ['created_at', 'desc'], 'sorting' => ['by' => 'textone', 'direction' => false],
])->assertOk(); ])->assertOk();
$form = Form::latest()->first(); $form = Form::latest()->first();
$this->assertEquals(['created_at', 'desc'], $form->fresh()->meta['sorting']); $this->assertEquals(['by' => 'textone', 'direction' => false], $form->fresh()->meta['sorting']);
$this->assertEquals(['created_at'], $form->fresh()->meta['active_columns']); $this->assertEquals(['created_at'], $form->fresh()->meta['active_columns']);
} }
} }