From 499764e90b3badef6b57970dd00bf785e176f803 Mon Sep 17 00:00:00 2001 From: Mitch Schwenk Date: Wed, 22 Apr 2026 10:40:55 -0700 Subject: [PATCH] Add extendTable hook support to relation pages Mirror Lunar's existing resource and relation-manager table extension pattern on relation-style resource pages by adding a table seam to BaseManageRelatedRecords. This introduces a shared ExtendsTables concern that routes the public table(Table $table) entrypoint through getDefaultTable() and the existing Lunar hook dispatcher via extendTable. The affected BaseManageRelatedRecords pages move their current table definitions into getDefaultTable() so packages can alter columns, filters, actions, and query behavior without replacing the whole page. RelationPageExtension now exposes a typed extendTable(Table $table): Table method for discoverability and consistency. To preserve compatibility for downstream code that may expect concrete pages to still expose a public table() method, the touched pages keep a thin public wrapper that delegates to the base implementation. Adds focused feature coverage using ManageCollectionProducts to verify: - the concrete page still exposes a public table() method - default table behavior is unchanged with no extension registered - a RelationPageExtension can extend the page table --- .../Pages/ManageBrandCollections.php | 5 ++ .../Pages/ManageBrandProducts.php | 5 ++ .../Pages/ManageCollectionChildren.php | 5 ++ .../Pages/ManageCollectionProducts.php | 5 ++ .../Pages/ManageProductAssociations.php | 5 ++ .../Pages/ManageProductCollections.php | 5 ++ .../Pages/ManageProductVariants.php | 38 ++----------- .../Pages/ManageVariantMedia.php | 5 ++ .../Extending/RelationPageExtension.php | 6 +++ .../Pages/BaseManageRelatedRecords.php | 2 + .../Support/Pages/Concerns/ExtendsTables.php | 18 +++++++ .../Pages/ManageUrlsRelatedRecords.php | 5 ++ .../Extending/RelationPageExtensionTest.php | 54 +++++++++++++++++++ 13 files changed, 125 insertions(+), 33 deletions(-) create mode 100644 packages/admin/src/Support/Pages/Concerns/ExtendsTables.php diff --git a/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandCollections.php b/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandCollections.php index cf688f27e5..a88af2c749 100644 --- a/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandCollections.php +++ b/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandCollections.php @@ -36,6 +36,11 @@ public static function getNavigationLabel(): string } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table->columns([ TranslatedTextColumn::make('attribute_data.name') diff --git a/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandProducts.php b/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandProducts.php index ec9f5262fa..1c68abe1da 100644 --- a/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandProducts.php +++ b/packages/admin/src/Filament/Resources/BrandResource/Pages/ManageBrandProducts.php @@ -38,6 +38,11 @@ public static function getNavigationLabel(): string } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table->columns([ ProductResource::getNameTableColumn()->searchable() diff --git a/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionChildren.php b/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionChildren.php index e3e7e6fa96..54bb346df6 100644 --- a/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionChildren.php +++ b/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionChildren.php @@ -57,6 +57,11 @@ public function form(Schema $schema): Schema } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { $record = $this->getOwnerRecord(); diff --git a/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionProducts.php b/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionProducts.php index 9d4bf6f4c2..079d794062 100644 --- a/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionProducts.php +++ b/packages/admin/src/Filament/Resources/CollectionResource/Pages/ManageCollectionProducts.php @@ -70,6 +70,11 @@ public function reorderTable(array $order, string|int|null $draggedRecordKey = n } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table->columns([ diff --git a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductAssociations.php b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductAssociations.php index afad396769..f3f72b12ed 100644 --- a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductAssociations.php +++ b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductAssociations.php @@ -62,6 +62,11 @@ public function form(Schema $schema): Schema } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table ->recordTitleAttribute('name') diff --git a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductCollections.php b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductCollections.php index 203617d351..1ef97ba078 100644 --- a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductCollections.php +++ b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductCollections.php @@ -37,6 +37,11 @@ public static function getNavigationLabel(): string } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table ->recordTitleAttribute('name') diff --git a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductVariants.php b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductVariants.php index 8e9f2a7020..d3553de495 100644 --- a/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductVariants.php +++ b/packages/admin/src/Filament/Resources/ProductResource/Pages/ManageProductVariants.php @@ -2,17 +2,9 @@ namespace Lunar\Admin\Filament\Resources\ProductResource\Pages; -use Filament\Actions\BulkActionGroup; -use Filament\Actions\CreateAction; -use Filament\Actions\DeleteAction; -use Filament\Actions\DeleteBulkAction; -use Filament\Actions\EditAction; -use Filament\Actions\ViewAction; use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Filament\Support\Facades\FilamentIcon; -use Filament\Tables; -use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; use Lunar\Admin\Filament\Resources\ProductResource; use Lunar\Admin\Filament\Resources\ProductResource\Widgets\ProductOptionsWidget; @@ -72,31 +64,11 @@ public function form(Schema $schema): Schema public function table(Table $table): Table { - return $table; + return parent::table($table); + } - return $table - ->recordTitleAttribute('name') - ->columns([ - TextColumn::make('sku'), - ]) - ->filters([ - // - ]) - ->headerActions([ - CreateAction::make(), - // Tables\Actions\AssociateAction::make(), - ]) - ->recordActions([ - ViewAction::make(), - EditAction::make(), - // Tables\Actions\DissociateAction::make(), - DeleteAction::make(), - ]) - ->toolbarActions([ - BulkActionGroup::make([ - // Tables\Actions\DissociateBulkAction::make(), - DeleteBulkAction::make(), - ]), - ]); + protected function getDefaultTable(Table $table): Table + { + return $table; } } diff --git a/packages/admin/src/Filament/Resources/ProductVariantResource/Pages/ManageVariantMedia.php b/packages/admin/src/Filament/Resources/ProductVariantResource/Pages/ManageVariantMedia.php index c0183c692b..cd51b08e7e 100644 --- a/packages/admin/src/Filament/Resources/ProductVariantResource/Pages/ManageVariantMedia.php +++ b/packages/admin/src/Filament/Resources/ProductVariantResource/Pages/ManageVariantMedia.php @@ -65,6 +65,11 @@ public function getBreadcrumbs(): array } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table ->heading(function () { diff --git a/packages/admin/src/Support/Extending/RelationPageExtension.php b/packages/admin/src/Support/Extending/RelationPageExtension.php index d9bafaaa54..c5bb21b8c9 100644 --- a/packages/admin/src/Support/Extending/RelationPageExtension.php +++ b/packages/admin/src/Support/Extending/RelationPageExtension.php @@ -2,10 +2,16 @@ namespace Lunar\Admin\Support\Extending; +use Filament\Tables\Table; use Illuminate\Database\Eloquent\Model; abstract class RelationPageExtension extends BaseExtension { + public function extendTable(Table $table): Table + { + return $table; + } + public function heading($title, Model $record): string { return $title; diff --git a/packages/admin/src/Support/Pages/BaseManageRelatedRecords.php b/packages/admin/src/Support/Pages/BaseManageRelatedRecords.php index 3cc4efa533..3fe62c44c5 100644 --- a/packages/admin/src/Support/Pages/BaseManageRelatedRecords.php +++ b/packages/admin/src/Support/Pages/BaseManageRelatedRecords.php @@ -8,6 +8,7 @@ use Lunar\Admin\Support\Pages\Concerns\ExtendsHeaderActions; use Lunar\Admin\Support\Pages\Concerns\ExtendsHeaderWidgets; use Lunar\Admin\Support\Pages\Concerns\ExtendsHeadings; +use Lunar\Admin\Support\Pages\Concerns\ExtendsTables; abstract class BaseManageRelatedRecords extends ManageRelatedRecords { @@ -16,4 +17,5 @@ abstract class BaseManageRelatedRecords extends ManageRelatedRecords use ExtendsHeaderActions; use ExtendsHeaderWidgets; use ExtendsHeadings; + use ExtendsTables; } diff --git a/packages/admin/src/Support/Pages/Concerns/ExtendsTables.php b/packages/admin/src/Support/Pages/Concerns/ExtendsTables.php new file mode 100644 index 0000000000..8efa70b023 --- /dev/null +++ b/packages/admin/src/Support/Pages/Concerns/ExtendsTables.php @@ -0,0 +1,18 @@ +callLunarHook('extendTable', $this->getDefaultTable($table)); + } + + protected function getDefaultTable(Table $table): Table + { + return $table; + } +} diff --git a/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php b/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php index 0502b93b70..5feba34a73 100644 --- a/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php +++ b/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php @@ -80,6 +80,11 @@ public function form(Schema $schema): Schema } public function table(Table $table): Table + { + return parent::table($table); + } + + protected function getDefaultTable(Table $table): Table { return $table ->recordTitleAttribute('name') diff --git a/tests/admin/Feature/Support/Extending/RelationPageExtensionTest.php b/tests/admin/Feature/Support/Extending/RelationPageExtensionTest.php index abd4eedd00..b9a853d4f5 100644 --- a/tests/admin/Feature/Support/Extending/RelationPageExtensionTest.php +++ b/tests/admin/Feature/Support/Extending/RelationPageExtensionTest.php @@ -1,10 +1,14 @@ group('extending'); +it('keeps the table method public on concrete relation pages', function () { + $method = new ReflectionMethod(ManageCollectionProducts::class, 'table'); + + expect($method->isPublic())->toBeTrue() + ->and($method->getDeclaringClass()->getName())->toBe(ManageCollectionProducts::class); +}); + +it('keeps the default relation page table intact when no extension is registered', function () { + Language::factory()->create([ + 'default' => true, + ]); + + $collection = Collection::factory()->create(); + + $this->asStaff(admin: true); + + Livewire::test(ManageCollectionProducts::class, [ + 'record' => $collection->getRouteKey(), + ])->assertTableColumnExists('attribute_data.name'); +}); + +it('can extend relation page table columns', function () { + $class = new class extends RelationPageExtension + { + public function extendTable(Table $table): Table + { + return $table->columns([ + ...$table->getColumns(), + TextColumn::make('test_column'), + ]); + } + }; + + Language::factory()->create([ + 'default' => true, + ]); + + $collection = Collection::factory()->create(); + + LunarPanel::extensions([ + ManageCollectionProducts::class => $class::class, + ]); + + $this->asStaff(admin: true); + + Livewire::test(ManageCollectionProducts::class, [ + 'record' => $collection->getRouteKey(), + ])->assertTableColumnExists('test_column'); +}); + it('can customise page headings', function () { $class = new class extends RelationPageExtension {