Merge branch 'main' into vehikl/singleton

This commit is contained in:
Vehikl 2025-06-19 15:41:29 -04:00
commit 127e4bdabf
89 changed files with 1067 additions and 512 deletions

View File

@ -0,0 +1,9 @@
<?php
namespace App\Enums;
enum HeaderActionPosition: string
{
case Before = 'before';
case After = 'after';
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Enums;
enum HeaderWidgetPosition: string
{
case Before = 'before';
case After = 'after';
}

View File

@ -8,8 +8,11 @@ use App\Extensions\OAuth\OAuthService;
use App\Models\Backup; use App\Models\Backup;
use App\Notifications\MailTested; use App\Notifications\MailTested;
use App\Traits\EnvironmentWriterTrait; use App\Traits\EnvironmentWriterTrait;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Exception; use Exception;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions;
use Filament\Forms\Components\Actions\Action as FormAction; use Filament\Forms\Components\Actions\Action as FormAction;
use Filament\Forms\Components\Component; use Filament\Forms\Components\Component;
@ -44,9 +47,12 @@ use Illuminate\Support\Str;
*/ */
class Settings extends Page implements HasForms class Settings extends Page implements HasForms
{ {
use CanCustomizeHeaderActions, InteractsWithHeaderActions {
CanCustomizeHeaderActions::getHeaderActions insteadof InteractsWithHeaderActions;
}
use CanCustomizeHeaderWidgets;
use EnvironmentWriterTrait; use EnvironmentWriterTrait;
use InteractsWithForms; use InteractsWithForms;
use InteractsWithHeaderActions;
protected static ?string $navigationIcon = 'tabler-settings'; protected static ?string $navigationIcon = 'tabler-settings';
@ -794,7 +800,8 @@ class Settings extends Page implements HasForms
} }
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Action::make('save') Action::make('save')

View File

@ -6,11 +6,16 @@ use App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\UserResource\Pages\EditUser; use App\Filament\Admin\Resources\UserResource\Pages\EditUser;
use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Models\ApiKey; use App\Models\ApiKey;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea; use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\ToggleButtons; use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteAction; use Filament\Tables\Actions\DeleteAction;
@ -20,6 +25,11 @@ use Illuminate\Database\Eloquent\Builder;
class ApiKeyResource extends Resource class ApiKeyResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = ApiKey::class; protected static ?string $model = ApiKey::class;
protected static ?string $navigationIcon = 'tabler-key'; protected static ?string $navigationIcon = 'tabler-key';
@ -56,7 +66,7 @@ class ApiKeyResource extends Resource
return trans('admin/dashboard.advanced'); return trans('admin/dashboard.advanced');
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -92,7 +102,7 @@ class ApiKeyResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->schema([ ->schema([
@ -142,7 +152,8 @@ class ApiKeyResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListApiKeys::route('/'), 'index' => Pages\ListApiKeys::route('/'),

View File

@ -4,16 +4,24 @@ namespace App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\ApiKeyResource; use App\Filament\Admin\Resources\ApiKeyResource;
use App\Models\ApiKey; use App\Models\ApiKey;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class CreateApiKey extends CreateRecord class CreateApiKey extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ApiKeyResource::class; protected static string $resource = ApiKeyResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -4,14 +4,22 @@ namespace App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\ApiKeyResource; use App\Filament\Admin\Resources\ApiKeyResource;
use App\Models\ApiKey; use App\Models\ApiKey;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListApiKeys extends ListRecords class ListApiKeys extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ApiKeyResource::class; protected static string $resource = ApiKeyResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make() CreateAction::make()

View File

@ -3,12 +3,19 @@
namespace App\Filament\Admin\Resources; namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\DatabaseHostResource\Pages; use App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Set; use Filament\Forms\Set;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\DeleteBulkAction;
@ -20,6 +27,11 @@ use Illuminate\Database\Eloquent\Builder;
class DatabaseHostResource extends Resource class DatabaseHostResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = DatabaseHost::class; protected static ?string $model = DatabaseHost::class;
protected static ?string $navigationIcon = 'tabler-database'; protected static ?string $navigationIcon = 'tabler-database';
@ -51,7 +63,7 @@ class DatabaseHostResource extends Resource
return trans('admin/dashboard.advanced'); return trans('admin/dashboard.advanced');
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -89,7 +101,7 @@ class DatabaseHostResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->schema([ ->schema([
@ -150,7 +162,16 @@ class DatabaseHostResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{
return [
RelationManagers\DatabasesRelationManager::class,
];
}
/** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListDatabaseHosts::route('/'), 'index' => Pages\ListDatabaseHosts::route('/'),

View File

@ -4,6 +4,8 @@ namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource; use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Services\Databases\Hosts\HostCreationService; use App\Services\Databases\Hosts\HostCreationService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
@ -26,6 +28,8 @@ use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
class CreateDatabaseHost extends CreateRecord class CreateDatabaseHost extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
use HasWizard; use HasWizard;
protected static string $resource = DatabaseHostResource::class; protected static string $resource = DatabaseHostResource::class;

View File

@ -3,9 +3,12 @@
namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages; namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource; use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers\DatabasesRelationManager;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use App\Services\Databases\Hosts\HostUpdateService; use App\Services\Databases\Hosts\HostUpdateService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
@ -15,6 +18,9 @@ use PDOException;
class EditDatabaseHost extends EditRecord class EditDatabaseHost extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = DatabaseHostResource::class; protected static string $resource = DatabaseHostResource::class;
private HostUpdateService $hostUpdateService; private HostUpdateService $hostUpdateService;
@ -24,7 +30,8 @@ class EditDatabaseHost extends EditRecord
$this->hostUpdateService = $hostUpdateService; $this->hostUpdateService = $hostUpdateService;
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make() DeleteAction::make()
@ -39,17 +46,6 @@ class EditDatabaseHost extends EditRecord
return []; return [];
} }
public function getRelationManagers(): array
{
if (DatabasesRelationManager::canViewForRecord($this->getRecord(), static::class)) {
return [
DatabasesRelationManager::class,
];
}
return [];
}
protected function handleRecordUpdate(Model $record, array $data): Model protected function handleRecordUpdate(Model $record, array $data): Model
{ {
if (!$record instanceof DatabaseHost) { if (!$record instanceof DatabaseHost) {

View File

@ -4,14 +4,22 @@ namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource; use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListDatabaseHosts extends ListRecords class ListDatabaseHosts extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = DatabaseHostResource::class; protected static string $resource = DatabaseHostResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make() CreateAction::make()

View File

@ -3,29 +3,25 @@
namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages; namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource; use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers\DatabasesRelationManager; use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewDatabaseHost extends ViewRecord class ViewDatabaseHost extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = DatabaseHostResource::class; protected static string $resource = DatabaseHostResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
EditAction::make(), EditAction::make(),
]; ];
} }
public function getRelationManagers(): array
{
if (DatabasesRelationManager::canViewForRecord($this->getRecord(), static::class)) {
return [
DatabasesRelationManager::class,
];
}
return [];
}
} }

View File

@ -3,11 +3,19 @@
namespace App\Filament\Admin\Resources; namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\EggResource\Pages; use App\Filament\Admin\Resources\EggResource\Pages;
use App\Filament\Admin\Resources\EggResource\RelationManagers;
use App\Models\Egg; use App\Models\Egg;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
class EggResource extends Resource class EggResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
protected static ?string $model = Egg::class; protected static ?string $model = Egg::class;
protected static ?string $navigationIcon = 'tabler-eggs'; protected static ?string $navigationIcon = 'tabler-eggs';
@ -44,7 +52,16 @@ class EggResource extends Resource
return ['name', 'tags', 'uuid', 'id']; return ['name', 'tags', 'uuid', 'id'];
} }
public static function getPages(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{
return [
RelationManagers\ServersRelationManager::class,
];
}
/** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListEggs::route('/'), 'index' => Pages\ListEggs::route('/'),

View File

@ -6,6 +6,10 @@ use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
use App\Filament\Admin\Resources\EggResource; use App\Filament\Admin\Resources\EggResource;
use App\Filament\Components\Forms\Fields\CopyFrom; use App\Filament\Components\Forms\Fields\CopyFrom;
use App\Models\EggVariable; use App\Models\EggVariable;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
@ -28,11 +32,15 @@ use Illuminate\Validation\Rules\Unique;
class CreateEgg extends CreateRecord class CreateEgg extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = EggResource::class; protected static string $resource = EggResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -4,12 +4,15 @@ namespace App\Filament\Admin\Resources\EggResource\Pages;
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor; use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
use App\Filament\Admin\Resources\EggResource; use App\Filament\Admin\Resources\EggResource;
use App\Filament\Admin\Resources\EggResource\RelationManagers\ServersRelationManager;
use App\Filament\Components\Actions\ExportEggAction; use App\Filament\Components\Actions\ExportEggAction;
use App\Filament\Components\Actions\ImportEggAction; use App\Filament\Components\Actions\ImportEggAction;
use App\Filament\Components\Forms\Fields\CopyFrom; use App\Filament\Components\Forms\Fields\CopyFrom;
use App\Models\Egg; use App\Models\Egg;
use App\Models\EggVariable; use App\Models\EggVariable;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
@ -31,6 +34,9 @@ use Illuminate\Validation\Rules\Unique;
class EditEgg extends EditRecord class EditEgg extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = EggResource::class; protected static string $resource = EggResource::class;
public function form(Form $form): Form public function form(Form $form): Form
@ -251,7 +257,8 @@ class EditEgg extends EditRecord
]); ]);
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make() DeleteAction::make()
@ -273,11 +280,4 @@ class EditEgg extends EditRecord
{ {
return []; return [];
} }
public function getRelationManagers(): array
{
return [
ServersRelationManager::class,
];
}
} }

View File

@ -10,6 +10,10 @@ use App\Filament\Components\Tables\Actions\UpdateEggAction;
use App\Filament\Components\Tables\Actions\UpdateEggBulkAction; use App\Filament\Components\Tables\Actions\UpdateEggBulkAction;
use App\Filament\Components\Tables\Filters\TagsFilter; use App\Filament\Components\Tables\Filters\TagsFilter;
use App\Models\Egg; use App\Models\Egg;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction as CreateHeaderAction; use Filament\Actions\CreateAction as CreateHeaderAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
@ -23,6 +27,9 @@ use Illuminate\Support\Str;
class ListEggs extends ListRecords class ListEggs extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = EggResource::class; protected static string $resource = EggResource::class;
public function table(Table $table): Table public function table(Table $table): Table
@ -95,7 +102,8 @@ class ListEggs extends ListRecords
]); ]);
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
ImportEggHeaderAction::make() ImportEggHeaderAction::make()

View File

@ -4,6 +4,10 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\MountResource\Pages; use App\Filament\Admin\Resources\MountResource\Pages;
use App\Models\Mount; use App\Models\Mount;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Forms\Components\Group; use Filament\Forms\Components\Group;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
@ -11,6 +15,7 @@ use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons; use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\DeleteBulkAction;
@ -22,6 +27,11 @@ use Illuminate\Database\Eloquent\Builder;
class MountResource extends Resource class MountResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = Mount::class; protected static ?string $model = Mount::class;
protected static ?string $navigationIcon = 'tabler-layers-linked'; protected static ?string $navigationIcon = 'tabler-layers-linked';
@ -53,7 +63,7 @@ class MountResource extends Resource
return trans('admin/dashboard.advanced'); return trans('admin/dashboard.advanced');
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -94,7 +104,7 @@ class MountResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->schema([ ->schema([
@ -162,7 +172,8 @@ class MountResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListMounts::route('/'), 'index' => Pages\ListMounts::route('/'),

View File

@ -3,17 +3,25 @@
namespace App\Filament\Admin\Resources\MountResource\Pages; namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource; use App\Filament\Admin\Resources\MountResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class CreateMount extends CreateRecord class CreateMount extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = MountResource::class; protected static string $resource = MountResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\MountResource\Pages; namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource; use App\Filament\Admin\Resources\MountResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
class EditMount extends EditRecord class EditMount extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = MountResource::class; protected static string $resource = MountResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make(), DeleteAction::make(),

View File

@ -4,14 +4,22 @@ namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource; use App\Filament\Admin\Resources\MountResource;
use App\Models\Mount; use App\Models\Mount;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListMounts extends ListRecords class ListMounts extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = MountResource::class; protected static string $resource = MountResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make() CreateAction::make()

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\MountResource\Pages; namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource; use App\Filament\Admin\Resources\MountResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewMount extends ViewRecord class ViewMount extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = MountResource::class; protected static string $resource = MountResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
EditAction::make(), EditAction::make(),

View File

@ -5,11 +5,18 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\NodeResource\Pages; use App\Filament\Admin\Resources\NodeResource\Pages;
use App\Filament\Admin\Resources\NodeResource\RelationManagers; use App\Filament\Admin\Resources\NodeResource\RelationManagers;
use App\Models\Node; use App\Models\Node;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
class NodeResource extends Resource class NodeResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
protected static ?string $model = Node::class; protected static ?string $model = Node::class;
protected static ?string $navigationIcon = 'tabler-server-2'; protected static ?string $navigationIcon = 'tabler-server-2';
@ -41,7 +48,8 @@ class NodeResource extends Resource
return (string) static::getEloquentQuery()->count() ?: null; return (string) static::getEloquentQuery()->count() ?: null;
} }
public static function getRelations(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{ {
return [ return [
RelationManagers\AllocationsRelationManager::class, RelationManagers\AllocationsRelationManager::class,
@ -49,7 +57,8 @@ class NodeResource extends Resource
]; ];
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListNodes::route('/'), 'index' => Pages\ListNodes::route('/'),

View File

@ -4,6 +4,8 @@ namespace App\Filament\Admin\Resources\NodeResource\Pages;
use App\Filament\Admin\Resources\NodeResource; use App\Filament\Admin\Resources\NodeResource;
use App\Models\Node; use App\Models\Node;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Grid; use Filament\Forms\Components\Grid;
@ -21,6 +23,9 @@ use Illuminate\Support\HtmlString;
class CreateNode extends CreateRecord class CreateNode extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = NodeResource::class; protected static string $resource = NodeResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;

View File

@ -8,6 +8,8 @@ use App\Repositories\Daemon\DaemonConfigurationRepository;
use App\Services\Helpers\SoftwareVersionService; use App\Services\Helpers\SoftwareVersionService;
use App\Services\Nodes\NodeAutoDeployService; use App\Services\Nodes\NodeAutoDeployService;
use App\Services\Nodes\NodeUpdateService; use App\Services\Nodes\NodeUpdateService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Exception; use Exception;
use Filament\Actions; use Filament\Actions;
use Filament\Forms; use Filament\Forms;
@ -34,6 +36,9 @@ use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
class EditNode extends EditRecord class EditNode extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = NodeResource::class; protected static string $resource = NodeResource::class;
private DaemonConfigurationRepository $daemonConfigurationRepository; private DaemonConfigurationRepository $daemonConfigurationRepository;
@ -630,7 +635,8 @@ class EditNode extends EditRecord
return []; return [];
} }
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Actions\DeleteAction::make() Actions\DeleteAction::make()

View File

@ -6,6 +6,8 @@ use App\Filament\Admin\Resources\NodeResource;
use App\Filament\Components\Tables\Columns\NodeHealthColumn; use App\Filament\Components\Tables\Columns\NodeHealthColumn;
use App\Filament\Components\Tables\Filters\TagsFilter; use App\Filament\Components\Tables\Filters\TagsFilter;
use App\Models\Node; use App\Models\Node;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
@ -16,6 +18,9 @@ use Filament\Tables\Table;
class ListNodes extends ListRecords class ListNodes extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = NodeResource::class; protected static string $resource = NodeResource::class;
public function table(Table $table): Table public function table(Table $table): Table
@ -73,7 +78,8 @@ class ListNodes extends ListRecords
]); ]);
} }
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()

View File

@ -4,6 +4,10 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\RoleResource\Pages; use App\Filament\Admin\Resources\RoleResource\Pages;
use App\Models\Role; use App\Models\Role;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\Component; use Filament\Forms\Components\Component;
@ -14,6 +18,7 @@ use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Get; use Filament\Forms\Get;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\DeleteBulkAction;
@ -26,6 +31,11 @@ use Spatie\Permission\Contracts\Permission;
class RoleResource extends Resource class RoleResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = Role::class; protected static ?string $model = Role::class;
protected static ?string $navigationIcon = 'tabler-users-group'; protected static ?string $navigationIcon = 'tabler-users-group';
@ -57,7 +67,7 @@ class RoleResource extends Resource
return static::getModel()::count() ?: null; return static::getModel()::count() ?: null;
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -97,7 +107,7 @@ class RoleResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
$permissionSections = []; $permissionSections = [];
@ -200,7 +210,8 @@ class RoleResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListRoles::route('/'), 'index' => Pages\ListRoles::route('/'),

View File

@ -4,6 +4,10 @@ namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource; use App\Filament\Admin\Resources\RoleResource;
use App\Models\Role; use App\Models\Role;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -14,13 +18,17 @@ use Spatie\Permission\Models\Permission;
*/ */
class CreateRole extends CreateRecord class CreateRole extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
public Collection $permissions; public Collection $permissions;
protected static string $resource = RoleResource::class; protected static string $resource = RoleResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -4,6 +4,10 @@ namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource; use App\Filament\Admin\Resources\RoleResource;
use App\Models\Role; use App\Models\Role;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
@ -15,6 +19,9 @@ use Spatie\Permission\Models\Permission;
*/ */
class EditRole extends EditRecord class EditRole extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = RoleResource::class; protected static string $resource = RoleResource::class;
public Collection $permissions; public Collection $permissions;
@ -45,7 +52,8 @@ class EditRole extends EditRecord
$this->record->syncPermissions($permissionModels); $this->record->syncPermissions($permissionModels);
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make() DeleteAction::make()

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\RoleResource\Pages; namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource; use App\Filament\Admin\Resources\RoleResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListRoles extends ListRecords class ListRoles extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = RoleResource::class; protected static string $resource = RoleResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make(), CreateAction::make(),

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\RoleResource\Pages; namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource; use App\Filament\Admin\Resources\RoleResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewRole extends ViewRecord class ViewRole extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = RoleResource::class; protected static string $resource = RoleResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
EditAction::make(), EditAction::make(),

View File

@ -3,15 +3,23 @@
namespace App\Filament\Admin\Resources; namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\ServerResource\Pages; use App\Filament\Admin\Resources\ServerResource\Pages;
use App\Filament\Admin\Resources\ServerResource\RelationManagers;
use App\Models\Mount; use App\Models\Mount;
use App\Models\Server; use App\Models\Server;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Get; use Filament\Forms\Get;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
class ServerResource extends Resource class ServerResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
protected static ?string $model = Server::class; protected static ?string $model = Server::class;
protected static ?string $navigationIcon = 'tabler-brand-docker'; protected static ?string $navigationIcon = 'tabler-brand-docker';
@ -66,7 +74,16 @@ class ServerResource extends Resource
->columnSpanFull(); ->columnSpanFull();
} }
public static function getPages(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{
return [
RelationManagers\AllocationsRelationManager::class,
];
}
/** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListServers::route('/'), 'index' => Pages\ListServers::route('/'),

View File

@ -11,6 +11,8 @@ use App\Services\Allocations\AssignmentService;
use App\Services\Servers\RandomWordService; use App\Services\Servers\RandomWordService;
use App\Services\Servers\ServerCreationService; use App\Services\Servers\ServerCreationService;
use App\Services\Users\UserCreationService; use App\Services\Users\UserCreationService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Closure; use Closure;
use Exception; use Exception;
use Filament\Forms; use Filament\Forms;
@ -45,6 +47,9 @@ use LogicException;
class CreateServer extends CreateRecord class CreateServer extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ServerResource::class; protected static string $resource = ServerResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;

View File

@ -5,7 +5,6 @@ namespace App\Filament\Admin\Resources\ServerResource\Pages;
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor; use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
use App\Enums\SuspendAction; use App\Enums\SuspendAction;
use App\Filament\Admin\Resources\ServerResource; use App\Filament\Admin\Resources\ServerResource;
use App\Filament\Admin\Resources\ServerResource\RelationManagers\AllocationsRelationManager;
use App\Filament\Components\Forms\Actions\PreviewStartupAction; use App\Filament\Components\Forms\Actions\PreviewStartupAction;
use App\Filament\Components\Forms\Actions\RotateDatabasePasswordAction; use App\Filament\Components\Forms\Actions\RotateDatabasePasswordAction;
use App\Filament\Server\Pages\Console; use App\Filament\Server\Pages\Console;
@ -26,6 +25,8 @@ use App\Services\Servers\ServerDeletionService;
use App\Services\Servers\SuspensionService; use App\Services\Servers\SuspensionService;
use App\Services\Servers\ToggleInstallService; use App\Services\Servers\ToggleInstallService;
use App\Services\Servers\TransferServerService; use App\Services\Servers\TransferServerService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Closure; use Closure;
use Exception; use Exception;
use Filament\Actions; use Filament\Actions;
@ -62,6 +63,9 @@ use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
class EditServer extends EditRecord class EditServer extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ServerResource::class; protected static string $resource = ServerResource::class;
private DaemonServerRepository $daemonServerRepository; private DaemonServerRepository $daemonServerRepository;
@ -1033,7 +1037,8 @@ class EditServer extends EditRecord
]; ];
} }
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = $this->getRecord(); $server = $this->getRecord();
@ -1136,13 +1141,6 @@ class EditServer extends EditRecord
return null; return null;
} }
public function getRelationManagers(): array
{
return [
AllocationsRelationManager::class,
];
}
private function shouldHideComponent(ServerVariable $serverVariable, Forms\Components\Component $component): bool private function shouldHideComponent(ServerVariable $serverVariable, Forms\Components\Component $component): bool
{ {
$containsRuleIn = array_first($serverVariable->variable->rules, fn ($value) => str($value)->startsWith('in:'), false); $containsRuleIn = array_first($serverVariable->variable->rules, fn ($value) => str($value)->startsWith('in:'), false);

View File

@ -5,6 +5,8 @@ namespace App\Filament\Admin\Resources\ServerResource\Pages;
use App\Filament\Server\Pages\Console; use App\Filament\Server\Pages\Console;
use App\Filament\Admin\Resources\ServerResource; use App\Filament\Admin\Resources\ServerResource;
use App\Models\Server; use App\Models\Server;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\Action; use Filament\Tables\Actions\Action;
@ -17,6 +19,9 @@ use Filament\Tables\Table;
class ListServers extends ListRecords class ListServers extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ServerResource::class; protected static string $resource = ServerResource::class;
public function table(Table $table): Table public function table(Table $table): Table
@ -101,7 +106,8 @@ class ListServers extends ListRecords
]); ]);
} }
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make() Actions\CreateAction::make()

View File

@ -6,10 +6,16 @@ use App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource\RelationManagers; use App\Filament\Admin\Resources\UserResource\RelationManagers;
use App\Models\Role; use App\Models\Role;
use App\Models\User; use App\Models\User;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction; use Filament\Tables\Actions\EditAction;
@ -22,6 +28,11 @@ use Illuminate\Database\Eloquent\Builder;
class UserResource extends Resource class UserResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = User::class; protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'tabler-users'; protected static ?string $navigationIcon = 'tabler-users';
@ -53,7 +64,7 @@ class UserResource extends Resource
return static::getModel()::count() ?: null; return static::getModel()::count() ?: null;
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -99,7 +110,7 @@ class UserResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->columns(['default' => 1, 'lg' => 3]) ->columns(['default' => 1, 'lg' => 3])
@ -146,14 +157,16 @@ class UserResource extends Resource
]); ]);
} }
public static function getRelations(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{ {
return [ return [
RelationManagers\ServersRelationManager::class, RelationManagers\ServersRelationManager::class,
]; ];
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListUsers::route('/'), 'index' => Pages\ListUsers::route('/'),

View File

@ -5,11 +5,18 @@ namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource; use App\Filament\Admin\Resources\UserResource;
use App\Models\Role; use App\Models\Role;
use App\Services\Users\UserCreationService; use App\Services\Users\UserCreationService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class CreateUser extends CreateRecord class CreateUser extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = UserResource::class; protected static string $resource = UserResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
@ -21,7 +28,8 @@ class CreateUser extends CreateRecord
$this->service = $service; $this->service = $service;
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -5,12 +5,19 @@ namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource; use App\Filament\Admin\Resources\UserResource;
use App\Models\User; use App\Models\User;
use App\Services\Users\UserUpdateService; use App\Services\Users\UserUpdateService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class EditUser extends EditRecord class EditUser extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = UserResource::class; protected static string $resource = UserResource::class;
private UserUpdateService $service; private UserUpdateService $service;
@ -20,7 +27,8 @@ class EditUser extends EditRecord
$this->service = $service; $this->service = $service;
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make() DeleteAction::make()

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\UserResource\Pages; namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource; use App\Filament\Admin\Resources\UserResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords class ListUsers extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = UserResource::class; protected static string $resource = UserResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make(), CreateAction::make(),

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\UserResource\Pages; namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource; use App\Filament\Admin\Resources\UserResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewUser extends ViewRecord class ViewUser extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = UserResource::class; protected static string $resource = UserResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
EditAction::make(), EditAction::make(),

View File

@ -4,9 +4,14 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\WebhookResource\Pages; use App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Models\WebhookConfiguration; use App\Models\WebhookConfiguration;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteAction; use Filament\Tables\Actions\DeleteAction;
@ -18,6 +23,11 @@ use Filament\Tables\Table;
class WebhookResource extends Resource class WebhookResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = WebhookConfiguration::class; protected static ?string $model = WebhookConfiguration::class;
protected static ?string $navigationIcon = 'tabler-webhook'; protected static ?string $navigationIcon = 'tabler-webhook';
@ -49,7 +59,7 @@ class WebhookResource extends Resource
return trans('admin/dashboard.advanced'); return trans('admin/dashboard.advanced');
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -75,7 +85,7 @@ class WebhookResource extends Resource
]); ]);
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->schema([ ->schema([
@ -98,7 +108,8 @@ class WebhookResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListWebhookConfigurations::route('/'), 'index' => Pages\ListWebhookConfigurations::route('/'),

View File

@ -3,15 +3,23 @@
namespace App\Filament\Admin\Resources\WebhookResource\Pages; namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource; use App\Filament\Admin\Resources\WebhookResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateWebhookConfiguration extends CreateRecord class CreateWebhookConfiguration extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = WebhookResource::class; protected static string $resource = WebhookResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getCreateFormAction()->formId('form'), $this->getCreateFormAction()->formId('form'),

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\WebhookResource\Pages; namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource; use App\Filament\Admin\Resources\WebhookResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
class EditWebhookConfiguration extends EditRecord class EditWebhookConfiguration extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = WebhookResource::class; protected static string $resource = WebhookResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
DeleteAction::make(), DeleteAction::make(),

View File

@ -4,14 +4,22 @@ namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource; use App\Filament\Admin\Resources\WebhookResource;
use App\Models\WebhookConfiguration; use App\Models\WebhookConfiguration;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListWebhookConfigurations extends ListRecords class ListWebhookConfigurations extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = WebhookResource::class; protected static string $resource = WebhookResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make() CreateAction::make()

View File

@ -3,14 +3,22 @@
namespace App\Filament\Admin\Resources\WebhookResource\Pages; namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource; use App\Filament\Admin\Resources\WebhookResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewWebhookConfiguration extends ViewRecord class ViewWebhookConfiguration extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = WebhookResource::class; protected static string $resource = WebhookResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
EditAction::make(), EditAction::make(),

View File

@ -2,15 +2,13 @@
namespace App\Filament\Admin\Widgets; namespace App\Filament\Admin\Widgets;
use Filament\Actions\CreateAction; use Filament\Forms\Components\Actions\Action;
use Filament\Widgets\Widget; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
class CanaryWidget extends Widget class CanaryWidget extends FormWidget
{ {
protected static string $view = 'filament.admin.widgets.canary-widget';
protected static bool $isLazy = false;
protected static ?int $sort = 1; protected static ?int $sort = 1;
public static function canView(): bool public static function canView(): bool
@ -18,15 +16,28 @@ class CanaryWidget extends Widget
return config('app.version') === 'canary'; return config('app.version') === 'canary';
} }
public function getViewData(): array public function form(Form $form): Form
{ {
return [ return $form
'actions' => [ ->schema([
CreateAction::make() Section::make(trans('admin/dashboard.sections.intro-developers.heading'))
->label(trans('admin/dashboard.sections.intro-developers.button_issues')) ->icon('tabler-code')
->icon('tabler-brand-github') ->iconColor('primary')
->url('https://github.com/pelican-dev/panel/issues', true), ->collapsible()
], ->collapsed()
]; ->persistCollapsed()
->schema([
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-developers.content')),
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-developers.extra_note')),
])
->headerActions([
Action::make('issues')
->label(trans('admin/dashboard.sections.intro-developers.button_issues'))
->icon('tabler-brand-github')
->url('https://github.com/pelican-dev/panel/issues', true),
]),
]);
} }
} }

View File

@ -0,0 +1,16 @@
<?php
namespace App\Filament\Admin\Widgets;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Widgets\Widget;
abstract class FormWidget extends Widget implements HasForms
{
use InteractsWithForms;
protected static bool $isLazy = false;
protected static string $view = 'filament.admin.widgets.form-widget';
}

View File

@ -2,26 +2,34 @@
namespace App\Filament\Admin\Widgets; namespace App\Filament\Admin\Widgets;
use Filament\Actions\CreateAction; use Filament\Forms\Components\Actions\Action;
use Filament\Widgets\Widget; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
class HelpWidget extends Widget class HelpWidget extends FormWidget
{ {
protected static string $view = 'filament.admin.widgets.help-widget';
protected static bool $isLazy = false;
protected static ?int $sort = 4; protected static ?int $sort = 4;
public function getViewData(): array public function form(Form $form): Form
{ {
return [ return $form
'actions' => [ ->schema([
CreateAction::make() Section::make(trans('admin/dashboard.sections.intro-help.heading'))
->label(trans('admin/dashboard.sections.intro-help.button_docs')) ->icon('tabler-question-mark')
->icon('tabler-speedboat') ->iconColor('info')
->url('https://pelican.dev/docs', true), ->collapsible()
], ->persistCollapsed()
]; ->schema([
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-help.content')),
])
->headerActions([
Action::make('docs')
->label(trans('admin/dashboard.sections.intro-help.button_docs'))
->icon('tabler-speedboat')
->url('https://pelican.dev/docs', true),
]),
]);
} }
} }

View File

@ -4,15 +4,13 @@ namespace App\Filament\Admin\Widgets;
use App\Filament\Admin\Resources\NodeResource\Pages\CreateNode; use App\Filament\Admin\Resources\NodeResource\Pages\CreateNode;
use App\Models\Node; use App\Models\Node;
use Filament\Actions\CreateAction; use Filament\Forms\Components\Actions\Action;
use Filament\Widgets\Widget; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
class NoNodesWidget extends Widget class NoNodesWidget extends FormWidget
{ {
protected static string $view = 'filament.admin.widgets.no-nodes-widget';
protected static bool $isLazy = false;
protected static ?int $sort = 2; protected static ?int $sort = 2;
public static function canView(): bool public static function canView(): bool
@ -20,15 +18,25 @@ class NoNodesWidget extends Widget
return Node::count() <= 0; return Node::count() <= 0;
} }
public function getViewData(): array public function form(Form $form): Form
{ {
return [ return $form
'actions' => [ ->schema([
CreateAction::make() Section::make(trans('admin/dashboard.sections.intro-first-node.heading'))
->label(trans('admin/dashboard.sections.intro-first-node.button_label'))
->icon('tabler-server-2') ->icon('tabler-server-2')
->url(CreateNode::getUrl()), ->iconColor('primary')
], ->collapsible()
]; ->persistCollapsed()
->schema([
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-first-node.content')),
])
->headerActions([
Action::make('create-node')
->label(trans('admin/dashboard.sections.intro-first-node.button_label'))
->icon('tabler-server-2')
->url(CreateNode::getUrl()),
]),
]);
} }
} }

View File

@ -2,27 +2,37 @@
namespace App\Filament\Admin\Widgets; namespace App\Filament\Admin\Widgets;
use Filament\Actions\CreateAction; use Filament\Forms\Components\Actions\Action;
use Filament\Widgets\Widget; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
class SupportWidget extends Widget class SupportWidget extends FormWidget
{ {
protected static string $view = 'filament.admin.widgets.support-widget';
protected static bool $isLazy = false;
protected static ?int $sort = 3; protected static ?int $sort = 3;
public function getViewData(): array public function form(Form $form): Form
{ {
return [ return $form
'actions' => [ ->schema([
CreateAction::make() Section::make(trans('admin/dashboard.sections.intro-support.heading'))
->label(trans('admin/dashboard.sections.intro-support.button_donate')) ->icon('tabler-heart-filled')
->icon('tabler-cash') ->iconColor('danger')
->url('https://pelican.dev/donate', true) ->collapsible()
->color('success'), ->persistCollapsed()
], ->schema([
]; Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-support.content')),
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-support.extra_note')),
])
->headerActions([
Action::make('donate')
->label(trans('admin/dashboard.sections.intro-support.button_donate'))
->icon('tabler-cash')
->url('https://pelican.dev/donate', true)
->color('success'),
]),
]);
} }
} }

View File

@ -3,15 +3,13 @@
namespace App\Filament\Admin\Widgets; namespace App\Filament\Admin\Widgets;
use App\Services\Helpers\SoftwareVersionService; use App\Services\Helpers\SoftwareVersionService;
use Filament\Actions\CreateAction; use Filament\Forms\Components\Actions\Action;
use Filament\Widgets\Widget; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Form;
class UpdateWidget extends Widget class UpdateWidget extends FormWidget
{ {
protected static string $view = 'filament.admin.widgets.update-widget';
protected static bool $isLazy = false;
protected static ?int $sort = 0; protected static ?int $sort = 0;
private SoftwareVersionService $softwareVersionService; private SoftwareVersionService $softwareVersionService;
@ -21,19 +19,34 @@ class UpdateWidget extends Widget
$this->softwareVersionService = $softwareVersionService; $this->softwareVersionService = $softwareVersionService;
} }
public function getViewData(): array public function form(Form $form): Form
{ {
return [ $isLatest = $this->softwareVersionService->isLatestPanel();
'version' => $this->softwareVersionService->currentPanelVersion(),
'latestVersion' => $this->softwareVersionService->latestPanelVersion(), return $form
'isLatest' => $this->softwareVersionService->isLatestPanel(), ->schema([
'actions' => [ $isLatest
CreateAction::make() ? Section::make(trans('admin/dashboard.sections.intro-no-update.heading'))
->label(trans('admin/dashboard.sections.intro-update-available.heading')) ->icon('tabler-checkbox')
->icon('tabler-clipboard-text') ->iconColor('success')
->url('https://pelican.dev/docs/panel/update', true) ->schema([
->color('warning'), Placeholder::make('')
], ->content(trans('admin/dashboard.sections.intro-no-update.content', ['version' => $this->softwareVersionService->currentPanelVersion()])),
]; ])
: Section::make(trans('admin/dashboard.sections.intro-update-available.heading'))
->icon('tabler-info-circle')
->iconColor('warning')
->schema([
Placeholder::make('')
->content(trans('admin/dashboard.sections.intro-update-available.content', ['latestVersion' => $this->softwareVersionService->latestPanelVersion()])),
])
->headerActions([
Action::make('update')
->label(trans('admin/dashboard.sections.intro-update-available.heading'))
->icon('tabler-clipboard-text')
->url('https://pelican.dev/docs/panel/update', true)
->color('warning'),
]),
]);
} }
} }

View File

@ -9,6 +9,8 @@ use App\Filament\Server\Pages\Console;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Repositories\Daemon\DaemonPowerRepository; use App\Repositories\Daemon\DaemonPowerRepository;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Components\Tab; use Filament\Resources\Components\Tab;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
@ -26,6 +28,9 @@ use Livewire\Attributes\On;
class ListServers extends ListRecords class ListServers extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ServerResource::class; protected static string $resource = ServerResource::class;
public const DANGER_THRESHOLD = 0.9; public const DANGER_THRESHOLD = 0.9;

View File

@ -12,11 +12,15 @@ use App\Services\Helpers\LanguageService;
use App\Services\Users\ToggleTwoFactorService; use App\Services\Users\ToggleTwoFactorService;
use App\Services\Users\TwoFactorSetupService; use App\Services\Users\TwoFactorSetupService;
use App\Services\Users\UserUpdateService; use App\Services\Users\UserUpdateService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use chillerlan\QRCode\Common\EccLevel; use chillerlan\QRCode\Common\EccLevel;
use chillerlan\QRCode\Common\Version; use chillerlan\QRCode\Common\Version;
use chillerlan\QRCode\QRCode; use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions; use chillerlan\QRCode\QROptions;
use DateTimeZone; use DateTimeZone;
use Filament\Actions\Action as HeaderAction;
use Filament\Actions\ActionGroup;
use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\FileUpload;
@ -51,6 +55,9 @@ use Laravel\Socialite\Facades\Socialite;
*/ */
class EditProfile extends BaseEditProfile class EditProfile extends BaseEditProfile
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
private ToggleTwoFactorService $toggleTwoFactorService; private ToggleTwoFactorService $toggleTwoFactorService;
protected OAuthService $oauthService; protected OAuthService $oauthService;
@ -508,7 +515,8 @@ class EditProfile extends BaseEditProfile
return []; return [];
} }
protected function getHeaderActions(): array /** @return array<HeaderAction|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
$this->getSaveFormAction()->formId('form'), $this->getSaveFormAction()->formId('form'),

View File

@ -14,9 +14,11 @@ use App\Filament\Server\Widgets\ServerOverview;
use App\Livewire\AlertBanner; use App\Livewire\AlertBanner;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use Filament\Actions\Action; use App\Traits\Filament\CanCustomizeHeaderActions;
use Filament\Actions\Concerns\InteractsWithActions; use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Pages\Page; use Filament\Pages\Page;
use Filament\Support\Enums\ActionSize; use Filament\Support\Enums\ActionSize;
use Filament\Widgets\Widget; use Filament\Widgets\Widget;
@ -25,6 +27,7 @@ use Livewire\Attributes\On;
class Console extends Page class Console extends Page
{ {
use CanCustomizeHeaderActions;
use InteractsWithActions; use InteractsWithActions;
protected static ?string $navigationIcon = 'tabler-brand-tabler'; protected static ?string $navigationIcon = 'tabler-brand-tabler';
@ -147,7 +150,8 @@ class Console extends Page
$this->cacheHeaderActions(); $this->cacheHeaderActions();
} }
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -3,6 +3,9 @@
namespace App\Filament\Server\Pages; namespace App\Filament\Server\Pages;
use App\Models\Server; use App\Models\Server;
use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Concerns\InteractsWithForms; use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form; use Filament\Forms\Form;
@ -14,6 +17,9 @@ use Filament\Pages\Page;
*/ */
abstract class ServerFormPage extends Page abstract class ServerFormPage extends Page
{ {
use BlockAccessInConflict;
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
use InteractsWithFormActions; use InteractsWithFormActions;
use InteractsWithForms; use InteractsWithForms;
@ -64,17 +70,4 @@ abstract class ServerFormPage extends Page
return $server; return $server;
} }
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
} }

View File

@ -10,12 +10,16 @@ use App\Models\Permission;
use App\Models\Role; use App\Models\Role;
use App\Models\Server; use App\Models\Server;
use App\Models\User; use App\Models\User;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyTable;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\ViewAction; use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
@ -28,6 +32,10 @@ use Illuminate\Support\HtmlString;
class ActivityResource extends Resource class ActivityResource extends Resource
{ {
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyTable;
protected static ?string $model = ActivityLog::class; protected static ?string $model = ActivityLog::class;
protected static ?string $modelLabel = 'Activity'; protected static ?string $modelLabel = 'Activity';
@ -38,7 +46,7 @@ class ActivityResource extends Resource
protected static ?string $navigationIcon = 'tabler-stack'; protected static ?string $navigationIcon = 'tabler-stack';
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
@ -122,11 +130,6 @@ class ActivityResource extends Resource
]); ]);
} }
public static function canViewAny(): bool
{
return auth()->user()->can(Permission::ACTION_ACTIVITY_READ, Filament::getTenant());
}
public static function getEloquentQuery(): Builder public static function getEloquentQuery(): Builder
{ {
/** @var Server $server */ /** @var Server $server */
@ -153,7 +156,13 @@ class ActivityResource extends Resource
}); });
} }
public static function getPages(): array public static function canViewAny(): bool
{
return auth()->user()->can(Permission::ACTION_ACTIVITY_READ, Filament::getTenant());
}
/** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListActivities::route('/'), 'index' => Pages\ListActivities::route('/'),

View File

@ -3,10 +3,15 @@
namespace App\Filament\Server\Resources\ActivityResource\Pages; namespace App\Filament\Server\Resources\ActivityResource\Pages;
use App\Filament\Server\Resources\ActivityResource; use App\Filament\Server\Resources\ActivityResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListActivities extends ListRecords class ListActivities extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ActivityResource::class; protected static string $resource = ActivityResource::class;
public function getBreadcrumbs(): array public function getBreadcrumbs(): array

View File

@ -7,7 +7,12 @@ use App\Filament\Server\Resources\AllocationResource\Pages;
use App\Models\Allocation; use App\Models\Allocation;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyTable;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\DetachAction; use Filament\Tables\Actions\DetachAction;
use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\IconColumn;
@ -18,6 +23,11 @@ use Illuminate\Database\Eloquent\Model;
class AllocationResource extends Resource class AllocationResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyTable;
protected static ?string $model = Allocation::class; protected static ?string $model = Allocation::class;
protected static ?string $modelLabel = 'Network'; protected static ?string $modelLabel = 'Network';
@ -28,7 +38,7 @@ class AllocationResource extends Resource
protected static ?string $navigationIcon = 'tabler-network'; protected static ?string $navigationIcon = 'tabler-network';
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
@ -83,19 +93,6 @@ class AllocationResource extends Resource
]); ]);
} }
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
public static function canViewAny(): bool public static function canViewAny(): bool
{ {
return auth()->user()->can(Permission::ACTION_ALLOCATION_READ, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_ALLOCATION_READ, Filament::getTenant());
@ -116,7 +113,8 @@ class AllocationResource extends Resource
return auth()->user()->can(Permission::ACTION_ALLOCATION_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_ALLOCATION_DELETE, Filament::getTenant());
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListAllocations::route('/'), 'index' => Pages\ListAllocations::route('/'),

View File

@ -7,15 +7,22 @@ use App\Filament\Server\Resources\AllocationResource;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Services\Allocations\FindAssignableAllocationService; use App\Services\Allocations\FindAssignableAllocationService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListAllocations extends ListRecords class ListAllocations extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = AllocationResource::class; protected static string $resource = AllocationResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -15,6 +15,12 @@ use App\Services\Backups\DownloadLinkService;
use App\Filament\Components\Tables\Columns\BytesColumn; use App\Filament\Components\Tables\Columns\BytesColumn;
use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Services\Backups\DeleteBackupService; use App\Services\Backups\DeleteBackupService;
use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use App\Traits\Filament\HasLimitBadge;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Placeholder;
@ -23,6 +29,7 @@ use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle; use Filament\Forms\Components\Toggle;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\Action; use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\ActionGroup; use Filament\Tables\Actions\ActionGroup;
@ -36,6 +43,13 @@ use Illuminate\Http\Request;
class BackupResource extends Resource class BackupResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
use HasLimitBadge;
protected static ?string $model = Backup::class; protected static ?string $model = Backup::class;
protected static ?int $navigationSort = 3; protected static ?int $navigationSort = 3;
@ -44,34 +58,23 @@ class BackupResource extends Resource
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;
public const WARNING_THRESHOLD = 0.7; protected static function getBadgeCount(): int
public static function getNavigationBadge(): string
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
$limit = $server->backup_limit; return $server->backups->count();
return $server->backups->count() . ($limit === 0 ? '' : ' / ' . $limit);
} }
public static function getNavigationBadgeColor(): ?string protected static function getBadgeLimit(): int
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
$limit = $server->backup_limit; return $server->backup_limit;
$count = $server->backups->count();
if ($limit === 0) {
return null;
}
return $count >= $limit ? 'danger' : ($count >= $limit * self::WARNING_THRESHOLD ? 'warning' : 'success');
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->schema([ ->schema([
@ -87,7 +90,7 @@ class BackupResource extends Resource
]); ]);
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
@ -202,19 +205,6 @@ class BackupResource extends Resource
]); ]);
} }
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
public static function canViewAny(): bool public static function canViewAny(): bool
{ {
return auth()->user()->can(Permission::ACTION_BACKUP_READ, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_BACKUP_READ, Filament::getTenant());
@ -230,7 +220,8 @@ class BackupResource extends Resource
return auth()->user()->can(Permission::ACTION_BACKUP_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_BACKUP_DELETE, Filament::getTenant());
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListBackups::route('/'), 'index' => Pages\ListBackups::route('/'),

View File

@ -7,6 +7,10 @@ use App\Filament\Server\Resources\BackupResource;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Services\Backups\InitiateBackupService; use App\Services\Backups\InitiateBackupService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
@ -15,9 +19,13 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
class ListBackups extends ListRecords class ListBackups extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = BackupResource::class; protected static string $resource = BackupResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -9,9 +9,16 @@ use App\Models\Database;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Services\Databases\DatabaseManagementService; use App\Services\Databases\DatabaseManagementService;
use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use App\Traits\Filament\HasLimitBadge;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\DeleteAction; use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\ViewAction; use Filament\Tables\Actions\ViewAction;
@ -22,40 +29,36 @@ use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
class DatabaseResource extends Resource class DatabaseResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
use HasLimitBadge;
protected static ?string $model = Database::class; protected static ?string $model = Database::class;
protected static ?int $navigationSort = 6; protected static ?int $navigationSort = 6;
protected static ?string $navigationIcon = 'tabler-database'; protected static ?string $navigationIcon = 'tabler-database';
public const WARNING_THRESHOLD = 0.7; protected static function getBadgeCount(): int
public static function getNavigationBadge(): string
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
$limit = $server->database_limit; return $server->databases->count();
return $server->databases->count() . ($limit === 0 ? '' : ' / ' . $limit);
} }
public static function getNavigationBadgeColor(): ?string protected static function getBadgeLimit(): int
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
$limit = $server->database_limit; return $server->database_limit;
$count = $server->databases->count();
if ($limit === 0) {
return null;
}
return $count >= $limit ? 'danger' : ($count >= $limit * self::WARNING_THRESHOLD ? 'warning' : 'success');
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
@ -92,7 +95,7 @@ class DatabaseResource extends Resource
]); ]);
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -113,19 +116,6 @@ class DatabaseResource extends Resource
]); ]);
} }
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
public static function canViewAny(): bool public static function canViewAny(): bool
{ {
return auth()->user()->can(Permission::ACTION_DATABASE_READ, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_DATABASE_READ, Filament::getTenant());
@ -151,7 +141,8 @@ class DatabaseResource extends Resource
return auth()->user()->can(Permission::ACTION_DATABASE_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_DATABASE_DELETE, Filament::getTenant());
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListDatabases::route('/'), 'index' => Pages\ListDatabases::route('/'),

View File

@ -6,6 +6,10 @@ use App\Filament\Server\Resources\DatabaseResource;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use App\Models\Server; use App\Models\Server;
use App\Services\Databases\DatabaseManagementService; use App\Services\Databases\DatabaseManagementService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Grid; use Filament\Forms\Components\Grid;
@ -15,9 +19,13 @@ use Filament\Resources\Pages\ListRecords;
class ListDatabases extends ListRecords class ListDatabases extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = DatabaseResource::class; protected static string $resource = DatabaseResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -5,32 +5,26 @@ namespace App\Filament\Server\Resources;
use App\Filament\Server\Resources\FileResource\Pages; use App\Filament\Server\Resources\FileResource\Pages;
use App\Models\File; use App\Models\File;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class FileResource extends Resource class FileResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
protected static ?string $model = File::class; protected static ?string $model = File::class;
protected static ?int $navigationSort = 2; protected static ?int $navigationSort = 2;
protected static ?string $navigationIcon = 'tabler-files'; protected static ?string $navigationIcon = 'tabler-files';
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
public static function canViewAny(): bool public static function canViewAny(): bool
{ {
return auth()->user()->can(Permission::ACTION_FILE_READ, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_FILE_READ, Filament::getTenant());
@ -51,7 +45,8 @@ class FileResource extends Resource
return auth()->user()->can(Permission::ACTION_FILE_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_FILE_DELETE, Filament::getTenant());
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'edit' => Pages\EditFiles::route('/edit/{path}'), 'edit' => Pages\EditFiles::route('/edit/{path}'),

View File

@ -12,6 +12,8 @@ use App\Livewire\AlertBanner;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Repositories\Daemon\DaemonFileRepository; use App\Repositories\Daemon\DaemonFileRepository;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
@ -37,6 +39,8 @@ use Livewire\Attributes\Locked;
*/ */
class EditFiles extends Page class EditFiles extends Page
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
use InteractsWithFormActions; use InteractsWithFormActions;
use InteractsWithForms; use InteractsWithForms;

