mirror of
https://github.com/alexjustesen/speedtest-tracker.git
synced 2026-06-23 07:10:10 +00:00
[Feature] Convert API page to Resource (#2214)
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Forms\Components\DateTimePicker;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Infolists\Components\Section;
|
||||
use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Infolists\Concerns\InteractsWithInfolists;
|
||||
use Filament\Infolists\Contracts\HasInfolists;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Support\Enums\FontFamily;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
use Filament\Tables\Actions\Action;
|
||||
use Filament\Tables\Actions\ActionGroup;
|
||||
use Filament\Tables\Actions\DeleteAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Concerns\InteractsWithTable;
|
||||
use Filament\Tables\Contracts\HasTable;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ApiTokens extends Page implements HasForms, HasInfolists, HasTable
|
||||
{
|
||||
use InteractsWithForms, InteractsWithInfolists, InteractsWithTable;
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-api';
|
||||
|
||||
protected static string $view = 'filament.pages.api-tokens';
|
||||
|
||||
protected static ?string $title = 'API Tokens';
|
||||
|
||||
protected static ?string $navigationGroup = 'Settings';
|
||||
|
||||
public ?string $token = '';
|
||||
|
||||
public function tokenInfolist(Infolist $infolist): Infolist
|
||||
{
|
||||
return $infolist
|
||||
->state([
|
||||
'token' => $this->token,
|
||||
])
|
||||
->schema([
|
||||
Section::make()
|
||||
->columns(1)
|
||||
->schema([
|
||||
TextEntry::make('token')
|
||||
->label('API Token')
|
||||
->formatStateUsing(fn (string $state) => explode('|', $state)[1])
|
||||
->helperText('Copy and save the token above, this token will not be shown again!')
|
||||
->color('gray')
|
||||
->copyable()
|
||||
->copyableState(fn (string $state) => explode('|', $state)[1])
|
||||
->fontFamily(FontFamily::Mono),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->relationship(fn (): MorphMany => Auth::user()->tokens())
|
||||
->headerActions([
|
||||
Action::make('createToken')
|
||||
->form([
|
||||
TextInput::make('token_name')
|
||||
->label('Name')
|
||||
->maxLength('100')
|
||||
->required()
|
||||
->autocomplete(false),
|
||||
CheckboxList::make('abilities')
|
||||
->options([
|
||||
'results:read' => 'Read results',
|
||||
'speedtests:run' => 'Run speedtest',
|
||||
'ookla:list-servers' => 'List servers',
|
||||
])
|
||||
->descriptions([
|
||||
'results:read' => 'Allow this token to read results.',
|
||||
'speedtests:run' => 'Allow this token to run speedtests.',
|
||||
'ookla:list-servers' => 'Allow this token to list server.',
|
||||
])
|
||||
->bulkToggleable(),
|
||||
DateTimePicker::make('token_expires_at')
|
||||
->label('Expires at')
|
||||
->nullable()
|
||||
->helperText('Leave empty for no expiration'),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
$token = Auth::user()->createToken(
|
||||
name: $data['token_name'],
|
||||
abilities: $data['abilities'],
|
||||
expiresAt: $data['token_expires_at'] ? Carbon::parse($data['token_expires_at']) : null,
|
||||
);
|
||||
|
||||
$this->token = $token->plainTextToken;
|
||||
})
|
||||
->label('Create API Token')
|
||||
->modal('createToken')
|
||||
->modalWidth(MaxWidth::ExtraLarge),
|
||||
])
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable(),
|
||||
TextColumn::make('abilities')
|
||||
->badge(),
|
||||
TextColumn::make('created_at')
|
||||
->alignEnd()
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
TextColumn::make('last_used_at')
|
||||
->alignEnd()
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
TextColumn::make('expires_at')
|
||||
->alignEnd()
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
])
|
||||
->actions([
|
||||
ActionGroup::make([
|
||||
DeleteAction::make(),
|
||||
]),
|
||||
])
|
||||
->bulkActions([
|
||||
// ...
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\ApiTokenResource\Pages;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Forms\Components\DateTimePicker;
|
||||
use Filament\Forms\Components\Grid;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables\Actions\ActionGroup;
|
||||
use Filament\Tables\Actions\DeleteAction;
|
||||
use Filament\Tables\Actions\DeleteBulkAction;
|
||||
use Filament\Tables\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TernaryFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Laravel\Sanctum\PersonalAccessToken;
|
||||
|
||||
class ApiTokenResource extends Resource
|
||||
{
|
||||
protected static ?string $model = PersonalAccessToken::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-api';
|
||||
|
||||
protected static ?string $navigationGroup = 'Settings';
|
||||
|
||||
protected static ?string $label = 'API Token';
|
||||
|
||||
protected static ?string $pluralLabel = 'API Tokens';
|
||||
|
||||
public static function getTokenFormSchema(): array
|
||||
{
|
||||
return [
|
||||
Grid::make()
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Name')
|
||||
->unique(ignoreRecord: true)
|
||||
->maxLength(100)
|
||||
->required(),
|
||||
CheckboxList::make('abilities')
|
||||
->label('Abilities')
|
||||
->options([
|
||||
'results:read' => 'Read results',
|
||||
'speedtests:run' => 'Run speedtest',
|
||||
'ookla:list-servers' => 'List servers',
|
||||
])
|
||||
->required()
|
||||
->bulkToggleable()
|
||||
->descriptions([
|
||||
'results:read' => 'Allow this token to read results.',
|
||||
'speedtests:run' => 'Allow this token to run speedtests.',
|
||||
'ookla:list-servers' => 'Allow this token to list servers.',
|
||||
]),
|
||||
DateTimePicker::make('expires_at')
|
||||
->label('Expires at')
|
||||
->nullable()
|
||||
->native(false)
|
||||
->helperText('Leave empty for no expiration'),
|
||||
])
|
||||
->columns([
|
||||
'lg' => 1,
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form->schema(static::getTokenFormSchema());
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->query(PersonalAccessToken::query()->where('tokenable_id', Auth::id()))
|
||||
->columns([
|
||||
TextColumn::make('name')->searchable(),
|
||||
TextColumn::make('abilities')->badge(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime(config('app.datetime_format'))
|
||||
->timezone(config('app.display_timezone'))
|
||||
->toggleable()
|
||||
->sortable()
|
||||
->alignEnd(),
|
||||
TextColumn::make('last_used_at')
|
||||
->dateTime(config('app.datetime_format'))
|
||||
->timezone(config('app.display_timezone'))
|
||||
->toggleable()
|
||||
->toggledHiddenByDefault()
|
||||
->sortable()
|
||||
->alignEnd(),
|
||||
TextColumn::make('expires_at')
|
||||
->dateTime(config('app.datetime_format'))
|
||||
->timezone(config('app.display_timezone'))
|
||||
->toggleable()
|
||||
->sortable()
|
||||
->alignEnd(),
|
||||
])
|
||||
->filters([
|
||||
TernaryFilter::make('expired')
|
||||
->label('Token Status')
|
||||
->placeholder('All tokens')
|
||||
->falseLabel('Active tokens')
|
||||
->trueLabel('Expired tokens')
|
||||
->native(false)
|
||||
->queries(
|
||||
true: fn (Builder $query) => $query
|
||||
->where('expires_at', '<=', now()),
|
||||
|
||||
false: fn (Builder $query) => $query
|
||||
->where(function (Builder $q) {
|
||||
$q->whereNull('expires_at')
|
||||
->orWhere('expires_at', '>', now());
|
||||
}),
|
||||
|
||||
blank: fn (Builder $query) => $query,
|
||||
),
|
||||
SelectFilter::make('abilities')
|
||||
->label('Abilities')
|
||||
->multiple()
|
||||
->options([
|
||||
'results:read' => 'Read results',
|
||||
'speedtests:run' => 'Run speedtest',
|
||||
'ookla:list-servers' => 'List servers',
|
||||
])
|
||||
->query(function (Builder $query, array $data): Builder {
|
||||
foreach ($data['values'] ?? [] as $value) {
|
||||
$query->whereJsonContains('abilities', $value);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}),
|
||||
])
|
||||
->actions([
|
||||
ActionGroup::make([
|
||||
EditAction::make()
|
||||
->disabled(fn ($record) => $record->expires_at !== null && $record->expires_at->isPast())
|
||||
->modalWidth('xl'),
|
||||
DeleteAction::make(),
|
||||
]),
|
||||
])
|
||||
->bulkActions([
|
||||
DeleteBulkAction::make(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListApiTokens::route('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\ApiTokenResource\Pages;
|
||||
|
||||
use App\Filament\Resources\ApiTokenResource;
|
||||
use Carbon\Carbon;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListApiTokens extends ListRecords
|
||||
{
|
||||
protected static string $resource = ApiTokenResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('createToken')
|
||||
->label('Create API Token')
|
||||
->form(ApiTokenResource::getTokenFormSchema())
|
||||
->action(function (array $data): void {
|
||||
$token = auth()->user()->createToken(
|
||||
$data['name'],
|
||||
$data['abilities'],
|
||||
$data['expires_at'] ? Carbon::parse($data['expires_at']) : null
|
||||
);
|
||||
|
||||
Notification::make()
|
||||
->title('Token Created')
|
||||
->body('Your token: `'.explode('|', $token->plainTextToken)[1].'`')
|
||||
->success()
|
||||
->persistent()
|
||||
->send();
|
||||
})
|
||||
->modalWidth('xl'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<x-filament-panels::page>
|
||||
@filled($token)
|
||||
<div>
|
||||
{{ $this->tokenInfolist }}
|
||||
</div>
|
||||
@endfilled
|
||||
|
||||
<div>
|
||||
{{ $this->table }}
|
||||
</div>
|
||||
</x-filament-panels::page>
|
||||
Reference in New Issue
Block a user