query(RadioApiKey::query()) ->defaultSort('created_at', 'desc') ->columns([ TextColumn::make('name') ->label('Naam') ->searchable(), TextColumn::make('key') ->label('API Key') ->formatStateUsing(fn ($state) => substr($state, 0, 16) . '...') ->copyable() ->copyMessage('Gekopieerd!'), TextColumn::make('rate_limit') ->label('Rate Limit') ->badge() ->color('info'), IconColumn::make('is_active') ->label('Actief') ->boolean() ->trueIcon('heroicon-o-check-circle') ->falseIcon('heroicon-o-x-circle') ->trueColor('success') ->falseColor('danger'), TextColumn::make('last_used_at') ->label('Laatst gebruikt') ->dateTime('d-m-Y H:i') ->placeholder('Nooit'), TextColumn::make('expires_at') ->label('Verloopt') ->dateTime('d-m-Y') ->placeholder('Nooit'), TextColumn::make('created_at') ->label('Aangemaakt') ->dateTime('d-m-Y H:i'), ]) ->actions(function ($record) { return [ ActionGroup::make([ Action::make('toggle') ->label($record->is_active ? 'Deactiveren' : 'Activeren') ->icon($record->is_active ? 'heroicon-o-pause' : 'heroicon-o-play') ->action(fn () => $this->toggleKey($record)), Action::make('delete') ->label('Verwijderen') ->icon('heroicon-o-trash') ->color('danger') ->requiresConfirmation() ->action(fn () => $record->delete()), ]), ]; }) ->headerActions([ Action::make('create') ->label('Nieuwe API Sleutel') ->icon('heroicon-o-plus') ->color('primary') ->form([ TextInput::make('name') ->label('Naam') ->required() ->maxLength(255) ->placeholder('Bijv. Discord Bot, Mobiele App'), TextInput::make('allowed_ips') ->label('Toegestane IP-adressen') ->placeholder('Leeg laten voor alle IPs (bijv. 1.2.3.4, 5.6.7.8)') ->helperText('Komma-gescheiden lijst van IP-adressen. Leeg = alle IPs toegestaan.'), Select::make('rate_limit') ->label('Rate Limit (verzoeken per minuut)') ->options([ 60 => '60/min', 100 => '100/min', 300 => '300/min', 500 => '500/min', 1000 => '1000/min', ]) ->default(300), Select::make('permissions') ->label('Permissies') ->multiple() ->options([ '*' => 'Alle permissies', 'now-playing' => 'Nu Afspelen', 'listeners' => 'Luisteraars', 'current-dj' => 'Huidige DJ', 'config' => 'Configuratie', 'shouts' => 'Shouts', 'points' => 'Punten', 'requests' => 'Song Requests', ]) ->default(['*']), Toggle::make('set_expiration') ->label('Vervaldatum instellen') ->live(), TextInput::make('expires_at') ->label('Vervaldatum') ->type('date') ->visible(fn ($get) => $get('set_expiration')), ]) ->action(function (array $data) { $this->createKey($data); }), ]); } private function createKey(array $data): void { $key = RadioApiKey::generate($data['name'], [ 'allowed_ips' => $data['allowed_ips'] ?? null, 'permissions' => $data['permissions'] ?? ['*'], 'rate_limit' => $data['rate_limit'] ?? 300, 'expires_at' => ! empty($data['set_expiration']) && ! empty($data['expires_at']) ? $data['expires_at'] : null, ]); $this->newKey = $key->key; Notification::make() ->success() ->title('API Sleutel Aangemaakt!') ->body('Kopieer de sleutel nu - deze wordt niet meer getoond.') ->send(); } private function toggleKey(RadioApiKey $key): void { $key->update(['is_active' => ! $key->is_active]); Notification::make() ->success() ->title($key->is_active ? 'API Sleutel geactiveerd' : 'API Sleutel gedeactiveerd') ->send(); } #[\Override] protected function getHeaderActions(): array { return []; } public function getNewKey(): ?string { $key = $this->newKey; $this->newKey = null; return $key; } }