mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-10-31 02:06:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			598 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			598 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace App\Filament\Pages;
 | |
| 
 | |
| use App\Models\Backup;
 | |
| use App\Notifications\MailTested;
 | |
| use App\Traits\EnvironmentWriterTrait;
 | |
| use Exception;
 | |
| use Filament\Actions\Action;
 | |
| use Filament\Forms\Components\Actions\Action as FormAction;
 | |
| use Filament\Forms\Components\Section;
 | |
| use Filament\Forms\Components\Tabs;
 | |
| use Filament\Forms\Components\Tabs\Tab;
 | |
| use Filament\Forms\Components\TagsInput;
 | |
| use Filament\Forms\Components\TextInput;
 | |
| use Filament\Forms\Components\Toggle;
 | |
| use Filament\Forms\Components\ToggleButtons;
 | |
| use Filament\Forms\Concerns\InteractsWithForms;
 | |
| use Filament\Forms\Contracts\HasForms;
 | |
| use Filament\Forms\Form;
 | |
| use Filament\Forms\Get;
 | |
| use Filament\Forms\Set;
 | |
| use Filament\Notifications\Notification;
 | |
| use Filament\Pages\Concerns\HasUnsavedDataChangesAlert;
 | |
| use Filament\Pages\Concerns\InteractsWithHeaderActions;
 | |
| use Filament\Pages\Page;
 | |
| use Illuminate\Support\Facades\Artisan;
 | |
| use Illuminate\Support\Facades\Notification as MailNotification;
 | |
| 
 | |
| /**
 | |
|  * @property Form $form
 | |
|  */
 | |
| class Settings extends Page implements HasForms
 | |
