schema([]); } public static function table(Table $table): Table { return $table ->defaultSort('created_at', 'desc') ->columns([ Tables\Columns\TextColumn::make('tenant.name') ->label(__('admin.refresh_tokens.fields.tenant')) ->searchable(), Tables\Columns\TextColumn::make('client_id') ->label(__('admin.refresh_tokens.fields.client')) ->copyable() ->toggleable(), Tables\Columns\TextColumn::make('ip_address') ->label(__('admin.refresh_tokens.fields.ip_address')) ->toggleable(), Tables\Columns\TextColumn::make('user_agent') ->label(__('admin.refresh_tokens.fields.user_agent')) ->limit(40) ->tooltip(fn (RefreshToken $record) => $record->user_agent) ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_at') ->label(__('admin.refresh_tokens.fields.created_at')) ->since() ->sortable(), Tables\Columns\TextColumn::make('last_used_at') ->label(__('admin.refresh_tokens.fields.last_used_at')) ->since() ->sortable() ->toggleable(), Tables\Columns\TextColumn::make('expires_at') ->label(__('admin.refresh_tokens.fields.expires_at')) ->dateTime() ->sortable() ->toggleable(), Tables\Columns\TextColumn::make('status') ->label(__('admin.refresh_tokens.fields.status')) ->badge() ->formatStateUsing(function (RefreshToken $record): string { if ($record->revoked_at) { return __('admin.refresh_tokens.status.revoked'); } if ($record->expires_at && $record->expires_at->isPast()) { return __('admin.refresh_tokens.status.expired'); } return __('admin.refresh_tokens.status.active'); }) ->color(function (RefreshToken $record): string { if ($record->revoked_at) { return 'danger'; } if ($record->expires_at && $record->expires_at->isPast()) { return 'warning'; } return 'success'; }), Tables\Columns\TextColumn::make('revoked_reason') ->label(__('admin.refresh_tokens.fields.revoked_reason')) ->formatStateUsing(function (?string $state): ?string { if (! $state) { return null; } $key = "admin.refresh_tokens.reasons.{$state}"; $translated = __($key); return $translated === $key ? $state : $translated; }) ->badge() ->color('gray') ->toggleable(), ]) ->filters([ SelectFilter::make('status') ->label(__('admin.refresh_tokens.filters.status')) ->options([ 'active' => __('admin.refresh_tokens.status.active'), 'revoked' => __('admin.refresh_tokens.status.revoked'), 'expired' => __('admin.refresh_tokens.status.expired'), ]) ->query(function (Builder $query, array $data): Builder { return match ($data['value'] ?? null) { 'revoked' => $query->whereNotNull('revoked_at'), 'expired' => $query->whereNull('revoked_at')->whereNotNull('expires_at')->where('expires_at', '<=', now()), 'active' => $query->whereNull('revoked_at')->where(function ($inner) { $inner->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }), default => $query, }; }), SelectFilter::make('tenant_id') ->label(__('admin.refresh_tokens.filters.tenant')) ->relationship('tenant', 'name') ->searchable(), ]) ->actions([ Tables\Actions\ViewAction::make(), Action::make('revoke') ->label(__('admin.refresh_tokens.actions.revoke')) ->icon('heroicon-o-no-symbol') ->color('danger') ->visible(fn (RefreshToken $record): bool => $record->isActive()) ->form([ Forms\Components\Select::make('reason') ->label(__('admin.refresh_tokens.fields.revoked_reason')) ->options([ 'manual' => __('admin.refresh_tokens.reasons.manual'), 'operator' => __('admin.refresh_tokens.reasons.operator'), ]) ->default('manual') ->required(), Forms\Components\Textarea::make('note') ->label(__('admin.refresh_tokens.fields.note')) ->rows(2) ->maxLength(255), ]) ->requiresConfirmation() ->action(function (RefreshToken $record, array $data): void { $note = $data['note'] ?? null; $record->revoke( $data['reason'] ?? 'manual', auth()->id(), request(), $note ? ['note' => $note] : [] ); }), ]) ->bulkActions([]); } public static function getRelations(): array { return [ AuditsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListRefreshTokens::route('/'), 'view' => Pages\ViewRefreshToken::route('/{record}'), ]; } }