mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-29 18:19:53 +08:00
feat(tables): persist grouping in the user's session (#20165)
* feat(tables): persist grouping in the user's session Add a `persistGroupInSession()` method to the table configuration, mirroring the existing `persistSortInSession()` behavior, so a user's chosen grouping is restored on their next visit. The Livewire `updatedTableGroupColumn()` hook never fired because the underlying property is `$tableGrouping` (Livewire resolves the hook as `updatedTableGrouping()`). Renaming it fixes that dormant hook, which is what both resets the page and now writes the grouping to the session. * fix(tables): align grouping session persistence --------- Co-authored-by: Dan Harrin <git@danharrin.com>
This commit is contained in:
@@ -381,3 +381,21 @@ public function table(Table $table): Table
|
||||
->groupingDirectionSettingHidden();
|
||||
}
|
||||
```
|
||||
|
||||
## Persisting the grouping in the user's session
|
||||
|
||||
To persist the grouping in the user's session, use the `persistGroupInSession()` method:
|
||||
|
||||
```php
|
||||
use Filament\Tables\Table;
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->groups([
|
||||
'status',
|
||||
'category',
|
||||
])
|
||||
->persistGroupInSession();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,9 +29,24 @@ trait CanGroupRecords
|
||||
return $this->getTable()->getDefaultGroup();
|
||||
}
|
||||
|
||||
public function updatedTableGrouping(): void
|
||||
{
|
||||
if ($this->getTable()->persistsGroupInSession()) {
|
||||
session()->put(
|
||||
$this->getTableGroupingSessionKey(),
|
||||
$this->tableGrouping,
|
||||
);
|
||||
}
|
||||
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `updatedTableGrouping()` instead.
|
||||
*/
|
||||
public function updatedTableGroupColumn(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
$this->updatedTableGrouping();
|
||||
}
|
||||
|
||||
public function getTableGroupingDirection(): ?string
|
||||
@@ -65,4 +80,11 @@ trait CanGroupRecords
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function getTableGroupingSessionKey(): string
|
||||
{
|
||||
$table = md5($this::class);
|
||||
|
||||
return "tables.{$table}_grouping";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +91,24 @@ trait InteractsWithTable
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->getTable()->isDefaultGroupSelectable()) {
|
||||
$this->tableGrouping = "{$this->getTable()->getDefaultGroup()->getId()}:asc";
|
||||
$shouldPersistGroupInSession = $this->getTable()->persistsGroupInSession();
|
||||
$groupingSessionKey = $this->getTableGroupingSessionKey();
|
||||
$hasPersistedGroupInSession = $shouldPersistGroupInSession && session()->exists($groupingSessionKey);
|
||||
|
||||
if (blank($this->tableGrouping)) {
|
||||
if ($hasPersistedGroupInSession) {
|
||||
$sessionGrouping = session()->get($groupingSessionKey);
|
||||
$this->tableGrouping = is_string($sessionGrouping) ? $sessionGrouping : null;
|
||||
} elseif ($this->getTable()->isDefaultGroupSelectable()) {
|
||||
$this->tableGrouping = "{$this->getTable()->getDefaultGroup()->getId()}:asc";
|
||||
}
|
||||
}
|
||||
|
||||
if ($shouldPersistGroupInSession) {
|
||||
session()->put(
|
||||
$groupingSessionKey,
|
||||
$this->tableGrouping,
|
||||
);
|
||||
}
|
||||
|
||||
$shouldPersistSearchInSession = $this->getTable()->persistsSearchInSession();
|
||||
|
||||
@@ -25,6 +25,8 @@ trait CanGroupRecords
|
||||
|
||||
protected bool | Closure $isGroupsOnly = false;
|
||||
|
||||
protected bool | Closure | null $persistsGroupInSession = false;
|
||||
|
||||
protected bool | Closure $areGroupingSettingsInDropdownOnDesktop = false;
|
||||
|
||||
protected bool | Closure $areGroupingSettingsHidden = false;
|
||||
@@ -104,6 +106,13 @@ trait CanGroupRecords
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function persistGroupInSession(bool | Closure $condition = true): static
|
||||
{
|
||||
$this->persistsGroupInSession = $condition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGroupRecordsTriggerAction(): Action
|
||||
{
|
||||
$action = Action::make('groupRecords')
|
||||
@@ -213,4 +222,9 @@ trait CanGroupRecords
|
||||
{
|
||||
return (bool) $this->evaluate($this->isGroupsOnly);
|
||||
}
|
||||
|
||||
public function persistsGroupInSession(): bool
|
||||
{
|
||||
return (bool) $this->evaluate($this->persistsGroupInSession);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tests\Fixtures\Livewire;
|
||||
|
||||
use Filament\Actions\Concerns\InteractsWithActions;
|
||||
use Filament\Actions\Contracts\HasActions;
|
||||
use Filament\Schemas\Concerns\InteractsWithSchemas;
|
||||
use Filament\Schemas\Contracts\HasSchemas;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Tests\Fixtures\Models\Post;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
|
||||
class PostsTableWithGroupPersistedInSession extends Component implements HasActions, HasSchemas, Tables\Contracts\HasTable
|
||||
{
|
||||
use InteractsWithActions;
|
||||
use InteractsWithSchemas;
|
||||
use Tables\Concerns\InteractsWithTable;
|
||||
|
||||
#[Url(as: 'grouping')]
|
||||
public ?string $tableGrouping = null;
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->query(Post::query())
|
||||
->groups(static fn () => [
|
||||
Tables\Grouping\Group::make('title'),
|
||||
Tables\Grouping\Group::make('author.name'),
|
||||
])
|
||||
->defaultGroup('title')
|
||||
->persistGroupInSession()
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('title')->sortable(),
|
||||
Tables\Columns\TextColumn::make('author.name')->sortable(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.table');
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
use Filament\Tables\Grouping\Group;
|
||||
use Filament\Tests\Fixtures\Livewire\GroupedCustomDataTable;
|
||||
use Filament\Tests\Fixtures\Livewire\PostsTable;
|
||||
use Filament\Tests\Fixtures\Livewire\PostsTableWithGroupPersistedInSession;
|
||||
use Filament\Tests\Fixtures\Livewire\PostsTableWithoutSummarizers;
|
||||
use Filament\Tests\Fixtures\Livewire\TicketMessagesTable;
|
||||
use Filament\Tests\Fixtures\Livewire\UsersTable;
|
||||
@@ -18,6 +19,7 @@ use Filament\Tests\Fixtures\Models\TicketMessage;
|
||||
use Filament\Tests\Fixtures\Models\User;
|
||||
use Filament\Tests\Tables\TestCase;
|
||||
use Livewire\Features\SupportTesting\Testable;
|
||||
use Livewire\Livewire;
|
||||
|
||||
use function Filament\Tests\livewire;
|
||||
|
||||
@@ -961,3 +963,87 @@ it('can group records by `HasOneThrough` -> `BelongsTo` relationship that uses `
|
||||
->set('tableGrouping', 'setting.languageWithTrashed.name')
|
||||
->assertCanSeeTableRecords($sortedUsers, inOrder: true);
|
||||
});
|
||||
|
||||
it('resets pagination when `$tableGrouping` is updated', function (): void {
|
||||
Post::factory()->count(20)->create();
|
||||
|
||||
livewire(PostsTable::class)
|
||||
->call('setPage', 2)
|
||||
->assertSet('paginators.page', 2)
|
||||
->set('tableGrouping', 'title')
|
||||
->assertSet('paginators.page', 1);
|
||||
});
|
||||
|
||||
describe('session persistence', function (): void {
|
||||
it('defaults `persistsGroupInSession()` to `false`', function (): void {
|
||||
livewire(PostsTable::class)
|
||||
->tap(function (Testable $testable): void {
|
||||
/** @var PostsTable $livewire */
|
||||
$livewire = $testable->instance();
|
||||
|
||||
expect($livewire->getTable()->persistsGroupInSession())->toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
it('can enable grouping persistence with `persistGroupInSession()`', function (): void {
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->tap(function (Testable $testable): void {
|
||||
/** @var PostsTableWithGroupPersistedInSession $livewire */
|
||||
$livewire = $testable->instance();
|
||||
|
||||
expect($livewire->getTable()->persistsGroupInSession())->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
it('scopes `getTableGroupingSessionKey()` to the component class', function (): void {
|
||||
/** @var PostsTableWithGroupPersistedInSession $livewire */
|
||||
$livewire = livewire(PostsTableWithGroupPersistedInSession::class)->instance();
|
||||
|
||||
expect($livewire->getTableGroupingSessionKey())
|
||||
->toBe('tables.' . md5($livewire::class) . '_grouping');
|
||||
});
|
||||
|
||||
it('can persist the grouping in the user\'s session', function (): void {
|
||||
Post::factory()->count(10)->create();
|
||||
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', 'title:asc')
|
||||
->set('tableGrouping', 'author.name:desc')
|
||||
->assertSet('tableGrouping', 'author.name:desc');
|
||||
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', 'author.name:desc');
|
||||
});
|
||||
|
||||
it('can clear the persisted grouping in the user\'s session', function (): void {
|
||||
Post::factory()->count(10)->create();
|
||||
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', 'title:asc')
|
||||
->set('tableGrouping', null)
|
||||
->assertSet('tableGrouping', null);
|
||||
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', null);
|
||||
});
|
||||
|
||||
it('does not override explicit `$tableGrouping` with the persisted grouping', function (): void {
|
||||
livewire(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', 'title:asc');
|
||||
|
||||
Livewire::withQueryParams(['grouping' => 'author.name:desc'])
|
||||
->test(PostsTableWithGroupPersistedInSession::class)
|
||||
->assertSet('tableGrouping', 'author.name:desc');
|
||||
});
|
||||
|
||||
it('does not persist the grouping in the user\'s session by default', function (): void {
|
||||
Post::factory()->count(10)->create();
|
||||
|
||||
livewire(PostsTable::class)
|
||||
->set('tableGrouping', 'title')
|
||||
->assertSet('tableGrouping', 'title');
|
||||
|
||||
livewire(PostsTable::class)
|
||||
->assertSet('tableGrouping', null);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user