send('fail2ban.list_jails', []); if ($result['success'] ?? false) { $this->jails = $result['jails'] ?? []; $this->resetTable(); } } catch (\Exception $e) { // Keep existing data on error } } public function makeFilamentTranslatableContentDriver(): ?\Filament\Support\Contracts\TranslatableContentDriver { return null; } public function table(Table $table): Table { return $table ->records(fn () => $this->jails) ->columns([ TextColumn::make('name') ->label(__('Service')) ->formatStateUsing(fn (string $state): string => ucfirst($state)) ->searchable(), TextColumn::make('description') ->label(__('Description')) ->limit(50) ->color('gray'), IconColumn::make('active') ->label(__('Active')) ->boolean() ->trueIcon('heroicon-o-check-circle') ->falseIcon('heroicon-o-x-circle') ->trueColor('success') ->falseColor('gray'), IconColumn::make('enabled') ->label(__('Enabled')) ->boolean() ->trueIcon('heroicon-o-shield-check') ->falseIcon('heroicon-o-shield-exclamation') ->trueColor('success') ->falseColor('gray'), ]) ->actions([ Action::make('toggle') ->label(fn (array $record): string => ($record['enabled'] ?? false) ? __('Disable') : __('Enable')) ->icon(fn (array $record): string => ($record['enabled'] ?? false) ? 'heroicon-o-x-circle' : 'heroicon-o-check-circle') ->color(fn (array $record): string => ($record['enabled'] ?? false) ? 'danger' : 'success') ->disabled(fn (array $record): bool => ($record['name'] ?? '') === 'sshd') ->action(function (array $record): void { $name = $record['name'] ?? ''; $enabled = $record['enabled'] ?? false; try { $agent = new AgentClient(); $action = $enabled ? 'fail2ban.disable_jail' : 'fail2ban.enable_jail'; $result = $agent->send($action, ['jail' => $name]); if ($result['success'] ?? false) { Notification::make() ->title($enabled ? __('Jail disabled') : __('Jail enabled')) ->success() ->send(); // Reload jails data directly $this->reloadJails(); } else { throw new \Exception($result['error'] ?? __('Operation failed')); } } catch (\Exception $e) { Notification::make() ->title(__('Error')) ->body($e->getMessage()) ->danger() ->send(); } }), ]) ->striped() ->emptyStateHeading(__('No protection modules')) ->emptyStateDescription(__('No Fail2ban jails are configured.')) ->emptyStateIcon('heroicon-o-shield-exclamation'); } public function render() { return $this->getTable()->render(); } }