Custom Page Table Actions Help - still broken

I have a custom page the table is showing fine however when I click on the action nothing is happening, it should be dumping the record. The end goal of this action is to run this query inside the action itself
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
However clicking on the action displays/does nothing itself, I tested the action on an actual resource and it works.
<?php

namespace Kenepa\TranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Kenepa\TranslationManager\Models\UserTranslation;
use Kenepa\TranslationManager\Resources\LanguageLineResource;
use Kenepa\TranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
// protected static ?string $navigationGroup = 'MyNavigationGroup';

protected static string $view = 'translation-manager::translation-billing';
protected static string $resource = LanguageLineResource::class;

public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}
public function mount(): void
{
abort_unless(static::shouldRegisterOnPanel(), 403);
}
public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}

public function table(Table $table): Table
{
return $table
->query(
UserTranslation::query()
->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
->where('is_paid', false)
->groupBy('user_id')
->orderBy('total_word_count', 'desc')
)
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
dd($record);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
<?php

namespace Kenepa\TranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Kenepa\TranslationManager\Models\UserTranslation;
use Kenepa\TranslationManager\Resources\LanguageLineResource;
use Kenepa\TranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
// protected static ?string $navigationGroup = 'MyNavigationGroup';

protected static string $view = 'translation-manager::translation-billing';
protected static string $resource = LanguageLineResource::class;

public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}
public function mount(): void
{
abort_unless(static::shouldRegisterOnPanel(), 403);
}
public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}

public function table(Table $table): Table
{
return $table
->query(
UserTranslation::query()
->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
->where('is_paid', false)
->groupBy('user_id')
->orderBy('total_word_count', 'desc')
)
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
dd($record);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
15 Replies
Lara Zeus
Lara Zeus3mo ago
did you add <x-filament-actions::modals />
datarecall
datarecall3mo ago
@Lara Zeus this is my view
<x-filament-panels::page>
<x-filament-actions::modals />

<div>
{{ $this->table }}
</div>
</x-filament-panels::page>
<x-filament-panels::page>
<x-filament-actions::modals />

<div>
{{ $this->table }}
</div>
</x-filament-panels::page>
The weird thing is the action works on any resource just not a custom page
awcodes
awcodes3mo ago
Try setting ->query() to just the base query. The select(), groupBy(), etc should be in ->modifyQueryUsing() The Page class also, already has the HasForms and HasActions interfaces and traits. Maybe including those on your page is interfering with something.
datarecall
datarecall3mo ago
@awcodes i tried that aswell just to bring everything to basics
public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => UserTranslation::query())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => UserTranslation::query())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
the action just doesn't seem to be executing at all. I added a delete action in there as well just to test but nothing happens when I click that either.
awcodes
awcodes3mo ago
You’re extending Page, right? But page doesn’t implement HasTables or uses InteractsWithTables. It’s also possible you’re using the wrong action class in your table’s ->actions() callback. Just kind of guessing here since I can’t see all of the code.
datarecall
datarecall3mo ago
<?php

namespace Kenepa\TranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Kenepa\TranslationManager\Models\UserTranslation;
use Kenepa\TranslationManager\Resources\LanguageLineResource;
use Kenepa\TranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
// protected static ?string $cluster = Translations::class;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static ?string $navigationGroup ='Translations';

protected static string $view = 'translation-manager::translation-billing';


public static function canAccess(array $parameters = []): bool
{
return auth()->user()->hasPermissionTo('manage-translation-billing');
}
public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}
public function mount(): void
{
abort_unless(static::shouldRegisterOnPanel(), 403);
}
public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}
public function tableQuery(): \Illuminate\Database\Eloquent\Builder|Relation|null
{
return UserTranslation::query();
// ->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
// ->where('is_paid', false)
// ->groupBy('user_id')
// ->orderBy('total_word_count', 'desc');
}
public function getHeaderWidgets(): array
{
return [
LanguageLineResource\Widgets\TotalTranslationsRequired::class
];
}

public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => UserTranslation::query())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
<?php

namespace Kenepa\TranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Kenepa\TranslationManager\Models\UserTranslation;
use Kenepa\TranslationManager\Resources\LanguageLineResource;
use Kenepa\TranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
// protected static ?string $cluster = Translations::class;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static ?string $navigationGroup ='Translations';

protected static string $view = 'translation-manager::translation-billing';


public static function canAccess(array $parameters = []): bool
{
return auth()->user()->hasPermissionTo('manage-translation-billing');
}
public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}
public function mount(): void
{
abort_unless(static::shouldRegisterOnPanel(), 403);
}
public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}
public function tableQuery(): \Illuminate\Database\Eloquent\Builder|Relation|null
{
return UserTranslation::query();
// ->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
// ->where('is_paid', false)
// ->groupBy('user_id')
// ->orderBy('total_word_count', 'desc');
}
public function getHeaderWidgets(): array
{
return [
LanguageLineResource\Widgets\TotalTranslationsRequired::class
];
}