| {
 | |
|     use EnvironmentWriterTrait;
 | |
|     use HasUnsavedDataChangesAlert;
 | |
|     use InteractsWithForms;
 | |
|     use InteractsWithHeaderActions;
 | |
| 
 | |
|     protected static ?string $navigationIcon = 'tabler-settings';
 | |
| 
 | |
|     protected static ?string $navigationGroup = 'Advanced';
 | |
| 
 | |
|     protected static string $view = 'filament.pages.settings';
 | |
| 
 | |
|     public ?array $data = [];
 | |
| 
 | |
|     public function mount(): void
 | |
|     {
 | |
|         $this->form->fill();
 | |
|     }
 | |
| 
 | |
|     public static function canAccess(): bool
 | |
|     {
 | |
|         return auth()->user()->can('view settings');
 | |
|     }
 | |
| 
 | |
|     protected function getFormSchema(): array
 | |
|     {
 | |
|         return [
 | |
|             Tabs::make('Tabs')
 | |
|                 ->columns()
 | |
|                 ->persistTabInQueryString()
 | |
|                 ->disabled(fn () => !auth()->user()->can('update settings'))
 | |
|                 ->tabs([
 | |
|                     Tab::make('general')
 | |
|                         ->label('General')
 | |
|                         ->icon('tabler-home')
 | |
|                         ->schema($this->generalSettings()),
 | |
|                     Tab::make('recaptcha')
 | |
|                         ->label('reCAPTCHA')
 | |
|                         ->icon('tabler-shield')
 | |
|                         ->schema($this->recaptchaSettings()),
 | |
|                     Tab::make('mail')
 | |
|                         ->label('Mail')
 | |
|                         ->icon('tabler-mail')
 | |
|                         ->schema($this->mailSettings()),
 | |
|                     Tab::make('backup')
 | |
|                         ->label('Backup')
 | |
|                         ->icon('tabler-box')
 | |
|                         ->schema($this->backupSettings()),
 | |
|                     Tab::make('misc')
 | |
|                         ->label('Misc')
 | |
|                         ->icon('tabler-tool')
 | |
|                         ->schema($this->miscSettings()),
 | |
|                 ]),
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     private function generalSettings(): array
 | |
|     {
 | |
|         return [
 | |
|             TextInput::make('APP_NAME')
 | |
|                 ->label('App Name')
 | |
|                 ->required()
 | |
|                 ->default(env('APP_NAME', 'Pelican')),
 | |
|             TextInput::make('APP_FAVICON')
 | |
|                 ->label('App Favicon')
 | |
|                 ->hintIcon('tabler-question-mark')
 | |
|                 ->hintIconTooltip('Favicons should be placed in the public folder, located in the root panel directory.')
 | |
|                 ->required()
 | |
|                 ->default(env('APP_FAVICON', '/pelican.ico')),
 | |
|             Toggle::make('APP_DEBUG')
 | |
|                 ->label('Enable Debug Mode?')
 | |
|                 ->inline(false)
 | |
|                 ->onIcon('tabler-check')
 | |
|                 ->offIcon('tabler-x')
 | |
|                 ->onColor('success')
 | |
|                 ->offColor('danger')
 | |
|                 ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                 ->afterStateUpdated(fn ($state, Set $set) => $set('APP_DEBUG', (bool) $state))
 | |
|                 ->default(env('APP_DEBUG', config('app.debug'))),
 | |
|             ToggleButtons::make('FILAMENT_TOP_NAVIGATION')
 | |
|                 ->label('Navigation')
 | |
|                 ->inline()
 | |
|                 ->options([
 | |
|                     false => 'Sidebar',
 | |
|                     true => 'Topbar',
 | |
|                 ])
 | |
|                 ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                 ->afterStateUpdated(fn ($state, Set $set) => $set('FILAMENT_TOP_NAVIGATION', (bool) $state))
 | |
|                 ->default(env('FILAMENT_TOP_NAVIGATION', config('panel.filament.top-navigation'))),
 | |
|             ToggleButtons::make('PANEL_USE_BINARY_PREFIX')
 | |
|                 ->label('Unit prefix')
 | |
|                 ->inline()
 | |
|                 ->options([
 | |
|                     false => 'Decimal Prefix (MB/ GB)',
 | |
|                     true => 'Binary Prefix (MiB/ GiB)',
 | |
|                 ])
 | |
|                 ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                 ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_USE_BINARY_PREFIX', (bool) $state))
 | |
|                 ->default(env('PANEL_USE_BINARY_PREFIX', config('panel.use_binary_prefix'))),
 | |
|             ToggleButtons::make('APP_2FA_REQUIRED')
 | |
|                 ->label('2FA Requirement')
 | |
|                 ->inline()
 | |
|                 ->options([
 | |
|                     0 => 'Not required',
 | |
|                     1 => 'Required for only Admins',
 | |
|                     2 => 'Required for all Users',
 | |
|                 ])
 | |
|                 ->formatStateUsing(fn ($state): int => (int) $state)
 | |
|                 ->afterStateUpdated(fn ($state, Set $set) => $set('APP_2FA_REQUIRED', (int) $state))
 | |
|                 ->default(env('APP_2FA_REQUIRED', config('panel.auth.2fa_required'))),
 | |
|             TagsInput::make('TRUSTED_PROXIES')
 | |
|                 ->label('Trusted Proxies')
 | |
|                 ->separator()
 | |
|                 ->splitKeys(['Tab', ' '])
 | |
|                 ->placeholder('New IP or IP Range')
 | |
|                 ->default(env('TRUSTED_PROXIES', config('trustedproxy.proxies')))
 | |
|                 ->hintActions([
 | |
|                     FormAction::make('clear')
 | |
|                         ->label('Clear')
 | |
|                         ->color('danger')
 | |
|                         ->icon('tabler-trash')
 | |
|                         ->requiresConfirmation()
 | |
|                         ->authorize(fn () => auth()->user()->can('update settings'))
 | |
|                         ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [])),
 | |
|                     FormAction::make('cloudflare')
 | |
|                         ->label('Set to Cloudflare IPs')
 | |
|                         ->icon('tabler-brand-cloudflare')
 | |
|                         ->authorize(fn () => auth()->user()->can('update settings'))
 | |
|                         ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [
 | |
|                             '173.245.48.0/20',
 | |
|                             '103.21.244.0/22',
 | |
|                             '103.22.200.0/22',
 | |
|                             '103.31.4.0/22',
 | |
|                             '141.101.64.0/18',
 | |
|                             '108.162.192.0/18',
 | |
|                             '190.93.240.0/20',
 | |
|                             '188.114.96.0/20',
 | |
|                             '197.234.240.0/22',
 | |
|                             '198.41.128.0/17',
 | |
|                             '162.158.0.0/15',
 | |
|                             '104.16.0.0/13',
 | |
|                             '104.24.0.0/14',
 | |
|                             '172.64.0.0/13',
 | |
|                             '131.0.72.0/22',
 | |
|                         ])),
 | |
|                 ]),
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     private function recaptchaSettings(): array
 | |
|     {
 | |
|         return [
 | |
|             Toggle::make('RECAPTCHA_ENABLED')
 | |
|                 ->label('Enable reCAPTCHA?')
 | |
|                 ->inline(false)
 | |
|                 ->onIcon('tabler-check')
 | |
|                 ->offIcon('tabler-x')
 | |
|                 ->onColor('success')
 | |
|                 ->offColor('danger')
 | |
|                 ->live()
 | |
|                 ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                 ->afterStateUpdated(fn ($state, Set $set) => $set('RECAPTCHA_ENABLED', (bool) $state))
 | |
|                 ->default(env('RECAPTCHA_ENABLED', config('recaptcha.enabled'))),
 | |
|             TextInput::make('RECAPTCHA_DOMAIN')
 | |
|                 ->label('Domain')
 | |
|                 ->required()
 | |
|                 ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED'))
 | |
|                 ->default(env('RECAPTCHA_DOMAIN', config('recaptcha.domain'))),
 | |
|             TextInput::make('RECAPTCHA_WEBSITE_KEY')
 | |
|                 ->label('Website Key')
 | |
|                 ->required()
 | |
|                 ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED'))
 | |
|                 ->default(env('RECAPTCHA_WEBSITE_KEY', config('recaptcha.website_key'))),
 | |
|             TextInput::make('RECAPTCHA_SECRET_KEY')
 | |
|                 ->label('Secret Key')
 | |
|                 ->required()
 | |
|                 ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED'))
 | |
|                 ->default(env('RECAPTCHA_SECRET_KEY', config('recaptcha.secret_key'))),
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     private function mailSettings(): array
 | |
|     {
 | |
|         return [
 | |
|             ToggleButtons::make('MAIL_MAILER')
 | |
|                 ->label('Mail Driver')
 | |
|                 ->columnSpanFull()
 | |
|                 ->inline()
 | |
|                 ->options([
 | |
|                     'log' => 'Print mails to Log',
 | |
|                     'smtp' => 'SMTP Server',
 | |
|                     'sendmail' => 'sendmail Binary',
 | |
|                     'mailgun' => 'Mailgun',
 | |
|                     'mandrill' => 'Mandrill',
 | |
|                     'postmark' => 'Postmark',
 | |
|                 ])
 | |
|                 ->live()
 | |
|                 ->default(env('MAIL_MAILER', config('mail.default')))
 | |
|                 ->hintAction(
 | |
|                     FormAction::make('test')
 | |
|                         ->label('Send Test Mail')
 | |
|                         ->icon('tabler-send')
 | |
|                         ->hidden(fn (Get $get) => $get('MAIL_MAILER') === 'log')
 | |
|                         ->authorize(fn () => auth()->user()->can('update settings'))
 | |
|                         ->action(function () {
 | |
|                             try {
 | |
|                                 MailNotification::route('mail', auth()->user()->email)
 | |
|                                     ->notify(new MailTested(auth()->user()));
 | |
| 
 | |
|                                 Notification::make()
 | |
|                                     ->title('Test Mail sent')
 | |
|                                     ->success()
 | |
|                                     ->send();
 | |
|                             } catch (Exception $exception) {
 | |
|                                 Notification::make()
 | |
|                                     ->title('Test Mail failed')
 | |
|                                     ->body($exception->getMessage())
 | |
|                                     ->danger()
 | |
|                                     ->send();
 | |
|                             }
 | |
|                         })
 | |
|                 ),
 | |
|             Section::make('"From" Settings')
 | |
|                 ->description('Set the Address and Name used as "From" in mails.')
 | |
|                 ->columns()
 | |
|                 ->schema([
 | |
|                     TextInput::make('MAIL_FROM_ADDRESS')
 | |
|                         ->label('From Address')
 | |
|                         ->required()
 | |
|                         ->email()
 | |
|                         ->default(env('MAIL_FROM_ADDRESS', config('mail.from.address'))),
 | |
|                     TextInput::make('MAIL_FROM_NAME')
 | |
|                         ->label('From Name')
 | |
|                         ->required()
 | |
|                         ->default(env('MAIL_FROM_NAME', config('mail.from.name'))),
 | |
|                 ]),
 | |
|             Section::make('SMTP Configuration')
 | |
|                 ->columns()
 | |
|                 ->visible(fn (Get $get) => $get('MAIL_MAILER') === 'smtp')
 | |
|                 ->schema([
 | |
|                     TextInput::make('MAIL_HOST')
 | |
|                         ->label('Host')
 | |
|                         ->required()
 | |
|                         ->default(env('MAIL_HOST', config('mail.mailers.smtp.host'))),
 | |
|                     TextInput::make('MAIL_PORT')
 | |
|                         ->label('Port')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1)
 | |
|                         ->maxValue(65535)
 | |
|                         ->default(env('MAIL_PORT', config('mail.mailers.smtp.port'))),
 | |
|                     TextInput::make('MAIL_USERNAME')
 | |
|                         ->label('Username')
 | |
|                         ->default(env('MAIL_USERNAME', config('mail.mailers.smtp.username'))),
 | |
|                     TextInput::make('MAIL_PASSWORD')
 | |
|                         ->label('Password')
 | |
|                         ->password()
 | |
|                         ->revealable()
 | |
|                         ->default(env('MAIL_PASSWORD')),
 | |
|                     ToggleButtons::make('MAIL_ENCRYPTION')
 | |
|                         ->label('Encryption')
 | |
|                         ->inline()
 | |
|                         ->options(['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'])
 | |
|                         ->default(env('MAIL_ENCRYPTION', config('mail.mailers.smtp.encryption', 'tls'))),
 | |
|                 ]),
 | |
|             Section::make('Mailgun Configuration')
 | |
|                 ->columns()
 | |
|                 ->visible(fn (Get $get) => $get('MAIL_MAILER') === 'mailgun')
 | |
|                 ->schema([
 | |
|                     TextInput::make('MAILGUN_DOMAIN')
 | |
|                         ->label('Domain')
 | |
|                         ->required()
 | |
|                         ->default(env('MAILGUN_DOMAIN', config('services.mailgun.domain'))),
 | |
|                     TextInput::make('MAILGUN_SECRET')
 | |
|                         ->label('Secret')
 | |
|                         ->required()
 | |
|                         ->default(env('MAILGUN_SECRET', config('services.mailgun.secret'))),
 | |
|                     TextInput::make('MAILGUN_ENDPOINT')
 | |
|                         ->label('Endpoint')
 | |
|                         ->required()
 | |
|                         ->default(env('MAILGUN_ENDPOINT', config('services.mailgun.endpoint'))),
 | |
|                 ]),
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     private function backupSettings(): array
 | |
|     {
 | |
|         return [
 | |
|             ToggleButtons::make('APP_BACKUP_DRIVER')
 | |
|                 ->label('Backup Driver')
 | |
|                 ->columnSpanFull()
 | |
|                 ->inline()
 | |
|                 ->options([
 | |
|                     Backup::ADAPTER_DAEMON => 'Wings',
 | |
|                     Backup::ADAPTER_AWS_S3 => 'S3',
 | |
|                 ])
 | |
|                 ->live()
 | |
|                 ->default(env('APP_BACKUP_DRIVER', config('backups.default'))),
 | |
|             Section::make('Throttles')
 | |
|                 ->description('Configure how many backups can be created in a period. Set period to 0 to disable this throttle.')
 | |
|                 ->columns()
 | |
|                 ->schema([
 | |
|                     TextInput::make('BACKUP_THROTTLE_LIMIT')
 | |
|                         ->label('Limit')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1)
 | |
|                         ->default(config('backups.throttles.limit')),
 | |
|                     TextInput::make('BACKUP_THROTTLE_PERIOD')
 | |
|                         ->label('Period')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(0)
 | |
|                         ->suffix('Seconds')
 | |
|                         ->default(config('backups.throttles.period')),
 | |
|                 ]),
 | |
|             Section::make('S3 Configuration')
 | |
|                 ->columns()
 | |
|                 ->visible(fn (Get $get) => $get('APP_BACKUP_DRIVER') === Backup::ADAPTER_AWS_S3)
 | |
|                 ->schema([
 | |
|                     TextInput::make('AWS_DEFAULT_REGION')
 | |
|                         ->label('Default Region')
 | |
|                         ->required()
 | |
|                         ->default(config('backups.disks.s3.region')),
 | |
|                     TextInput::make('AWS_ACCESS_KEY_ID')
 | |
|                         ->label('Access Key ID')
 | |
|                         ->required()
 | |
|                         ->default(config('backups.disks.s3.key')),
 | |
|                     TextInput::make('AWS_SECRET_ACCESS_KEY')
 | |
|                         ->label('Secret Access Key')
 | |
|                         ->required()
 | |
|                         ->default(config('backups.disks.s3.secret')),
 | |
|                     TextInput::make('AWS_BACKUPS_BUCKET')
 | |
|                         ->label('Bucket')
 | |
|                         ->required()
 | |
|                         ->default(config('backups.disks.s3.bucket')),
 | |
|                     TextInput::make('AWS_ENDPOINT')
 | |
|                         ->label('Endpoint')
 | |
|                         ->required()
 | |
|                         ->default(config('backups.disks.s3.endpoint')),
 | |
|                     Toggle::make('AWS_USE_PATH_STYLE_ENDPOINT')
 | |
|                         ->label('Use path style endpoint?')
 | |
|                         ->inline(false)
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('AWS_USE_PATH_STYLE_ENDPOINT', (bool) $state))
 | |
|                         ->default(env('AWS_USE_PATH_STYLE_ENDPOINT', config('backups.disks.s3.use_path_style_endpoint'))),
 | |
|                 ]),
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     private function miscSettings(): array
 | |
|     {
 | |
|         return [
 | |
|             Section::make('Automatic Allocation Creation')
 | |
|                 ->description('Toggle if Users can create allocations via the client area.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     Toggle::make('PANEL_CLIENT_ALLOCATIONS_ENABLED')
 | |
|                         ->label('Allow Users to create allocations?')
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->columnSpanFull()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_CLIENT_ALLOCATIONS_ENABLED', (bool) $state))
 | |
|                         ->default(env('PANEL_CLIENT_ALLOCATIONS_ENABLED', config('panel.client_features.allocations.enabled'))),
 | |
|                     TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_START')
 | |
|                         ->label('Starting Port')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1024)
 | |
|                         ->maxValue(65535)
 | |
|                         ->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED'))
 | |
|                         ->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_START')),
 | |
|                     TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_END')
 | |
|                         ->label('Ending Port')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1024)
 | |
|                         ->maxValue(65535)
 | |
|                         ->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED'))
 | |
|                         ->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_END')),
 | |
|                 ]),
 | |
|             Section::make('Mail Notifications')
 | |
|                 ->description('Toggle which mail notifications should be sent to Users.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     Toggle::make('PANEL_SEND_INSTALL_NOTIFICATION')
 | |
|                         ->label('Server Installed')
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->columnSpanFull()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_INSTALL_NOTIFICATION', (bool) $state))
 | |
|                         ->default(env('PANEL_SEND_INSTALL_NOTIFICATION', config('panel.email.send_install_notification'))),
 | |
|                     Toggle::make('PANEL_SEND_REINSTALL_NOTIFICATION')
 | |
|                         ->label('Server Reinstalled')
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->columnSpanFull()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_REINSTALL_NOTIFICATION', (bool) $state))
 | |
|                         ->default(env('PANEL_SEND_REINSTALL_NOTIFICATION', config('panel.email.send_reinstall_notification'))),
 | |
|                 ]),
 | |
|             Section::make('Connections')
 | |
|                 ->description('Timeouts used when making requests.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     TextInput::make('GUZZLE_TIMEOUT')
 | |
|                         ->label('Request Timeout')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(15)
 | |
|                         ->maxValue(60)
 | |
|                         ->suffix('Seconds')
 | |
|                         ->default(env('GUZZLE_TIMEOUT', config('panel.guzzle.timeout'))),
 | |
|                     TextInput::make('GUZZLE_CONNECT_TIMEOUT')
 | |
|                         ->label('Connect Timeout')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(5)
 | |
|                         ->maxValue(60)
 | |
|                         ->suffix('Seconds')
 | |
|                         ->default(env('GUZZLE_CONNECT_TIMEOUT', config('panel.guzzle.connect_timeout'))),
 | |
|                 ]),
 | |
|             Section::make('Activity Logs')
 | |
|                 ->description('Configure how often old activity logs should be pruned and whether admin activities should be logged.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     TextInput::make('APP_ACTIVITY_PRUNE_DAYS')
 | |
|                         ->label('Prune age')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1)
 | |
|                         ->maxValue(365)
 | |
|                         ->suffix('Days')
 | |
|                         ->default(env('APP_ACTIVITY_PRUNE_DAYS', config('activity.prune_days'))),
 | |
|                     Toggle::make('APP_ACTIVITY_HIDE_ADMIN')
 | |
|                         ->label('Hide admin activities?')
 | |
|                         ->inline(false)
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('APP_ACTIVITY_HIDE_ADMIN', (bool) $state))
 | |
