laravellaravel-livewirealpine.jslaravel-filament

Laravel Filament V3 causes Action components on ViewResource to be disabled on polling


As the title suggests I have an application that receives a huge amount of data that gets updated aproximately 3-5 times every second for each record in the database. It is required that my application displays the data live using polling.

I'm using laravel filament v3 and a Filament\Resources\Pages\ViewRecord class to display the detail of my resource.

I'm using its infolist() method to display my resource columns via TextEntry class instance as such:

\Filament\Infolists\Components\TextEntry::make('updated_at')
    ->extraAttributes(['wire:poll.1s' => '']),

This works well and using the extraAttributes() chain method on even one of my TextEntry instances causes the entire resource detail to rerender all of its data correctly.

In the getActions() I have a set of actions such as this one:

Action::make('Test Action')
    ->requiresConfirmation()
    ->action(function () use ($model) {
        ... random action logic ...
    }),

This action opens a modal that contains a submit button used for final action confirmation before submitting the form and causing the action logic to get executed.

Here's whats currently causing me trouble:

When the action opens there is still the polling logic getting executed in the background. During the execution of the polling logic the submit button gets disabled for a short time. So since I'm polling my form every single second, my submit button also gets disabled for a short time and reenabled again.

I have tried going through the filament/actions/resources/views and filament/filament/resources/views/components blade templates and removing references of :disable or :isProcessing livewire attributes but nothing seems to work.

Also I have found no particular references to my specific use case in the laravel filament documentation (polling on resource detail view while also implementing actions) and ChatGPT is also lost.

What is the recommended way for implementing my specific use case in laravel filament v3?

How can I prevent the submit button from getting disabled during polling?


Solution

  • There is a bug currently introduced into filament v3 that causes the modal-close event to not get fired - see Filament\Infolists\Concerns\InteractsWithInfolists.php and line 330:

    if ($shouldCloseModal) {
        $this->dispatch('close-modal', id: "{$this->getId()}-infolist-action");
    }
    

    the $shouldCloseModal boolean gets passed in as false even on proper Action closing, causing the modal-close event to not get fired.

    I have bypassed said problem by overloading the entire public function unmountInfolistAction(bool $shouldCancelParentActions = true, bool $shouldCloseModal = true): void method.

    Then I also overloaded the public function dispatch($event, ...$params): void method from Livewire\Features\SupportEvents\HandlesEvents trait since the $listeners events also dont work.

    This is the key snippet of code that then allowed me to control the polling on modal opening and closing events:

    class ViewEntity extends ViewRecord
    {
        public bool $isPolling = true;
    
        public function dispatch($event, ...$params): void
        {
            if ($event === 'open-modal') {
                $this->isPolling = false;
            }
    
            if ($event === 'close-modal') {
                $this->isPolling = true;
            }
    
            parent::dispatch($event, ...$params);
        }
    }
    

    Here is the overloading trait I've added to my ViewRecord class to fix the aformentioned bug:

    <?php
    
    declare(strict_types=1);
    
    namespace App\Filament\Traits;
    
    trait InfolistActionUnmountFixTrait
    {
        /**
         * TODO: there is a bug currently introduced in the filament that causes the close-modal event to not get dispatched, this overload is a fix to said bug.
         *
         * @throws \Exception
         */
        public function unmountInfolistAction(bool $shouldCancelParentActions = true, bool $shouldCloseModal = true): void
        {
            parent::unmountInfolistAction($shouldCancelParentActions, $shouldCloseModal);
    
            $this->dispatch('close-modal', id: "{$this->getId()}-infolist-action");
        }
    }
    

    Very hacky, but the best thing that I have at the moment.