View File

@ -12,7 +12,10 @@ use App\Models\Server;
use App\Repositories\Daemon\DaemonFileRepository; use App\Repositories\Daemon\DaemonFileRepository;
use App\Filament\Components\Tables\Columns\BytesColumn; use App\Filament\Components\Tables\Columns\BytesColumn;
use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action as HeaderAction; use Filament\Actions\Action as HeaderAction;
use Filament\Actions\ActionGroup as HeaderActionGroup;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\FileUpload;
@ -43,6 +46,9 @@ use Livewire\Attributes\Locked;
class ListFiles extends ListRecords class ListFiles extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = FileResource::class; protected static string $resource = FileResource::class;
#[Locked] #[Locked]
@ -399,7 +405,8 @@ class ListFiles extends ListRecords
]); ]);
} }
protected function getHeaderActions(): array /** @return array<HeaderAction|HeaderActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -7,6 +7,8 @@ use App\Models\File;
use App\Models\Server; use App\Models\Server;
use App\Filament\Components\Tables\Columns\BytesColumn; use App\Filament\Components\Tables\Columns\BytesColumn;
use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
@ -16,6 +18,9 @@ use Livewire\Attributes\Url;
class SearchFiles extends ListRecords class SearchFiles extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = FileResource::class; protected static string $resource = FileResource::class;
protected static ?string $title = 'Global Search'; protected static ?string $title = 'Global Search';

View File

@ -9,7 +9,11 @@ use App\Filament\Server\Resources\ScheduleResource\RelationManagers\TasksRelatio
use App\Helpers\Utilities; use App\Helpers\Utilities;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Schedule; use App\Models\Schedule;
use App\Models\Server; use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyForm;
use App\Traits\Filament\CanModifyTable;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Filament\Facades\Filament; use Filament\Facades\Filament;
@ -23,6 +27,8 @@ use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Set; use Filament\Forms\Set;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Support\Exceptions\Halt; use Filament\Support\Exceptions\Halt;
use Filament\Tables\Actions\DeleteAction; use Filament\Tables\Actions\DeleteAction;
@ -35,25 +41,18 @@ use Illuminate\Database\Eloquent\Model;
class ScheduleResource extends Resource class ScheduleResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyForm;
use CanModifyTable;
protected static ?string $model = Schedule::class; protected static ?string $model = Schedule::class;
protected static ?int $navigationSort = 4; protected static ?int $navigationSort = 4;
protected static ?string $navigationIcon = 'tabler-clock'; protected static ?string $navigationIcon = 'tabler-clock';
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
public static function canViewAny(): bool public static function canViewAny(): bool
{ {
return auth()->user()->can(Permission::ACTION_SCHEDULE_READ, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_SCHEDULE_READ, Filament::getTenant());
@ -74,7 +73,7 @@ class ScheduleResource extends Resource
return auth()->user()->can(Permission::ACTION_SCHEDULE_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_SCHEDULE_DELETE, Filament::getTenant());
} }
public static function form(Form $form): Form public static function defaultForm(Form $form): Form
{ {
return $form return $form
->columns([ ->columns([
@ -311,7 +310,7 @@ class ScheduleResource extends Resource
]); ]);
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
@ -349,14 +348,16 @@ class ScheduleResource extends Resource
]); ]);
} }
public static function getRelations(): array /** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{ {
return [ return [
TasksRelationManager::class, TasksRelationManager::class,
]; ];
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListSchedules::route('/'), 'index' => Pages\ListSchedules::route('/'),

View File

@ -6,11 +6,16 @@ use App\Facades\Activity;
use App\Filament\Server\Resources\ScheduleResource; use App\Filament\Server\Resources\ScheduleResource;
use App\Models\Schedule; use App\Models\Schedule;
use App\Models\Server; use App\Models\Server;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateSchedule extends CreateRecord class CreateSchedule extends CreateRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ScheduleResource::class; protected static string $resource = ScheduleResource::class;
protected static bool $canCreateAnother = false; protected static bool $canCreateAnother = false;

View File

@ -5,11 +5,16 @@ namespace App\Filament\Server\Resources\ScheduleResource\Pages;
use App\Facades\Activity; use App\Facades\Activity;
use App\Filament\Server\Resources\ScheduleResource; use App\Filament\Server\Resources\ScheduleResource;
use App\Models\Schedule; use App\Models\Schedule;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
class EditSchedule extends EditRecord class EditSchedule extends EditRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ScheduleResource::class; protected static string $resource = ScheduleResource::class;
protected function afterSave(): void protected function afterSave(): void
@ -35,7 +40,8 @@ class EditSchedule extends EditRecord
return $data; return $data;
} }
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Actions\DeleteAction::make() Actions\DeleteAction::make()

View File

@ -3,14 +3,22 @@
namespace App\Filament\Server\Resources\ScheduleResource\Pages; namespace App\Filament\Server\Resources\ScheduleResource\Pages;
use App\Filament\Server\Resources\ScheduleResource; use App\Filament\Server\Resources\ScheduleResource;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\CreateAction; use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
class ListSchedules extends ListRecords class ListSchedules extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ScheduleResource::class; protected static string $resource = ScheduleResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
CreateAction::make() CreateAction::make()

View File

@ -7,16 +7,23 @@ use App\Filament\Server\Resources\ScheduleResource;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Schedule; use App\Models\Schedule;
use App\Services\Schedules\ProcessScheduleService; use App\Services\Schedules\ProcessScheduleService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Resources\Pages\ViewRecord; use Filament\Resources\Pages\ViewRecord;
class ViewSchedule extends ViewRecord class ViewSchedule extends ViewRecord
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = ScheduleResource::class; protected static string $resource = ScheduleResource::class;
protected function getHeaderActions(): array /** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
return [ return [
Action::make('runNow') Action::make('runNow')

View File

@ -8,6 +8,11 @@ use App\Models\Server;
use App\Models\User; use App\Models\User;
use App\Services\Subusers\SubuserDeletionService; use App\Services\Subusers\SubuserDeletionService;
use App\Services\Subusers\SubuserUpdateService; use App\Services\Subusers\SubuserUpdateService;
use App\Traits\Filament\BlockAccessInConflict;
use App\Traits\Filament\CanCustomizePages;
use App\Traits\Filament\CanCustomizeRelations;
use App\Traits\Filament\CanModifyTable;
use App\Traits\Filament\HasLimitBadge;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
@ -19,6 +24,7 @@ use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Set; use Filament\Forms\Set;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables\Actions\DeleteAction; use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction; use Filament\Tables\Actions\EditAction;
@ -29,6 +35,12 @@ use Illuminate\Database\Eloquent\Model;
class UserResource extends Resource class UserResource extends Resource
{ {
use BlockAccessInConflict;
use CanCustomizePages;
use CanCustomizeRelations;
use CanModifyTable;
use HasLimitBadge;
protected static ?string $model = User::class; protected static ?string $model = User::class;
protected static ?int $navigationSort = 5; protected static ?int $navigationSort = 5;
@ -37,25 +49,12 @@ class UserResource extends Resource
protected static ?string $tenantOwnershipRelationshipName = 'subServers'; protected static ?string $tenantOwnershipRelationshipName = 'subServers';
public static function getNavigationBadge(): string protected static function getBadgeCount(): int
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
return (string) $server->subusers->count(); return $server->subusers->count();
}
// TODO: find better way handle server conflict state
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
} }
public static function canViewAny(): bool public static function canViewAny(): bool
@ -78,7 +77,7 @@ class UserResource extends Resource
return auth()->user()->can(Permission::ACTION_USER_DELETE, Filament::getTenant()); return auth()->user()->can(Permission::ACTION_USER_DELETE, Filament::getTenant());
} }
public static function table(Table $table): Table public static function defaultTable(Table $table): Table
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();
@ -225,7 +224,8 @@ class UserResource extends Resource
]); ]);
} }
public static function getPages(): array /** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{ {
return [ return [
'index' => Pages\ListUsers::route('/'), 'index' => Pages\ListUsers::route('/'),

View File

@ -7,6 +7,8 @@ use App\Filament\Server\Resources\UserResource;
use App\Models\Permission; use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Services\Subusers\SubuserCreationService; use App\Services\Subusers\SubuserCreationService;
use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Exception; use Exception;
use Filament\Actions; use Filament\Actions;
use Filament\Facades\Filament; use Filament\Facades\Filament;
@ -25,9 +27,13 @@ use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords class ListUsers extends ListRecords
{ {
use CanCustomizeHeaderActions;
use CanCustomizeHeaderWidgets;
protected static string $resource = UserResource::class; protected static string $resource = UserResource::class;
protected function getHeaderActions(): array /** @return array<Actions\Action|Actions\ActionGroup> */
protected function getDefaultHeaderActions(): array
{ {
/** @var Server $server */ /** @var Server $server */
$server = Filament::getTenant(); $server = Filament::getTenant();

View File

@ -34,13 +34,14 @@ class SettingsController extends ClientApiController
*/ */
public function rename(RenameServerRequest $request, Server $server): JsonResponse public function rename(RenameServerRequest $request, Server $server): JsonResponse
{ {
$originalName = $server->name;
$name = $request->input('name'); $name = $request->input('name');
$server->update(['name' => $name]); $server->update(['name' => $name]);
if ($server->wasChanged('name')) { if ($server->wasChanged('name')) {
Activity::event('server:settings.rename') Activity::event('server:settings.rename')
->property(['old' => $server->getOriginal('name'), 'new' => $name]) ->property(['old' => $originalName, 'new' => $name])
->log(); ->log();
} }
@ -56,12 +57,13 @@ class SettingsController extends ClientApiController
return new JsonResponse([], Response::HTTP_FORBIDDEN); return new JsonResponse([], Response::HTTP_FORBIDDEN);
} }
$originalDescription = $server->description;
$description = $request->input('description'); $description = $request->input('description');
$server->update(['description' => $description ?? '']); $server->update(['description' => $description ?? '']);
if ($server->wasChanged('description')) { if ($server->wasChanged('description')) {
Activity::event('server:settings.description') Activity::event('server:settings.description')
->property(['old' => $server->getOriginal('description'), 'new' => $description]) ->property(['old' => $originalDescription, 'new' => $description])
->log(); ->log();
} }

View File

@ -0,0 +1,21 @@
<?php
namespace App\Traits\Filament;
use App\Models\Server;
use Filament\Facades\Filament;
trait BlockAccessInConflict
{
public static function canAccess(): bool
{
/** @var Server $server */
$server = Filament::getTenant();
if ($server->isInConflictState()) {
return false;
}
return parent::canAccess();
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Traits\Filament;
use App\Enums\HeaderActionPosition;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
trait CanCustomizeHeaderActions
{
/** @var array<string, Action|ActionGroup> */
protected static array $customHeaderActions = [];
public static function registerCustomHeaderActions(HeaderActionPosition $position, Action|ActionGroup ...$customHeaderActions): void
{
static::$customHeaderActions[$position->value] = array_merge(static::$customHeaderActions[$position->value] ?? [], $customHeaderActions);
}
/** @return array<Action|ActionGroup> */
protected function getDefaultHeaderActions(): array
{
return [];
}
/** @return array<Action|ActionGroup> */
protected function getHeaderActions(): array
{
return array_merge(
static::$customHeaderActions[HeaderActionPosition::Before->value] ?? [],
$this->getDefaultHeaderActions(),
static::$customHeaderActions[HeaderActionPosition::After->value] ?? []
);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Traits\Filament;
use App\Enums\HeaderWidgetPosition;
use Filament\Widgets\Widget;
use Filament\Widgets\WidgetConfiguration;
trait CanCustomizeHeaderWidgets
{
/** @var array<class-string<Widget>|WidgetConfiguration> */
protected static array $customHeaderWidgets = [];
public static function registerCustomHeaderWidgets(HeaderWidgetPosition $position, string|WidgetConfiguration ...$customHeaderWidgets): void
{
static::$customHeaderWidgets[$position->value] = array_merge(static::$customHeaderWidgets[$position->value] ?? [], $customHeaderWidgets);
}
/** @return array<class-string<Widget>|WidgetConfiguration> */
protected function getDefaultHeaderWidgets(): array
{
return [];
}
/** @return array<class-string<Widget>|WidgetConfiguration> */
protected function getHeaderWidgets(): array
{
return array_merge(
static::$customHeaderWidgets[HeaderWidgetPosition::Before->value] ?? [],
$this->getDefaultHeaderWidgets(),
static::$customHeaderWidgets[HeaderWidgetPosition::After->value] ?? []
);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Traits\Filament;
use Filament\Resources\Pages\PageRegistration;
trait CanCustomizePages
{
/** @var array<string, PageRegistration> */
protected static array $customPages = [];
/** @param array<string, PageRegistration> $customPages */
public static function registerCustomPages(array $customPages): void
{
static::$customPages = array_merge(static::$customPages, $customPages);
}
/** @return array<string, PageRegistration> */
public static function getDefaultPages(): array
{
return [];
}
/** @return array<string, PageRegistration> */
public static function getPages(): array
{
return array_unique(array_merge(static::getDefaultPages(), static::$customPages), SORT_REGULAR);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Traits\Filament;
use Filament\Resources\RelationManagers\RelationManager;
trait CanCustomizeRelations
{
/** @var array<class-string<RelationManager>> */
protected static array $customRelations = [];
public static function registerCustomRelations(string ...$customRelations): void
{
static::$customRelations = array_merge(static::$customRelations, $customRelations);
}
/** @return class-string<RelationManager>[] */
public static function getDefaultRelations(): array
{
return [];
}
/** @return class-string<RelationManager>[] */
public static function getRelations(): array
{
return array_unique(array_merge(static::getDefaultRelations(), static::$customRelations));
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Traits\Filament;
use Closure;
use Filament\Forms\Form;
trait CanModifyForm
{
/** @var array<Closure> */
protected static array $customFormModifications = [];
public static function modifyForm(Closure $closure): void
{
static::$customFormModifications[] = $closure;
}
public static function defaultForm(Form $form): Form
{
return $form;
}
public static function form(Form $form): Form
{
$form = static::defaultForm($form);
foreach (static::$customFormModifications as $closure) {
$form = $closure($form);
}
return $form;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Traits\Filament;
use Closure;
use Filament\Tables\Table;
trait CanModifyTable
{
/** @var array<Closure> */
protected static array $customTableModifications = [];
public static function modifyTable(Closure $closure): void
{
static::$customTableModifications[] = $closure;
}
public static function defaultTable(Table $table): Table
{
return $table;
}
public static function table(Table $table): Table
{
$table = static::defaultTable($table);
foreach (static::$customTableModifications as $closure) {
$table = $closure($table);
}
return $table;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Traits\Filament;
trait HasLimitBadge
{
public const WARNING_THRESHOLD = 0.7;
protected static function getBadgeCount(): int
{
return 0;
}
protected static function getBadgeLimit(): int
{
return 0;
}
public static function getNavigationBadge(): string
{
$limit = static::getBadgeLimit();
$count = static::getBadgeCount();
return $count . ($limit === 0 ? '' : ' / ' . $limit);
}
public static function getNavigationBadgeColor(): ?string
{
$limit = static::getBadgeLimit();
$count = static::getBadgeCount();
if ($limit === 0) {
return null;
}
return $count >= $limit ? 'danger' : ($count >= $limit * self::WARNING_THRESHOLD ? 'warning' : 'success');
}
}

View File

@ -1,83 +0,0 @@
{
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PANEL",
"meta": {
"version": "PLCN_v1",
"update_url": "https:\/\/github.com\/pelican-dev\/panel\/raw\/main\/database\/Seeders\/eggs\/source-engine\/egg-counter--strike--global-offensive.json"
},
"exported_at": "2025-03-18T12:36:01+00:00",
"name": "Counter-Strike: Global Offensive",
"author": "panel@example.com",
"uuid": "437c367d-06be-498f-a604-fdad135504d7",
"description": "Counter-Strike: Global Offensive is a multiplayer first-person shooter video game developed by Hidden Path Entertainment and Valve Corporation.",
"tags": [
"source",
"steamcmd"
],
"features": [
"gsl_token",
"steam_disk_space"
],
"docker_images": {
"ghcr.io\/parkervcp\/games:source": "ghcr.io\/parkervcp\/games:source"
},
"file_denylist": [],
"startup": ".\/srcds_run -game csgo -console -port {{SERVER_PORT}} +ip 0.0.0.0 +map {{SRCDS_MAP}} -strictportbind -norestart +sv_setsteamaccount {{STEAM_ACC}}",
"config": {
"files": "{}",
"startup": "{\r\n \"done\": \"Connection to Steam servers successful\"\r\n}",
"logs": "{}",
"stop": "quit"
},
"scripts": {
"installation": {
"script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\nmkdir -p \/mnt\/server\/steamapps # Fix steamcmd disk write error when this folder is missing\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +force_install_dir \/mnt\/server +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
"container": "ghcr.io\/parkervcp\/installers:debian",
"entrypoint": "bash"
}
},
"variables": [
{
"name": "Map",
"description": "The default map for the server.",
"env_variable": "SRCDS_MAP",
"default_value": "de_dust2",
"user_viewable": true,
"user_editable": true,
"rules": [
"required",
"string",
"alpha_dash"
],
"sort": 1
},
{
"name": "Steam Account Token",
"description": "The Steam Account Token required for the server to be displayed publicly.",
"env_variable": "STEAM_ACC",
"default_value": "",
"user_viewable": true,
"user_editable": true,
"rules": [
"required",
"string",
"alpha_num",
"size:32"
],
"sort": 2
},
{
"name": "Source AppID",
"description": "Required for game to update on server restart. Do not modify this.",
"env_variable": "SRCDS_APPID",
"default_value": "740",
"user_viewable": false,
"user_editable": false,
"rules": [
"required",
"string",
"max:20"
],
"sort": 3
}
]
}

View File

@ -1,19 +0,0 @@
<x-filament-widgets::widget>
<x-filament::section
icon="tabler-code"
icon-color="primary"
id="intro-developers"
collapsible
persist-collapsed
collapsed
:header-actions="$actions"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-developers.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-developers.content') }}</p>
<p><br /></p>
<p>{{ trans('admin/dashboard.sections.intro-developers.extra_note') }}</p>
</x-filament::section>
</x-filament-widgets::widget>

View File

@ -0,0 +1,3 @@
<x-filament-widgets::widget>
{{ $this->form }}
</x-filament-widgets::widget>

View File

@ -1,14 +0,0 @@
<x-filament-widgets::widget>
<x-filament::section
icon="tabler-question-mark"
icon-color="info"
id="intro-help"
collapsible
persist-collapsed
:header-actions="$actions"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-help.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-help.content') }}</p>
</x-filament::section>
</x-filament-widgets::widget>

View File

@ -1,14 +0,0 @@
<x-filament-widgets::widget>
<x-filament::section
icon="tabler-server-2"
icon-color="primary"
id="intro-first-node"
collapsible
persist-collapsed
:header-actions="$actions"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-first-node.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-first-node.content') }}</p>
</x-filament::section>
</x-filament-widgets::widget>

View File

@ -1,18 +0,0 @@
<x-filament-widgets::widget>
<x-filament::section
icon="tabler-heart-filled"
icon-color="danger"
id="intro-support"
collapsible
persist-collapsed
:header-actions="$actions"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-support.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-support.content') }}</p>
<p><br /></p>
<p>{{ trans('admin/dashboard.sections.intro-support.extra_note') }}</p>
</x-filament::section>
</x-filament-widgets::widget>

View File

@ -1,25 +0,0 @@
<x-filament-widgets::widget>
@if (!$isLatest)
<x-filament::section
icon="tabler-info-circle"
icon-color="warning"
id="intro-update-available"
:header-actions="$actions"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-update-available.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-update-available.content', ['latestVersion' => $latestVersion]) }}</p>
</x-filament::section>
@else
<x-filament::section
icon="tabler-checkbox"
icon-color="success"
id="intro-no-update"
>
<x-slot name="heading">{{ trans('admin/dashboard.sections.intro-no-update.heading') }}</x-slot>
<p>{{ trans('admin/dashboard.sections.intro-no-update.content', ['version' => $version]) }}</p>
</x-filament::section>
@endif
</x-filament-widgets::widget>

View File

@ -41,7 +41,7 @@ it('server description can be changed', function () {
expect()->toLogActivities(1) expect()->toLogActivities(1)
->and($logged->properties['old'])->toBe($originalDescription) ->and($logged->properties['old'])->toBe($originalDescription)
->and($logged->properties['new'])->toBe($newDescription) ->and($logged->properties['new'])->toBe($newDescription)
->and($server->description)->not()->toBe($originalDescription); ->and($server->description)->toBe($newDescription);
}); });
it('server description cannot be changed', function () { it('server description cannot be changed', function () {
@ -53,7 +53,7 @@ it('server description cannot be changed', function () {
->post("/api/client/servers/$server->uuid/settings/description", [ ->post("/api/client/servers/$server->uuid/settings/description", [
'description' => 'Test Description', 'description' => 'Test Description',
]) ])
->assertStatus(Response::HTTP_NO_CONTENT); ->assertStatus(Response::HTTP_FORBIDDEN);
$server = $server->refresh(); $server = $server->refresh();
expect()->toLogActivities(0) expect()->toLogActivities(0)