|                         ->default(env('APP_ACTIVITY_HIDE_ADMIN', config('activity.hide_admin_activity'))),
 | |
|                 ]),
 | |
|             Section::make('API')
 | |
|                 ->description('Defines the rate limit for the number of requests per minute that can be executed.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     TextInput::make('APP_API_CLIENT_RATELIMIT')
 | |
|                         ->label('Client API Rate Limit')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1)
 | |
|                         ->suffix('Requests Per Minute')
 | |
|                         ->default(env('APP_API_CLIENT_RATELIMIT', config('http.rate_limit.client'))),
 | |
|                     TextInput::make('APP_API_APPLICATION_RATELIMIT')
 | |
|                         ->label('Application API Rate Limit')
 | |
|                         ->required()
 | |
|                         ->numeric()
 | |
|                         ->minValue(1)
 | |
|                         ->suffix('Requests Per Minute')
 | |
|                         ->default(env('APP_API_APPLICATION_RATELIMIT', config('http.rate_limit.application'))),
 | |
|                 ]),
 | |
|             Section::make('Server')
 | |
|                 ->description('Settings for Servers.')
 | |
|                 ->columns()
 | |
|                 ->collapsible()
 | |
|                 ->collapsed()
 | |
|                 ->schema([
 | |
|                     Toggle::make('PANEL_EDITABLE_SERVER_DESCRIPTIONS')
 | |
|                         ->label('Allow Users to edit Server Descriptions?')
 | |
|                         ->onIcon('tabler-check')
 | |
|                         ->offIcon('tabler-x')
 | |
|                         ->onColor('success')
 | |
|                         ->offColor('danger')
 | |
|                         ->live()
 | |
|                         ->columnSpanFull()
 | |
|                         ->formatStateUsing(fn ($state): bool => (bool) $state)
 | |
|                         ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_EDITABLE_SERVER_DESCRIPTIONS', (bool) $state))
 | |
|                         ->default(env('PANEL_EDITABLE_SERVER_DESCRIPTIONS', config('panel.editable_server_descriptions'))),
 | |
|                 ]),
 | |
