0

Fail on save record on a modal in button action at header of infolist - filament laravel

I have a page view AgendamentoView. That display infolist of an Agendamento (schedule). Each schedule have one or more relation to Ocorrencias (incident). This page describes a list of related incidents of this schedule.

To display this, I used InfolistSection to display the information about schedule and other InfolistSection to display the incident view.

AgendamentoResource.php (ScheduleResource.php)


// ...
public static function infolist(Infolist $infolist): Infolist
    {
    //...
    return $infolist
        ->schema([
            InfolistSection::make('Agendamento ' . $id_agendamento)->schema([/*...*/]),

            InfolistSection::make('Ocorrências')
                    ->schema(fn(Agendamento $ag) => OcorrenciaResource::getInfolistComponents($ag->id))
                    ->columns(1)
                    ->headerActions([
                        InfolistAction::make('nova-ocorrência')
                            ->requiresConfirmation()
                            ->form(function (Agendamento $record) {

                                return [
                                    Textarea::make('texto')
                                        ->autofocus(),
                                    Hidden::make('user_id')
                                        ->default(Auth::id()),
                                    Hidden::make('agendamento_id')
                                        ->default($record->id),
                                    TextInput::make('login'),
                                    TextInput::make('senha')
                                        ->type('password')

                                ];
                            })
                            ->modalIcon('heroicon-o-bars-3-center-left')
                            ->modalDescription('Descreva o que aconteceu.')
                            ->modalAlignment(Alignment::Left)
                            ->action(function ($data) {
                    
                                if (!Auth::attempt(['email' => $data['login'], 'password' => $data['senha']])) {
                                    Notification::make()
                                        ->title('Falha na Autenticação.')
                                        ->body('Credenciais inválidas. Tente novamente.')
                                        ->color('danger')
                                        ->send();
                                    return;
                                }

                                $ocorrencia = Ocorrencia::make([ 
                                    'user_id' => $data['user_id'],
                                    'agendamento_id' => $data['agendamento_id'],
                                    'texto' => $data['texto']
                                ]);

                                $ocorrencia->save();

                                Notification::make()
                                    ->title('Ocorrência registrada com sucesso!')
                                    ->success()
                                    ->send();
                            })
                    ]),
    ]);

OcorrenciaResource.php (IncidentResource.php)

//...
class OcorrenciaResource extends Resource
{
//...
public static function getInfolistComponents(int $id_ag): array {
        $ocorrencias_por_data = Ocorrencia::buscarPeloAgendamento($id_ag);
        $components = [];

        foreach ($ocorrencias_por_data as $data => $ocorrencias) {

            $components[] = Group::make([
                TextEntry::make("data_$data")
                    ->label('')
                    ->state($data)
                    ->size(TextEntrySize::Large)
                    ->extraAttributes(['class' => 'font-bold']),
            ])
            ->columns(1)
            ->extraAttributes(['class' => 'border-t mt-4 pt-2']); 

            $components[] = Group::make([
                TextEntry::make("titulo_col_1")
                    ->label('')
                    ->state('Usuario'),
                TextEntry::make("titulo_col_2")
                    ->label('')
                    ->state('Texto'),
                TextEntry::make("titulo_col_3")
                    ->label('')
                    ->state('Hora'),
            ])->columns(3)->extraAttributes(['class' => 'px-5 font-bold']);

            foreach ($ocorrencias as $oc) {
                $components[] = Group::make([
                    TextEntry::make("usuario_ocorrencia_{$oc->user_id}")
                        ->label('')
                        ->state(User::find($oc->user_id)->name),
                    TextEntry::make("texto_ocorrencia_{$oc->id}")
                        ->label('')
                        ->state($oc->texto),
                    TextEntry::make("hora_ocorrencia_{$oc->created_at}")
                        ->label('')
                        ->state(Carbon::parse($oc->created_at)->format('H:i')), // Corrigido para H:i
                ])->columns(3)->extraAttributes(['class' => 'bg-slate-100 p-5 rounded-md mb-2']);
            }
        }

        return $components;
    }
}
//...

The second infolist hava a headerAction "nova-ocorrencia" (new incident). This have a requiresConfirmation() and form([]) schema with login, password and a text. The error occurs when click in confirm button or when close the modal.

Filament\Forms\ComponentContainer::{closure:Filament\Forms\Concerns\HasComponents::getComponents():122}(): Argument #1 ($component) must be of type Filament\Forms\Components\Component, Filament\Tables\Columns\TextColumn given

composer.json

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The skeleton application for the Laravel framework.",
    "keywords": ["laravel", "framework"],
    "license": "MIT",
    "require": {
        "php": "^8.1",
        "filafly/filament-font-awesome-icons": "^1.0",
        "filament/filament": "^3.0",
        "filament/spatie-laravel-settings-plugin": "^3.2",
        "guzzlehttp/guzzle": "^7.2",
        "laravel/framework": "^11.0",
        "laravel/sanctum": "^4.0",
        "laravel/tinker": "^2.8",
        "owen-it/laravel-auditing": "^14.0",
        "saade/filament-fullcalendar": "^3.0",
        "spatie/laravel-settings": "^3.4"
    },
    "require-dev": {
        "barryvdh/laravel-debugbar": "^3.16",
        "fakerphp/faker": "^1.9.1",
        "laravel/pint": "^1.0",
        "laravel/sail": "*",
        "mockery/mockery": "^1.6",
        "phpunit/phpunit": "^10.1",
        "spatie/laravel-ignition": "^2.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

1
  • Read the exception. Not all components are compatible with different parents. You could try upgrading to Filament v4, where they removed this weird component subdivision mechanism. Commented yesterday

1 Answer 1

0

Reason:
Your infolist is built dynamically, and Filament tries to re-process those components during the modal save. It mixes infolist + form components and crashes.

Fix (A step-by-step example):

  1. Open getInfolistComponents().

  2. Ensure all components come from Filament\Infolists\Components.

  3. Add ->infolist() to every Group::make() you return.

  4. Do not return any table or form components from that method.

  5. In the modal action use:

    ->action(function(array $data, Agendamento $record) {  })
    
    

This stops Filament from treating your infolist components as form components.

The real problem:

Your dynamic Infolist rebuilds itself on every request, including inside the modal submission.Filament tries to re-construct the infolist while processing the modal, but because the modal uses a form context, Filament mixes form + infolist components and fails.

This is a known Filament issue when:

  1. You build infolist dynamically through a callback.

  2. The callback pulls database data before the record exists (For example during modal execution).

  3. Filament tries to cast the returned components as form components, and errors.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.