diff --git a/resources/js/components/forms/SubmissionListing.vue b/resources/js/components/forms/SubmissionListing.vue index 6ace7860c0..b75d4c5eb8 100644 --- a/resources/js/components/forms/SubmissionListing.vue +++ b/resources/js/components/forms/SubmissionListing.vue @@ -5,8 +5,6 @@ - -
-
- - +
+ + + + +
+
+ +
diff --git a/src/Facades/FormSubmission.php b/src/Facades/FormSubmission.php index f3fcef7af1..8b24412fc0 100644 --- a/src/Facades/FormSubmission.php +++ b/src/Facades/FormSubmission.php @@ -5,8 +5,8 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Facade; use Statamic\Contracts\Forms\Submission as SubmissionContract; +use Statamic\Contracts\Forms\SubmissionQueryBuilder; use Statamic\Contracts\Forms\SubmissionRepository; -use Statamic\Stache\Query\SubmissionQueryBuilder; /** * @method static Collection all() diff --git a/src/Forms/Form.php b/src/Forms/Form.php index 37e24803c9..d504b69174 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -7,6 +7,7 @@ use Statamic\Contracts\Data\Augmented; use Statamic\Contracts\Forms\Form as FormContract; use Statamic\Contracts\Forms\Submission; +use Statamic\Contracts\Forms\SubmissionQueryBuilder; use Statamic\Data\HasAugmentedInstance; use Statamic\Events\FormBlueprintFound; use Statamic\Events\FormCreated; @@ -296,6 +297,11 @@ public function submissions() return FormSubmission::whereForm($this->handle()); } + public function querySubmissions(): SubmissionQueryBuilder + { + return FormSubmission::query()->where('form', $this->handle()); + } + /** * Get a submission. * diff --git a/src/Http/Controllers/CP/Forms/FormSubmissionsController.php b/src/Http/Controllers/CP/Forms/FormSubmissionsController.php index 0269c78316..2940c8f7ed 100644 --- a/src/Http/Controllers/CP/Forms/FormSubmissionsController.php +++ b/src/Http/Controllers/CP/Forms/FormSubmissionsController.php @@ -2,15 +2,17 @@ namespace Statamic\Http\Controllers\CP\Forms; -use Statamic\Extensions\Pagination\LengthAwarePaginator; -use Statamic\Facades\Config; +use Statamic\Fields\Field; use Statamic\Http\Controllers\CP\CpController; +use Statamic\Http\Requests\FilteredRequest; use Statamic\Http\Resources\CP\Submissions\Submissions; -use Statamic\Support\Str; +use Statamic\Query\Scopes\Filters\Concerns\QueriesFilters; class FormSubmissionsController extends CpController { - public function index($form) + use QueriesFilters; + + public function index(FilteredRequest $request, $form) { $this->authorize('view', $form); @@ -18,52 +20,46 @@ public function index($form) return ['data' => [], 'meta' => ['columns' => []]]; } - $submissions = $form->submissions()->values(); + $query = $this->indexQuery($form); - // Search submissions. - if ($search = $this->request->search) { - $submissions = $this->searchSubmissions($submissions); - } + $activeFilterBadges = $this->queryFilters($query, $request->filters, [ + 'form' => $form->handle(), + ]); - // Sort submissions. - $sort = $this->request->sort ?? 'datestamp'; - $order = $this->request->order ?? ($sort === 'datestamp' ? 'desc' : 'asc'); - $submissions = $this->sortSubmissions($submissions, $sort, $order); + $sortField = request('sort', 'date'); + $sortDirection = request('order', $sortField === 'date' ? 'desc' : 'asc'); - // Paginate submissions. - $totalSubmissionCount = $submissions->count(); - $perPage = request('perPage') ?? Config::get('statamic.cp.pagination_size'); - $currentPage = (int) $this->request->page ?: 1; - $offset = ($currentPage - 1) * $perPage; - $submissions = $submissions->slice($offset, $perPage); - $paginator = new LengthAwarePaginator($submissions, $totalSubmissionCount, $perPage, $currentPage); + if ($sortField) { + $query->orderBy($sortField, $sortDirection); + } + + $submissions = $query->paginate(request('perPage')); - return (new Submissions($paginator)) + return (new Submissions($submissions)) ->blueprint($form->blueprint()) - ->columnPreferenceKey("forms.{$form->handle()}.columns"); + ->columnPreferenceKey("forms.{$form->handle()}.columns") + ->additional(['meta' => [ + 'activeFilterBadges' => $activeFilterBadges, + ]]); } - private function searchSubmissions($submissions) + protected function indexQuery($form) { - return $submissions->filter(function ($submission) { - return collect($submission->data()) - ->filter(function ($value) { - return $value && is_string($value); - }) - ->filter(function ($value) { - return Str::contains(strtolower($value), strtolower($this->request->search)); + $query = $form->querySubmissions(); + + if ($search = request('search')) { + $query->where('date', 'like', '%'.$search.'%'); + + $form->blueprint()->fields()->all() + ->filter(function (Field $field): bool { + return in_array($field->type(), ['text', 'textarea', 'integer']); }) - ->isNotEmpty(); - })->values(); - } + ->each(function (Field $field) use ($query, $search): void { + $query->orWhere($field->handle(), 'like', '%'.$search.'%'); + }); + } - private function sortSubmissions($submissions, $sortBy, $sortOrder) - { - return $submissions->sortBy(function ($submission) use ($sortBy) { - return $sortBy === 'datestamp' - ? $submission->date()->timestamp - : $submission->get($sortBy); - }, null, $sortOrder === 'desc')->values(); + return $query; } public function destroy($form, $id) diff --git a/src/Http/Controllers/CP/Forms/FormsController.php b/src/Http/Controllers/CP/Forms/FormsController.php index 6ac63cdeec..a2c53b7399 100644 --- a/src/Http/Controllers/CP/Forms/FormsController.php +++ b/src/Http/Controllers/CP/Forms/FormsController.php @@ -8,6 +8,7 @@ use Statamic\Facades\Action; use Statamic\Facades\Blueprint; use Statamic\Facades\Form; +use Statamic\Facades\Scope; use Statamic\Facades\User; use Statamic\Http\Controllers\CP\CpController; use Statamic\Rules\Handle; @@ -72,7 +73,15 @@ public function show($form) ->rejectUnlisted() ->values(); - return view('statamic::forms.show', compact('form', 'columns')); + $viewData = [ + 'form' => $form, + 'columns' => $columns, + 'filters' => Scope::filters('form-submissions', [ + 'form' => $form->handle(), + ]), + ]; + + return view('statamic::forms.show', $viewData); } /** diff --git a/src/Query/Scopes/Filters/Fields.php b/src/Query/Scopes/Filters/Fields.php index 2ce25209e3..50e3b6ac9d 100644 --- a/src/Query/Scopes/Filters/Fields.php +++ b/src/Query/Scopes/Filters/Fields.php @@ -4,6 +4,7 @@ use Statamic\Facades\Blueprint; use Statamic\Facades\Collection; +use Statamic\Facades\Form; use Statamic\Facades\Taxonomy; use Statamic\Facades\User; use Statamic\Query\Scopes\Filter; @@ -63,7 +64,7 @@ public function badge($values) public function visibleTo($key) { - return in_array($key, ['entries', 'entries-fieldtype', 'terms', 'users', 'usergroup-users']); + return in_array($key, ['entries', 'entries-fieldtype', 'form-submissions', 'terms', 'users', 'usergroup-users']); } protected function getFields() @@ -91,6 +92,17 @@ protected function getBlueprints() }); } + if ($forms = Arr::getFirst($this->context, ['form', 'forms'])) { + return collect(Arr::wrap($forms))->map(function ($form) { + return Form::find($form) + ->blueprint() + ->ensureField('date', [ + 'type' => 'date', + 'filterable' => true, + ]); + }); + } + if (isset($this->context['blueprints'])) { return collect($this->context['blueprints'])->map(function ($handle) { return $handle === 'user' diff --git a/src/Stache/Query/SubmissionQueryBuilder.php b/src/Stache/Query/SubmissionQueryBuilder.php index 4a60afcc66..305b9d0af4 100644 --- a/src/Stache/Query/SubmissionQueryBuilder.php +++ b/src/Stache/Query/SubmissionQueryBuilder.php @@ -5,6 +5,7 @@ use Illuminate\Support\Collection; use Statamic\Contracts\Forms\SubmissionQueryBuilder as QueryBuilderContract; use Statamic\Facades; +use Statamic\Query\OrderBy; class SubmissionQueryBuilder extends Builder implements QueryBuilderContract { @@ -32,6 +33,17 @@ public function whereIn($column, $values, $boolean = 'and') return parent::whereIn($column, $values, $boolean); } + public function orderBy($column, $direction = 'asc') + { + if ($column === 'datestamp') { + $column = 'date'; + } + + $this->orderBys[] = new OrderBy($column, $direction); + + return $this; + } + protected function collect($items = []) { return Collection::make($items);