| 
 | |
|         ];
 | |
|     }
 | |
| 
 | |
|     protected function getFormStatePath(): ?string
 | |
|     {
 | |
|         return 'data';
 | |
|     }
 | |
| 
 | |
|     protected function hasUnsavedDataChangesAlert(): bool
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     public function save(): void
 | |
|     {
 | |
|         try {
 | |
|             $data = $this->form->getState();
 | |
| 
 | |
|             // Convert bools to a string, so they are correctly written to the .env file
 | |
|             $data = array_map(fn ($value) => is_bool($value) ? ($value ? 'true' : 'false') : $value, $data);
 | |
| 
 | |
|             $this->writeToEnvironment($data);
 | |
| 
 | |
|             Artisan::call('config:clear');
 | |
|             Artisan::call('queue:restart');
 | |
| 
 | |
|             $this->rememberData();
 | |
| 
 | |
|             $this->redirect($this->getUrl());
 | |
| 
 | |
|             Notification::make()
 | |
|                 ->title('Settings saved')
 | |
|                 ->success()
 | |
|                 ->send();
 | |
|         } catch (Exception $exception) {
 | |
|             Notification::make()
 | |
|                 ->title('Save failed')
 | |
|                 ->body($exception->getMessage())
 | |
|                 ->danger()
 | |
|                 ->send();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     protected function getHeaderActions(): array
 | |
|     {
 | |
|         return [
 | |
|             Action::make('save')
 | |
|                 ->action('save')
 | |
|                 ->authorize(fn () => auth()->user()->can('update settings'))
 | |
|                 ->keyBindings(['mod+s']),
 | |
|         ];
 | |
| 
 | |
|     }
 | |
| }
 | 
