sessions()->count(); return $count > 0 ? (string) $count : null; } /** * Gated on the same permission that governs the rest of this screen, * rather than a permission of its own: whoever may already deactivate an * account is exactly who should be able to see, and end, where it is * currently signed in. */ public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool { return (bool) Auth::user()?->can('users.update'); } public function table(Table $table): Table { return $table ->recordTitleAttribute('id') ->defaultSort('last_activity', 'desc') ->columns([ TextColumn::make('ip_address') ->label(__('panel.sessions.fields.ip_address')) ->fontFamily('mono') ->placeholder('—'), TextColumn::make('user_agent') ->label(__('panel.sessions.fields.device')) ->state(fn (UserSession $record) => self::describeUserAgent($record->user_agent)) ->description(fn (UserSession $record) => $record->isCurrent() ? __('panel.sessions.this_one') : null), TextColumn::make('last_activity') ->label(__('panel.sessions.fields.last_activity')) ->state(fn (UserSession $record) => $record->last_activity) ->since() ->dateTimeTooltip(), ]) ->recordActions([ Action::make('revoke') ->label(__('panel.sessions.actions.revoke')) ->icon('heroicon-o-x-circle') ->color('danger') ->requiresConfirmation() // The one row this screen must never offer to end: doing // so would sign out whoever is looking at it, mid-click. ->visible(fn (UserSession $record) => ! $record->isCurrent()) ->action(function (UserSession $record): void { $record->delete(); Notification::make() ->title(__('panel.sessions.revoked')) ->success() ->send(); }), ]) ->emptyStateHeading(__('panel.sessions.empty.heading')) ->emptyStateDescription(__('panel.sessions.empty.description')) ->emptyStateIcon('heroicon-o-computer-desktop'); } /** * Browser and platform, guessed from the raw string every session row * already carries — not a parsing library, just enough of one to turn * "Mozilla/5.0 (Macintosh…) AppleWebKit… Safari/605.1" into something a * person recognises at a glance. */ protected static function describeUserAgent(?string $userAgent): string { if (blank($userAgent)) { return __('panel.sessions.unknown_device'); } $browser = match (true) { Str::contains($userAgent, 'Edg/') => 'Edge', Str::contains($userAgent, 'OPR/') => 'Opera', Str::contains($userAgent, 'Firefox/') => 'Firefox', Str::contains($userAgent, 'Chrome/') => 'Chrome', Str::contains($userAgent, 'Safari/') => 'Safari', default => null, }; $platform = match (true) { Str::contains($userAgent, 'iPhone') || Str::contains($userAgent, 'iPad') => 'iOS', Str::contains($userAgent, 'Android') => 'Android', Str::contains($userAgent, 'Mac OS X') => 'macOS', Str::contains($userAgent, 'Windows') => 'Windows', Str::contains($userAgent, 'Linux') => 'Linux', default => null, }; return match (true) { $browser && $platform => "{$browser} · {$platform}", $browser !== null => $browser, $platform !== null => $platform, default => __('panel.sessions.unknown_device'), }; } }