Skip to content

Commit f95455f

Browse files
Add search input to filter ReportBuilder column selection (#112)
Add Alpine.js-powered client-side search to the report editor's column selection panel. Users can now type to filter columns by label, with sections hiding entirely when no columns match. Controlled by a new $enableColumnSearch property (defaults to true) on WithReportBuilder. Closes #111 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 68cb993 commit f95455f

3 files changed

Lines changed: 73 additions & 12 deletions

File tree

resources/views/report-editor.blade.php

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div x-data="{open: true }" x-cloak
1+
<div x-data="{open: true, search: '' }" x-cloak
22
class="m-4 block p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700">
33

44
@if(!$selectedColumns)
@@ -8,18 +8,27 @@ class="m-4 block p-6 bg-white border border-gray-200 rounded-lg shadow dark:bg-g
88
@endif
99

1010
<div x-show="open">
11+
@if($this->enableColumnSearch)
12+
<div class="mb-4">
13+
<input type="text" x-model="search" placeholder="Search columns..."
14+
class="w-full text-sm border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white" />
15+
</div>
16+
@endif
17+
1118
@foreach($this->availableColumns() as $section => $columns)
12-
<h6 class="mb-4 pb-1 text-base font-bold text-gray-600 dark:text-white border-b border-dashed">{{ $section }}</h6>
13-
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
14-
@foreach($columns as $columnKey => $column)
15-
<div class="flex items-center mb-4">
16-
<input wire:model.live.debounce.1000ms="selectedColumns" id="{{$column['key']}}" type="checkbox"
17-
value="{{ $column['key'] }}"
18-
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
19-
<label for="{{$column['key']}}"
20-
class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">{{$column['label']}}</label>
21-
</div>
22-
@endforeach
19+
<div x-show="[{!! collect($columns)->map(fn ($column) => "'" . e($column['label']) . "'")->implode(',') !!}].some(label => label.toLowerCase().includes(search.toLowerCase()))">
20+
<h6 class="mb-4 pb-1 text-base font-bold text-gray-600 dark:text-white border-b border-dashed">{{ $section }}</h6>
21+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
22+
@foreach($columns as $columnKey => $column)
23+
<div class="flex items-center mb-4" x-show="'{{ e($column['label']) }}'.toLowerCase().includes(search.toLowerCase())">
24+
<input wire:model.live.debounce.1000ms="selectedColumns" id="{{$column['key']}}" type="checkbox"
25+
value="{{ $column['key'] }}"
26+
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
27+
<label for="{{$column['key']}}"
28+
class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">{{$column['label']}}</label>
29+
</div>
30+
@endforeach
31+
</div>
2332
</div>
2433
@endforeach
2534

src/Support/Concerns/WithReportBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ trait WithReportBuilder
3030

3131
public bool $enableGroupBy = false;
3232

33+
public bool $enableColumnSearch = true;
34+
3335
private function findElementByKey(array $array, $targetValue): ?array
3436
{
3537
foreach ($array as $value) {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
it('has enableColumnSearch property defaulting to true on WithReportBuilder trait', function () {
4+
$trait = new class
5+
{
6+
use ACTTraining\QueryBuilder\Support\Concerns\WithReportBuilder;
7+
};
8+
9+
expect($trait->enableColumnSearch)->toBeTrue();
10+
});
11+
12+
it('report editor view contains the column search markup', function () {
13+
$viewContent = file_get_contents(
14+
__DIR__.'/../resources/views/report-editor.blade.php'
15+
);
16+
17+
expect($viewContent)
18+
->toContain('x-model="search"')
19+
->toContain('placeholder="Search columns..."')
20+
->toContain('enableColumnSearch')
21+
->toContain("search: ''");
22+
});
23+
24+
it('report editor view wraps search input in enableColumnSearch conditional', function () {
25+
$viewContent = file_get_contents(
26+
__DIR__.'/../resources/views/report-editor.blade.php'
27+
);
28+
29+
expect($viewContent)
30+
->toContain('@if($this->enableColumnSearch)')
31+
->toContain('.toLowerCase().includes(search.toLowerCase())');
32+
});
33+
34+
it('report editor view adds x-show filtering to individual column checkboxes', function () {
35+
$viewContent = file_get_contents(
36+
__DIR__.'/../resources/views/report-editor.blade.php'
37+
);
38+
39+
expect($viewContent)
40+
->toContain("x-show=\"'{{ e(\$column['label']) }}'.toLowerCase().includes(search.toLowerCase())\"");
41+
});
42+
43+
it('report editor view adds x-show filtering to section wrappers', function () {
44+
$viewContent = file_get_contents(
45+
__DIR__.'/../resources/views/report-editor.blade.php'
46+
);
47+
48+
expect($viewContent)
49+
->toContain('.some(label => label.toLowerCase().includes(search.toLowerCase()))');
50+
});

0 commit comments

Comments
 (0)