public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => UserTranslation::query())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('hello');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
@awcodes the full code is at the top but here is the updated code, it is extending page and does implement hasForms and HasTable along with using their traits. TY for looking over this stuck on what i could be missing here. Anyone have any idea what I can do to make this work ?
awcodes
awcodes3mo ago
You need to call parent::mount() in your mount function since you are overriding it.
datarecall
datarecall3mo ago
<?php

namespace IllusiveCh\FilamentTranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use IllusiveCh\FilamentTranslationManager\Models\UserTranslation;
use IllusiveCh\FilamentTranslationManager\Resources\LanguageLineResource;
use IllusiveCh\FilamentTranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
// protected static ?string $cluster = Translations::class;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static ?string $navigationGroup ='Translations';

protected static string $view = 'translation-manager::translation-billing';


public static function canAccess(array $parameters = []): bool
{
return auth()->user()->hasPermissionTo('manage-translation-billing');
}
public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}

public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}
public function tableQuery(): \Illuminate\Database\Eloquent\Builder|Relation|null
{
return UserTranslation::query()
->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
->where('is_paid', false)
->groupBy('user_id')
->orderBy('total_word_count', 'desc');
}
public function getHeaderWidgets(): array
{
return [
LanguageLineResource\Widgets\TotalTranslationsRequired::class
];
}

public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => $this->tableQuery())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('here');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
<?php

namespace IllusiveCh\FilamentTranslationManager\Pages;

use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use IllusiveCh\FilamentTranslationManager\Models\UserTranslation;
use IllusiveCh\FilamentTranslationManager\Resources\LanguageLineResource;
use IllusiveCh\FilamentTranslationManager\Traits\CanRegisterPanelNavigation;

class TranslationBilling extends Page implements HasForms, HasTable
{
use CanRegisterPanelNavigation;
use InteractsWithTable;
use InteractsWithForms;
// protected static ?string $cluster = Translations::class;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static ?string $navigationGroup ='Translations';

protected static string $view = 'translation-manager::translation-billing';


public static function canAccess(array $parameters = []): bool
{
return auth()->user()->hasPermissionTo('manage-translation-billing');
}
public static function shouldRegisterNavigation(array $parameters = []): bool
{
return static::shouldRegisterOnPanel() ? config('translation-manager.quick_translate_navigation_registration') : false;
}
public static function getNavigationGroup(): ?string
{
return config('translation-manager.navigation_group');
}

public static function getNavigationIcon(): ?string
{
return 'heroicon-o-currency-dollar';
}

public function getTableRecordKey($record): string
{
return (string) $record->getKeyName();
}
public function tableQuery(): \Illuminate\Database\Eloquent\Builder|Relation|null
{
return UserTranslation::query()
->select('user_id', DB::raw('SUM(word_count) as total_word_count'))
->where('is_paid', false)
->groupBy('user_id')
->orderBy('total_word_count', 'desc');
}
public function getHeaderWidgets(): array
{
return [
LanguageLineResource\Widgets\TotalTranslationsRequired::class
];
}

public function table(Table $table): Table
{
return $table
->query(fn (Builder $query) => $this->tableQuery())
->columns([
TextColumn::make('user.name')
->searchable(),
TextColumn::make('total_word_count')
->sortable(),
])
->filters([
// ...
])
->actions([
Action::make('delete')
->action(fn () => $this->record->delete()),
Action::make('mark_paid')
->label('Mark Paid')
->icon('heroicon-o-currency-dollar')
->color('success')
->before(function ($record) {
dd('here');
})
->action(function ($record) {
UserTranslation::query()
->where('user_id', $record->user_id)
->update(['is_paid' => true]);
})
->after(function(){
Notification::make()
->duration(3000)
->success()
->title('User Paid')
->body('User has been marked as paid.')
->send();
})
])
->bulkActions([
// ...
]);
}
}
@awcodes Ok I removed the mount method entirely just to be safe, however the actions still are not running. Delete or mark paid Any thoughts on what else could be wrong ?
awcodes
awcodes3mo ago
Try a different name for the action. I’m wondering if it’s conflicting with another cached action. Also maybe drop the interactsWithForms, doubt that’s a problem but you should only need that if you have a form on the page too.
datarecall
datarecall3mo ago
I have updated the code with a new action name, Inspecting console I can see the request being posted but the mountedActions array response seems to be empty which may be weird??
No description
No description
awcodes
awcodes3mo ago
The code I’ve seen looks fine to me. Hard to say what is going on without seeing the whole codebase at this point.
datarecall
datarecall3mo ago
i can put that action on any table and it seems to work fine, just not a custom page
awcodes
awcodes3mo ago
I hear ya, but there’s something else missing and without being able to actually interact with the code I’m at a loss as to what the problem might actually be. I’m using table actions just fine on custom pages. So something else is going on somewhere else in your app that I just can’t see from the code that has been shared.
datarecall
datarecall3mo ago
sounds good, atleast I know the code is correct ill try to hunt down elsewhere it could be.
CORONEL
CORONEL2mo ago
@datarecall , did you figured it out? I'm facing the same behaviour when trying to call a table action from a custom component table. Ok, i got it working for my use case. I was declaring the table->query() to a relation query, just replacing it by table->relationship(...) made it work.