diff --git a/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php b/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php index 039b8c2749..7a0cf0cd9b 100644 --- a/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php +++ b/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php @@ -5,11 +5,21 @@ use App\Filament\Admin\Resources\UserResource\Pages\EditUser; use App\Filament\Server\Resources\ActivityResource; use App\Models\ActivityLog; -use App\Models\User; use App\Filament\Components\Tables\Columns\DateTimeColumn; +use App\Models\Server; +use App\Models\User; +use Filament\Facades\Filament; +use Filament\Forms\Components\Actions\Action; +use Filament\Forms\Components\DateTimePicker; +use Filament\Forms\Components\KeyValue; +use Filament\Forms\Components\Placeholder; +use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\ListRecords; +use Filament\Tables\Actions\ViewAction; use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Table; +use Illuminate\Support\HtmlString; class ListActivities extends ListRecords { @@ -17,30 +27,85 @@ class ListActivities extends ListRecords public function table(Table $table): Table { + /** @var Server $server */ + $server = Filament::getTenant(); + return $table + ->paginated([25, 50, 100, 250]) + ->defaultPaginationPageOption(25) ->columns([ TextColumn::make('event') ->html() ->description(fn ($state) => $state) - ->formatStateUsing(function ($state, ActivityLog $activityLog) { - $properties = $activityLog->wrapProperties(); + ->icon(fn (ActivityLog $activityLog) => $activityLog->getIcon()) + ->formatStateUsing(fn (ActivityLog $activityLog) => $activityLog->getLabel()), + TextColumn::make('user') + ->state(function (ActivityLog $activityLog) use ($server) { + if (!$activityLog->actor instanceof User) { + return 'System'; + } - return trans_choice('activity.'.str($state)->replace(':', '.'), array_get($properties, 'count', 1), $properties); - }) - ->tooltip(function (ActivityLog $activityLog) { - $files = array_get($activityLog->properties, 'files', []); + $user = $activityLog->actor->username; - return is_array($files) ? implode(',', $files) : null; - }), - TextColumn::make('user') - ->state(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User ? $activityLog->actor->username : 'System') + // Only show the email if the actor is the server owner/ a subuser or if the viewing user is an admin + if (auth()->user()->isAdmin() || $server->owner_id === $activityLog->actor->id || $server->subusers->where('user_id', $activityLog->actor->id)->first()) { + $user .= " ({$activityLog->actor->email})"; + } + + return $user; + }) ->tooltip(fn (ActivityLog $activityLog) => auth()->user()->can('seeIps activityLog') ? $activityLog->ip : '') - ->url(fn (ActivityLog $activityLog): string => $activityLog->actor instanceof User ? EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin', tenant: null) : ''), + ->url(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update user') ? EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin') : '') + ->grow(false), DateTimeColumn::make('timestamp') ->since() - ->sortable(), + ->sortable() + ->grow(false), + ]) + ->defaultSort('timestamp', 'desc') + ->actions([ + ViewAction::make() + //->visible(fn (ActivityLog $activityLog) => $activityLog->hasAdditionalMetadata()) + ->form([ + Placeholder::make('event') + ->content(fn (ActivityLog $activityLog) => new HtmlString($activityLog->getLabel())), + TextInput::make('user') + ->formatStateUsing(function (ActivityLog $activityLog) use ($server) { + if (!$activityLog->actor instanceof User) { + return 'System'; + } + + $user = $activityLog->actor->username; + + // Only show the email if the actor is the server owner/ a subuser or if the viewing user is an admin + if (auth()->user()->isAdmin() || $server->owner_id === $activityLog->actor->id || $server->subusers->where('user_id', $activityLog->actor->id)->first()) { + $user .= " ({$activityLog->actor->email})"; + } + + if (auth()->user()->can('seeIps activityLog')) { + $user .= " - $activityLog->ip"; + } + + return $user; + }) + ->hintAction( + Action::make('edit') + ->label(__('filament-actions::edit.single.label')) + ->icon('tabler-edit') + ->visible(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User && auth()->user()->can('update user')) + ->url(fn (ActivityLog $activityLog) => EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin')) + ), + DateTimePicker::make('timestamp'), + KeyValue::make('properties') + ->label('Metadata'), + ]), ]) - ->defaultSort('timestamp', 'desc'); + ->filters([ + SelectFilter::make('event') + ->options(fn (Table $table) => $table->getQuery()->pluck('event', 'event')->unique()->sort()) + ->searchable() + ->preload(), + ]); } public function getBreadcrumbs(): array diff --git a/app/Models/ActivityLog.php b/app/Models/ActivityLog.php index 15e2fd1431..d7ce7530ab 100644 --- a/app/Models/ActivityLog.php +++ b/app/Models/ActivityLog.php @@ -5,6 +5,8 @@ use Carbon\Carbon; use Illuminate\Support\Facades\Event; use App\Events\ActivityLogged; +use Filament\Support\Contracts\HasIcon; +use Filament\Support\Contracts\HasLabel; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\MassPrunable; use Illuminate\Database\Eloquent\Relations\HasOne; @@ -47,7 +49,7 @@ * @method static Builder|ActivityLog whereProperties($value) * @method static Builder|ActivityLog whereTimestamp($value) */ -class ActivityLog extends Model +class ActivityLog extends Model implements HasIcon, HasLabel { use MassPrunable; @@ -143,6 +145,22 @@ protected static function boot(): void }); } + public function getIcon(): string + { + if ($this->apiKey) { + return 'tabler-api'; + } + + return $this->actor instanceof User ? 'tabler-user' : 'tabler-device-desktop'; + } + + public function getLabel(): string + { + $properties = $this->wrapProperties(); + + return trans_choice('activity.'.str($this->event)->replace(':', '.'), array_key_exists('count', $properties) ? $properties['count'] : 1, $properties); + } + public function htmlable(): string { $user = $this->actor; @@ -152,8 +170,6 @@ public function htmlable(): string 'username' => 'system', ]); } - $properties = $this->wrapProperties(); - $event = trans_choice('activity.'.str($this->event)->replace(':', '.'), array_key_exists('count', $properties) ? $properties['count'] : 1, $properties); return "
$user->username — $this->event
-$event
+{$this->getLabel()}
$this->ip — {$this->timestamp->diffForHumans()}