Reduce Reuse (#443)

* Reduce Reuse

Reduce the repetitiveness of \Form\Component\Blah along with all the others...

* PHPStan Fix
This commit is contained in:
Charles 2024-06-29 17:38:18 -04:00 committed by GitHub
parent 75d35e6ee8
commit 82c0568129
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 427 additions and 350 deletions

View File

@ -4,9 +4,13 @@ namespace App\Filament\Resources\ApiKeyResource\Pages;
use App\Filament\Resources\ApiKeyResource; use App\Filament\Resources\ApiKeyResource;
use App\Models\ApiKey; use App\Models\ApiKey;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Filament\Forms;
class CreateApiKey extends CreateRecord class CreateApiKey extends CreateRecord
{ {
@ -18,26 +22,26 @@ class CreateApiKey extends CreateRecord
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\Hidden::make('identifier')->default(ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION)), Hidden::make('identifier')->default(ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION)),
Forms\Components\Hidden::make('token')->default(str_random(ApiKey::KEY_LENGTH)), Hidden::make('token')->default(str_random(ApiKey::KEY_LENGTH)),
Forms\Components\Hidden::make('user_id') Hidden::make('user_id')
->default(auth()->user()->id) ->default(auth()->user()->id)
->required(), ->required(),
Forms\Components\Hidden::make('key_type') Hidden::make('key_type')
->inlineLabel() ->inlineLabel()
->default(ApiKey::TYPE_APPLICATION) ->default(ApiKey::TYPE_APPLICATION)
->required(), ->required(),
Forms\Components\Fieldset::make('Permissions') Fieldset::make('Permissions')
->columns([ ->columns([
'default' => 1, 'default' => 1,
'sm' => 1, 'sm' => 1,
'md' => 2, 'md' => 2,
]) ])
->schema( ->schema(
collect(ApiKey::RESOURCES)->map(fn ($resource) => Forms\Components\ToggleButtons::make("r_$resource") collect(ApiKey::RESOURCES)->map(fn ($resource) => ToggleButtons::make("r_$resource")
->label(str($resource)->replace('_', ' ')->title())->inline() ->label(str($resource)->replace('_', ' ')->title())->inline()
->options([ ->options([
0 => 'None', 0 => 'None',
@ -67,13 +71,13 @@ class CreateApiKey extends CreateRecord
)->all(), )->all(),
), ),
Forms\Components\TagsInput::make('allowed_ips') TagsInput::make('allowed_ips')
->placeholder('Example: 127.0.0.1 or 192.168.1.1') ->placeholder('Example: 127.0.0.1 or 192.168.1.1')
->label('Whitelisted IPv4 Addresses') ->label('Whitelisted IPv4 Addresses')
->helperText('Press enter to add a new IP address or leave blank to allow any IP address') ->helperText('Press enter to add a new IP address or leave blank to allow any IP address')
->columnSpanFull(), ->columnSpanFull(),
Forms\Components\Textarea::make('memo') Textarea::make('memo')
->required() ->required()
->label('Description') ->label('Description')
->helperText(' ->helperText('

View File

@ -6,8 +6,9 @@ use App\Filament\Resources\ApiKeyResource;
use App\Models\ApiKey; use App\Models\ApiKey;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Filament\Tables;
class ListApiKeys extends ListRecords class ListApiKeys extends ListRecords
{ {
@ -19,37 +20,37 @@ class ListApiKeys extends ListRecords
->searchable(false) ->searchable(false)
->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION)) ->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION))
->columns([ ->columns([
Tables\Columns\TextColumn::make('key') TextColumn::make('key')
->copyable() ->copyable()
->icon('tabler-clipboard-text') ->icon('tabler-clipboard-text')
->state(fn (ApiKey $key) => $key->identifier . $key->token), ->state(fn (ApiKey $key) => $key->identifier . $key->token),
Tables\Columns\TextColumn::make('memo') TextColumn::make('memo')
->label('Description') ->label('Description')
->wrap() ->wrap()
->limit(50), ->limit(50),
Tables\Columns\TextColumn::make('identifier') TextColumn::make('identifier')
->hidden() ->hidden()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('last_used_at') TextColumn::make('last_used_at')
->label('Last Used') ->label('Last Used')
->placeholder('Not Used') ->placeholder('Not Used')
->dateTime() ->dateTime()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at') TextColumn::make('created_at')
->label('Created') ->label('Created')
->dateTime() ->dateTime()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('user.username') TextColumn::make('user.username')
->label('Created By') ->label('Created By')
->url(fn (ApiKey $apiKey): string => route('filament.admin.resources.users.edit', ['record' => $apiKey->user])), ->url(fn (ApiKey $apiKey): string => route('filament.admin.resources.users.edit', ['record' => $apiKey->user])),
]) ])
->actions([ ->actions([
Tables\Actions\DeleteAction::make(), DeleteAction::make(),
]); ]);
} }

View File

@ -4,6 +4,8 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages;
use App\Filament\Resources\DatabaseHostResource; use App\Filament\Resources\DatabaseHostResource;
use App\Services\Databases\Hosts\HostCreationService; use App\Services\Databases\Hosts\HostCreationService;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
@ -34,14 +36,14 @@ class CreateDatabaseHost extends CreateRecord
'lg' => 4, 'lg' => 4,
]) ])
->schema([ ->schema([
Forms\Components\TextInput::make('host') TextInput::make('host')
->columnSpan(2) ->columnSpan(2)
->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.') ->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.')
->required() ->required()
->live(onBlur: true) ->live(onBlur: true)
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state)) ->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('port') TextInput::make('port')
->columnSpan(1) ->columnSpan(1)
->helperText('The port that MySQL is running on for this host.') ->helperText('The port that MySQL is running on for this host.')
->required() ->required()
@ -49,26 +51,26 @@ class CreateDatabaseHost extends CreateRecord
->default(3306) ->default(3306)
->minValue(0) ->minValue(0)
->maxValue(65535), ->maxValue(65535),
Forms\Components\TextInput::make('max_databases') TextInput::make('max_databases')
->label('Max databases') ->label('Max databases')
->helpertext('Blank is unlimited.') ->helpertext('Blank is unlimited.')
->numeric(), ->numeric(),
Forms\Components\TextInput::make('name') TextInput::make('name')
->label('Display Name') ->label('Display Name')
->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.') ->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.')
->required() ->required()
->maxLength(60), ->maxLength(60),
Forms\Components\TextInput::make('username') TextInput::make('username')
->helperText('The username of an account that has enough permissions to create new users and databases on the system.') ->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('password') TextInput::make('password')
->helperText('The password for the database user.') ->helperText('The password for the database user.')
->password() ->password()
->revealable() ->revealable()
->maxLength(255) ->maxLength(255)
->required(), ->required(),
Forms\Components\Select::make('node_id') Select::make('node_id')
->searchable() ->searchable()
->preload() ->preload()
->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.') ->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.')

View File

@ -3,9 +3,12 @@
namespace App\Filament\Resources\DatabaseHostResource\Pages; namespace App\Filament\Resources\DatabaseHostResource\Pages;
use App\Filament\Resources\DatabaseHostResource; use App\Filament\Resources\DatabaseHostResource;
use App\Filament\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 Filament\Actions; use Filament\Actions;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
@ -30,40 +33,40 @@ class EditDatabaseHost extends EditRecord
'lg' => 4, 'lg' => 4,
]) ])
->schema([ ->schema([
Forms\Components\TextInput::make('host') TextInput::make('host')
->columnSpan(2) ->columnSpan(2)
->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.') ->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.')
->required() ->required()
->live(onBlur: true) ->live(onBlur: true)
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state)) ->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('port') TextInput::make('port')
->columnSpan(1) ->columnSpan(1)
->helperText('The port that MySQL is running on for this host.') ->helperText('The port that MySQL is running on for this host.')
->required() ->required()
->numeric() ->numeric()
->minValue(0) ->minValue(0)
->maxValue(65535), ->maxValue(65535),
Forms\Components\TextInput::make('max_databases') TextInput::make('max_databases')
->label('Max databases') ->label('Max databases')
->helpertext('Blank is unlimited.') ->helpertext('Blank is unlimited.')
->numeric(), ->numeric(),
Forms\Components\TextInput::make('name') TextInput::make('name')
->label('Display Name') ->label('Display Name')
->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.') ->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.')
->required() ->required()
->maxLength(60), ->maxLength(60),
Forms\Components\TextInput::make('username') TextInput::make('username')
->helperText('The username of an account that has enough permissions to create new users and databases on the system.') ->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('password') TextInput::make('password')
->helperText('The password for the database user.') ->helperText('The password for the database user.')
->password() ->password()
->revealable() ->revealable()
->maxLength(255) ->maxLength(255)
->required(), ->required(),
Forms\Components\Select::make('node_id') Select::make('node_id')
->searchable() ->searchable()
->preload() ->preload()
->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.') ->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.')
@ -91,7 +94,7 @@ class EditDatabaseHost extends EditRecord
public function getRelationManagers(): array public function getRelationManagers(): array
{ {
return [ return [
DatabaseHostResource\RelationManagers\DatabasesRelationManager::class, DatabasesRelationManager::class,
]; ];
} }

View File

@ -5,7 +5,10 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages;
use App\Filament\Resources\DatabaseHostResource; use App\Filament\Resources\DatabaseHostResource;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables; use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
class ListDatabaseHosts extends ListRecords class ListDatabaseHosts extends ListRecords
@ -19,30 +22,27 @@ class ListDatabaseHosts extends ListRecords
return $table return $table
->searchable(false) ->searchable(false)
->columns([ ->columns([
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('host') TextColumn::make('host')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('port') TextColumn::make('port')
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('username') TextColumn::make('username')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('max_databases') TextColumn::make('max_databases')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('node.name') TextColumn::make('node.name')
->numeric() ->numeric()
->sortable(), ->sortable(),
]) ])
->filters([
//
])
->actions([ ->actions([
Tables\Actions\EditAction::make(), EditAction::make(),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(), DeleteBulkAction::make(),
]), ]),
]); ]);
} }

View File

@ -4,11 +4,14 @@ namespace App\Filament\Resources\DatabaseHostResource\RelationManagers;
use App\Models\Database; use App\Models\Database;
use App\Services\Databases\DatabasePasswordService; use App\Services\Databases\DatabasePasswordService;
use Filament\Forms;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables; use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
class DatabasesRelationManager extends RelationManager class DatabasesRelationManager extends RelationManager
@ -19,9 +22,9 @@ class DatabasesRelationManager extends RelationManager
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\TextInput::make('database')->columnSpanFull(), TextInput::make('database')->columnSpanFull(),
Forms\Components\TextInput::make('username'), TextInput::make('username'),
Forms\Components\TextInput::make('password') TextInput::make('password')
->hintAction( ->hintAction(
Action::make('rotate') Action::make('rotate')
->icon('tabler-refresh') ->icon('tabler-refresh')
@ -29,12 +32,12 @@ class DatabasesRelationManager extends RelationManager
->action(fn (DatabasePasswordService $service, Database $database, $set, $get) => $this->rotatePassword($service, $database, $set, $get)) ->action(fn (DatabasePasswordService $service, Database $database, $set, $get) => $this->rotatePassword($service, $database, $set, $get))
) )
->formatStateUsing(fn (Database $database) => $database->password), ->formatStateUsing(fn (Database $database) => $database->password),
Forms\Components\TextInput::make('remote')->label('Connections From'), TextInput::make('remote')->label('Connections From'),
Forms\Components\TextInput::make('max_connections'), TextInput::make('max_connections'),
Forms\Components\TextInput::make('JDBC') TextInput::make('JDBC')
->label('JDBC Connection String') ->label('JDBC Connection String')
->columnSpanFull() ->columnSpanFull()
->formatStateUsing(fn (Forms\Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), ->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')),
]); ]);
} }
public function table(Table $table): Table public function table(Table $table): Table
@ -42,18 +45,18 @@ class DatabasesRelationManager extends RelationManager
return $table return $table
->recordTitleAttribute('servers') ->recordTitleAttribute('servers')
->columns([ ->columns([
Tables\Columns\TextColumn::make('database')->icon('tabler-database'), TextColumn::make('database')->icon('tabler-database'),
Tables\Columns\TextColumn::make('username')->icon('tabler-user'), TextColumn::make('username')->icon('tabler-user'),
Tables\Columns\TextColumn::make('remote'), TextColumn::make('remote'),
Tables\Columns\TextColumn::make('server.name') TextColumn::make('server.name')
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->url(fn (Database $database) => route('filament.admin.resources.servers.edit', ['record' => $database->server_id])), ->url(fn (Database $database) => route('filament.admin.resources.servers.edit', ['record' => $database->server_id])),
Tables\Columns\TextColumn::make('max_connections'), TextColumn::make('max_connections'),
Tables\Columns\TextColumn::make('created_at')->dateTime(), TextColumn::make('created_at')->dateTime(),
]) ])
->actions([ ->actions([
Tables\Actions\DeleteAction::make(), DeleteAction::make(),
Tables\Actions\ViewAction::make()->color('primary'), ViewAction::make()->color('primary'),
]); ]);
} }

View File

@ -3,9 +3,10 @@
namespace App\Filament\Resources\DatabaseResource\Pages; namespace App\Filament\Resources\DatabaseResource\Pages;
use App\Filament\Resources\DatabaseResource; use App\Filament\Resources\DatabaseResource;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Filament\Forms;
class CreateDatabase extends CreateRecord class CreateDatabase extends CreateRecord
{ {
@ -15,29 +16,29 @@ class CreateDatabase extends CreateRecord
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\Select::make('server_id') Select::make('server_id')
->relationship('server', 'name') ->relationship('server', 'name')
->searchable() ->searchable()
->preload() ->preload()
->required(), ->required(),
Forms\Components\TextInput::make('database_host_id') TextInput::make('database_host_id')
->required() ->required()
->numeric(), ->numeric(),
Forms\Components\TextInput::make('database') TextInput::make('database')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('remote') TextInput::make('remote')
->required() ->required()
->maxLength(255) ->maxLength(255)
->default('%'), ->default('%'),
Forms\Components\TextInput::make('username') TextInput::make('username')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('password') TextInput::make('password')
->password() ->password()
->revealable() ->revealable()
->required(), ->required(),
Forms\Components\TextInput::make('max_connections') TextInput::make('max_connections')
->numeric() ->numeric()
->minValue(0) ->minValue(0)
->default(0), ->default(0),

View File

@ -4,9 +4,10 @@ namespace App\Filament\Resources\DatabaseResource\Pages;
use App\Filament\Resources\DatabaseResource; use App\Filament\Resources\DatabaseResource;
use Filament\Actions; use Filament\Actions;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Filament\Forms;
class EditDatabase extends EditRecord class EditDatabase extends EditRecord
{ {
@ -16,29 +17,29 @@ class EditDatabase extends EditRecord
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\Select::make('server_id') Select::make('server_id')
->relationship('server', 'name') ->relationship('server', 'name')
->searchable() ->searchable()
->preload() ->preload()
->required(), ->required(),
Forms\Components\TextInput::make('database_host_id') TextInput::make('database_host_id')
->required() ->required()
->numeric(), ->numeric(),
Forms\Components\TextInput::make('database') TextInput::make('database')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('remote') TextInput::make('remote')
->required() ->required()
->maxLength(255) ->maxLength(255)
->default('%'), ->default('%'),
Forms\Components\TextInput::make('username') TextInput::make('username')
->required() ->required()
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('password') TextInput::make('password')
->password() ->password()
->revealable() ->revealable()
->required(), ->required(),
Forms\Components\TextInput::make('max_connections') TextInput::make('max_connections')
->numeric() ->numeric()
->minValue(0) ->minValue(0)
->default(0), ->default(0),

View File

@ -4,9 +4,12 @@ namespace App\Filament\Resources\DatabaseResource\Pages;
use App\Filament\Resources\DatabaseResource; use App\Filament\Resources\DatabaseResource;
use Filament\Actions; use Filament\Actions;
use Filament\Tables\Actions\EditAction;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Filament\Tables;
class ListDatabases extends ListRecords class ListDatabases extends ListRecords
{ {
@ -16,39 +19,36 @@ class ListDatabases extends ListRecords
{ {
return $table return $table
->columns([ ->columns([
Tables\Columns\TextColumn::make('server.name') TextColumn::make('server.name')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('database_host_id') TextColumn::make('database_host_id')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('database') TextColumn::make('database')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('username') TextColumn::make('username')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('remote') TextColumn::make('remote')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('max_connections') TextColumn::make('max_connections')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at') TextColumn::make('created_at')
->dateTime() ->dateTime()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at') TextColumn::make('updated_at')
->dateTime() ->dateTime()
->sortable() ->sortable()
->toggleable(isToggledHiddenByDefault: true), ->toggleable(isToggledHiddenByDefault: true),
]) ])
->filters([
//
])
->actions([ ->actions([
Tables\Actions\EditAction::make(), EditAction::make(),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(), DeleteBulkAction::make(),
]), ]),
]); ]);
} }

View File

@ -3,6 +3,18 @@
namespace App\Filament\Resources\EggResource\Pages; namespace App\Filament\Resources\EggResource\Pages;
use App\Filament\Resources\EggResource; use App\Filament\Resources\EggResource;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor; use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
use Filament\Forms; use Filament\Forms;
@ -19,26 +31,26 @@ class CreateEgg extends CreateRecord
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\Tabs::make()->tabs([ Tabs::make()->tabs([
Forms\Components\Tabs\Tab::make('Configuration') Tab::make('Configuration')
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4]) ->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
->schema([ ->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->required() ->required()
->maxLength(255) ->maxLength(255)
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->helperText('A simple, human-readable name to use as an identifier for this Egg.'), ->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
Forms\Components\TextInput::make('author') TextInput::make('author')
->maxLength(255) ->maxLength(255)
->required() ->required()
->email() ->email()
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->helperText('The author of this version of the Egg.'), ->helperText('The author of this version of the Egg.'),
Forms\Components\Textarea::make('description') Textarea::make('description')
->rows(3) ->rows(3)
->columnSpanFull() ->columnSpanFull()
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'), ->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
Forms\Components\Textarea::make('startup') Textarea::make('startup')
->rows(3) ->rows(3)
->columnSpanFull() ->columnSpanFull()
->required() ->required()
@ -46,26 +58,26 @@ class CreateEgg extends CreateRecord
'java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}', 'java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}',
])) ]))
->helperText('The default startup command that should be used for new servers using this Egg.'), ->helperText('The default startup command that should be used for new servers using this Egg.'),
Forms\Components\TagsInput::make('features') TagsInput::make('features')
->placeholder('Add Feature') ->placeholder('Add Feature')
->helperText('') ->helperText('')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\Toggle::make('force_outgoing_ip') Toggle::make('force_outgoing_ip')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP.
Required for certain games to work properly when the Node has multiple public IP addresses. Required for certain games to work properly when the Node has multiple public IP addresses.
Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."),
Forms\Components\Hidden::make('script_is_privileged') Hidden::make('script_is_privileged')
->default(1), ->default(1),
Forms\Components\TagsInput::make('tags') TagsInput::make('tags')
->placeholder('Add Tags') ->placeholder('Add Tags')
->helperText('') ->helperText('')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\TextInput::make('update_url') TextInput::make('update_url')
->disabled() ->disabled()
->helperText('Not implemented.') ->helperText('Not implemented.')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\KeyValue::make('docker_images') KeyValue::make('docker_images')
->live() ->live()
->columnSpanFull() ->columnSpanFull()
->required() ->required()
@ -77,37 +89,37 @@ class CreateEgg extends CreateRecord
->helperText('The docker images available to servers using this egg.'), ->helperText('The docker images available to servers using this egg.'),
]), ]),
Forms\Components\Tabs\Tab::make('Process Management') Tab::make('Process Management')
->columns() ->columns()
->schema([ ->schema([
Forms\Components\Hidden::make('config_from') Hidden::make('config_from')
->default(null) ->default(null)
->label('Copy Settings From') ->label('Copy Settings From')
// ->placeholder('None') // ->placeholder('None')
// ->relationship('configFrom', 'name', ignoreRecord: true) // ->relationship('configFrom', 'name', ignoreRecord: true)
->helperText('If you would like to default to settings from another Egg select it from the menu above.'), ->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
Forms\Components\TextInput::make('config_stop') TextInput::make('config_stop')
->required() ->required()
->maxLength(255) ->maxLength(255)
->label('Stop Command') ->label('Stop Command')
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'), ->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
Forms\Components\Textarea::make('config_startup')->rows(10)->json() Textarea::make('config_startup')->rows(10)->json()
->label('Start Configuration') ->label('Start Configuration')
->default('{}') ->default('{}')
->helperText('List of values the daemon should be looking for when booting a server to determine completion.'), ->helperText('List of values the daemon should be looking for when booting a server to determine completion.'),
Forms\Components\Textarea::make('config_files')->rows(10)->json() Textarea::make('config_files')->rows(10)->json()
->label('Configuration Files') ->label('Configuration Files')
->default('{}') ->default('{}')
->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'), ->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'),
Forms\Components\Textarea::make('config_logs')->rows(10)->json() Textarea::make('config_logs')->rows(10)->json()
->label('Log Configuration') ->label('Log Configuration')
->default('{}') ->default('{}')
->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'), ->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'),
]), ]),
Forms\Components\Tabs\Tab::make('Egg Variables') Tab::make('Egg Variables')
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\Repeater::make('variables') Repeater::make('variables')
->label('') ->label('')
->addActionLabel('Add New Egg Variable') ->addActionLabel('Add New Egg Variable')
->grid() ->grid()
@ -137,7 +149,7 @@ class CreateEgg extends CreateRecord
return $data; return $data;
}) })
->schema([ ->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->live() ->live()
->debounce(750) ->debounce(750)
->maxLength(255) ->maxLength(255)
@ -145,8 +157,8 @@ class CreateEgg extends CreateRecord
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString()) ->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
) )
->required(), ->required(),
Forms\Components\Textarea::make('description')->columnSpanFull(), Textarea::make('description')->columnSpanFull(),
Forms\Components\TextInput::make('env_variable') TextInput::make('env_variable')
->label('Environment Variable') ->label('Environment Variable')
->maxLength(255) ->maxLength(255)
->prefix('{{') ->prefix('{{')
@ -154,29 +166,29 @@ class CreateEgg extends CreateRecord
->hintIcon('tabler-code') ->hintIcon('tabler-code')
->hintIconTooltip(fn ($state) => "{{{$state}}}") ->hintIconTooltip(fn ($state) => "{{{$state}}}")
->required(), ->required(),
Forms\Components\TextInput::make('default_value')->maxLength(255), TextInput::make('default_value')->maxLength(255),
Forms\Components\Fieldset::make('User Permissions') Fieldset::make('User Permissions')
->schema([ ->schema([
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'), Checkbox::make('user_viewable')->label('Viewable'),
Forms\Components\Checkbox::make('user_editable')->label('Editable'), Checkbox::make('user_editable')->label('Editable'),
]), ]),
Forms\Components\Textarea::make('rules')->columnSpanFull(), Textarea::make('rules')->columnSpanFull(),
]), ]),
]), ]),
Forms\Components\Tabs\Tab::make('Install Script') Tab::make('Install Script')
->columns(3) ->columns(3)
->schema([ ->schema([
Forms\Components\Hidden::make('copy_script_from'), Hidden::make('copy_script_from'),
//->placeholder('None') //->placeholder('None')
//->relationship('scriptFrom', 'name', ignoreRecord: true), //->relationship('scriptFrom', 'name', ignoreRecord: true),
Forms\Components\TextInput::make('script_container') TextInput::make('script_container')
->required() ->required()
->maxLength(255) ->maxLength(255)
->default('alpine:3.4'), ->default('alpine:3.4'),
Forms\Components\Select::make('script_entry') Select::make('script_entry')
->selectablePlaceholder(false) ->selectablePlaceholder(false)
->default('bash') ->default('bash')
->options(['bash', 'ash', '/bin/bash']) ->options(['bash', 'ash', '/bin/bash'])

View File

@ -3,11 +3,25 @@
namespace App\Filament\Resources\EggResource\Pages; namespace App\Filament\Resources\EggResource\Pages;
use App\Filament\Resources\EggResource; use App\Filament\Resources\EggResource;
use App\Filament\Resources\EggResource\RelationManagers\ServersRelationManager;
use App\Models\Egg; use App\Models\Egg;
use App\Services\Eggs\Sharing\EggImporterService; use App\Services\Eggs\Sharing\EggImporterService;
use Exception; use Exception;
use Filament\Actions; use Filament\Actions;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor; use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
@ -23,64 +37,64 @@ class EditEgg extends EditRecord
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\Tabs::make()->tabs([ Tabs::make()->tabs([
Forms\Components\Tabs\Tab::make('Configuration') Tab::make('Configuration')
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4]) ->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
->schema([ ->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->required() ->required()
->maxLength(255) ->maxLength(255)
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
->helperText('A simple, human-readable name to use as an identifier for this Egg.'), ->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
Forms\Components\TextInput::make('uuid') TextInput::make('uuid')
->label('Egg UUID') ->label('Egg UUID')
->disabled() ->disabled()
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2])
->helperText('This is the globally unique identifier for this Egg which Wings uses as an identifier.'), ->helperText('This is the globally unique identifier for this Egg which Wings uses as an identifier.'),
Forms\Components\TextInput::make('id') TextInput::make('id')
->label('Egg ID') ->label('Egg ID')
->disabled(), ->disabled(),
Forms\Components\Textarea::make('description') Textarea::make('description')
->rows(3) ->rows(3)
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'), ->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
Forms\Components\TextInput::make('author') TextInput::make('author')
->required() ->required()
->maxLength(255) ->maxLength(255)
->email() ->email()
->disabled() ->disabled()
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->helperText('The author of this version of the Egg. Uploading a new Egg configuration from a different author will change this.'), ->helperText('The author of this version of the Egg. Uploading a new Egg configuration from a different author will change this.'),
Forms\Components\Textarea::make('startup') Textarea::make('startup')
->rows(2) ->rows(2)
->columnSpanFull() ->columnSpanFull()
->required() ->required()
->helperText('The default startup command that should be used for new servers using this Egg.'), ->helperText('The default startup command that should be used for new servers using this Egg.'),
Forms\Components\TagsInput::make('file_denylist') TagsInput::make('file_denylist')
->hidden() // latest wings breaks it. ->hidden() // latest wings breaks it.
->placeholder('denied-file.txt') ->placeholder('denied-file.txt')
->helperText('A list of files that the end user is not allowed to edit.') ->helperText('A list of files that the end user is not allowed to edit.')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\TagsInput::make('features') TagsInput::make('features')
->placeholder('Add Feature') ->placeholder('Add Feature')
->helperText('') ->helperText('')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\Toggle::make('force_outgoing_ip') Toggle::make('force_outgoing_ip')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP.
Required for certain games to work properly when the Node has multiple public IP addresses. Required for certain games to work properly when the Node has multiple public IP addresses.
Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."),
Forms\Components\Hidden::make('script_is_privileged') Hidden::make('script_is_privileged')
->helperText('The docker images available to servers using this egg.'), ->helperText('The docker images available to servers using this egg.'),
Forms\Components\TagsInput::make('tags') TagsInput::make('tags')
->placeholder('Add Tags') ->placeholder('Add Tags')
->helperText('') ->helperText('')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\TextInput::make('update_url') TextInput::make('update_url')
->disabled() ->disabled()
->helperText('Not implemented.') ->helperText('Not implemented.')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
Forms\Components\KeyValue::make('docker_images') KeyValue::make('docker_images')
->live() ->live()
->columnSpanFull() ->columnSpanFull()
->required() ->required()
@ -90,32 +104,32 @@ class EditEgg extends EditRecord
->helperText('The docker images available to servers using this egg.'), ->helperText('The docker images available to servers using this egg.'),
]), ]),
Forms\Components\Tabs\Tab::make('Process Management') Tab::make('Process Management')
->columns() ->columns()
->schema([ ->schema([
Forms\Components\Select::make('config_from') Select::make('config_from')
->label('Copy Settings From') ->label('Copy Settings From')
->placeholder('None') ->placeholder('None')
->relationship('configFrom', 'name', ignoreRecord: true) ->relationship('configFrom', 'name', ignoreRecord: true)
->helperText('If you would like to default to settings from another Egg select it from the menu above.'), ->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
Forms\Components\TextInput::make('config_stop') TextInput::make('config_stop')
->maxLength(255) ->maxLength(255)
->label('Stop Command') ->label('Stop Command')
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'), ->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
Forms\Components\Textarea::make('config_startup')->rows(10)->json() Textarea::make('config_startup')->rows(10)->json()
->label('Start Configuration') ->label('Start Configuration')
->helperText('List of values the daemon should be looking for when booting a server to determine completion.'), ->helperText('List of values the daemon should be looking for when booting a server to determine completion.'),
Forms\Components\Textarea::make('config_files')->rows(10)->json() Textarea::make('config_files')->rows(10)->json()
->label('Configuration Files') ->label('Configuration Files')
->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'), ->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'),
Forms\Components\Textarea::make('config_logs')->rows(10)->json() Textarea::make('config_logs')->rows(10)->json()
->label('Log Configuration') ->label('Log Configuration')
->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'), ->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'),
]), ]),
Forms\Components\Tabs\Tab::make('Egg Variables') Tab::make('Egg Variables')
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\Repeater::make('variables') Repeater::make('variables')
->label('') ->label('')
->grid() ->grid()
->relationship('variables') ->relationship('variables')
@ -144,7 +158,7 @@ class EditEgg extends EditRecord
return $data; return $data;
}) })
->schema([ ->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->live() ->live()
->debounce(750) ->debounce(750)
->maxLength(255) ->maxLength(255)
@ -152,8 +166,8 @@ class EditEgg extends EditRecord
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString()) ->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
) )
->required(), ->required(),
Forms\Components\Textarea::make('description')->columnSpanFull(), Textarea::make('description')->columnSpanFull(),
Forms\Components\TextInput::make('env_variable') TextInput::make('env_variable')
->label('Environment Variable') ->label('Environment Variable')
->maxLength(255) ->maxLength(255)
->prefix('{{') ->prefix('{{')
@ -161,29 +175,29 @@ class EditEgg extends EditRecord
->hintIcon('tabler-code') ->hintIcon('tabler-code')
->hintIconTooltip(fn ($state) => "{{{$state}}}") ->hintIconTooltip(fn ($state) => "{{{$state}}}")
->required(), ->required(),
Forms\Components\TextInput::make('default_value')->maxLength(255), TextInput::make('default_value')->maxLength(255),
Forms\Components\Fieldset::make('User Permissions') Fieldset::make('User Permissions')
->schema([ ->schema([
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'), Checkbox::make('user_viewable')->label('Viewable'),
Forms\Components\Checkbox::make('user_editable')->label('Editable'), Checkbox::make('user_editable')->label('Editable'),
]), ]),
Forms\Components\TextInput::make('rules')->columnSpanFull(), TextInput::make('rules')->columnSpanFull(),
]), ]),
]), ]),
Forms\Components\Tabs\Tab::make('Install Script') Tab::make('Install Script')
->columns(3) ->columns(3)
->schema([ ->schema([
Forms\Components\Select::make('copy_script_from') Select::make('copy_script_from')
->placeholder('None') ->placeholder('None')
->relationship('scriptFrom', 'name', ignoreRecord: true), ->relationship('scriptFrom', 'name', ignoreRecord: true),
Forms\Components\TextInput::make('script_container') TextInput::make('script_container')
->required() ->required()
->maxLength(255) ->maxLength(255)
->default('alpine:3.4'), ->default('alpine:3.4'),
Forms\Components\TextInput::make('script_entry') TextInput::make('script_entry')
->required() ->required()
->maxLength(255) ->maxLength(255)
->default('ash'), ->default('ash'),
@ -217,23 +231,23 @@ class EditEgg extends EditRecord
Actions\Action::make('importEgg') Actions\Action::make('importEgg')
->label('Import') ->label('Import')
->form([ ->form([
Forms\Components\Placeholder::make('warning') Placeholder::make('warning')
->label('This will overwrite the current egg to the one you upload.'), ->label('This will overwrite the current egg to the one you upload.'),
Tabs::make('Tabs') Tabs::make('Tabs')
->tabs([ ->tabs([
Tabs\Tab::make('From File') Tab::make('From File')
->icon('tabler-file-upload') ->icon('tabler-file-upload')
->schema([ ->schema([
Forms\Components\FileUpload::make('egg') FileUpload::make('egg')
->label('Egg') ->label('Egg')
->hint('eg. minecraft.json') ->hint('eg. minecraft.json')
->acceptedFileTypes(['application/json']) ->acceptedFileTypes(['application/json'])
->storeFiles(false), ->storeFiles(false),
]), ]),
Tabs\Tab::make('From URL') Tab::make('From URL')
->icon('tabler-world-upload') ->icon('tabler-world-upload')
->schema([ ->schema([
Forms\Components\TextInput::make('url') TextInput::make('url')
->label('URL') ->label('URL')
->hint('Link to the egg file (eg. minecraft.json)') ->hint('Link to the egg file (eg. minecraft.json)')
->url(), ->url(),
@ -302,7 +316,7 @@ class EditEgg extends EditRecord
public function getRelationManagers(): array public function getRelationManagers(): array
{ {
return [ return [
EggResource\RelationManagers\ServersRelationManager::class, ServersRelationManager::class,
]; ];
} }
} }

View File

@ -8,10 +8,16 @@ use App\Services\Eggs\Sharing\EggExporterService;
use App\Services\Eggs\Sharing\EggImporterService; use App\Services\Eggs\Sharing\EggImporterService;
use Exception; use Exception;
use Filament\Actions; use Filament\Actions;
use Filament\Forms; use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Filament\Tables; use Filament\Tables;
@ -27,22 +33,22 @@ class ListEggs extends ListRecords
->defaultPaginationPageOption(25) ->defaultPaginationPageOption(25)
->checkIfRecordIsSelectableUsing(fn (Egg $egg) => $egg->servers_count <= 0) ->checkIfRecordIsSelectableUsing(fn (Egg $egg) => $egg->servers_count <= 0)
->columns([ ->columns([
Tables\Columns\TextColumn::make('id') TextColumn::make('id')
->label('Id') ->label('Id')
->hidden(), ->hidden(),
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->icon('tabler-egg') ->icon('tabler-egg')
->description(fn ($record): ?string => (strlen($record->description) > 120) ? substr($record->description, 0, 120).'...' : $record->description) ->description(fn ($record): ?string => (strlen($record->description) > 120) ? substr($record->description, 0, 120).'...' : $record->description)
->wrap() ->wrap()
->searchable() ->searchable()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('servers_count') TextColumn::make('servers_count')
->counts('servers') ->counts('servers')
->icon('tabler-server') ->icon('tabler-server')
->label('Servers'), ->label('Servers'),
]) ])
->actions([ ->actions([
Tables\Actions\EditAction::make(), EditAction::make(),
Tables\Actions\Action::make('export') Tables\Actions\Action::make('export')
->icon('tabler-download') ->icon('tabler-download')
->label('Export') ->label('Export')
@ -52,8 +58,8 @@ class ListEggs extends ListRecords
}, 'egg-' . $egg->getKebabName() . '.json')), }, 'egg-' . $egg->getKebabName() . '.json')),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(), DeleteBulkAction::make(),
]), ]),
]); ]);
} }
@ -67,20 +73,20 @@ class ListEggs extends ListRecords
->form([ ->form([
Tabs::make('Tabs') Tabs::make('Tabs')
->tabs([ ->tabs([
Tabs\Tab::make('From File') Tab::make('From File')
->icon('tabler-file-upload') ->icon('tabler-file-upload')
->schema([ ->schema([
Forms\Components\FileUpload::make('egg') FileUpload::make('egg')
->label('Egg') ->label('Egg')
->hint('This should be the json file ( egg-minecraft.json )') ->hint('This should be the json file ( egg-minecraft.json )')
->acceptedFileTypes(['application/json']) ->acceptedFileTypes(['application/json'])
->storeFiles(false) ->storeFiles(false)
->multiple(), ->multiple(),
]), ]),
Tabs\Tab::make('From URL') Tab::make('From URL')
->icon('tabler-world-upload') ->icon('tabler-world-upload')
->schema([ ->schema([
Forms\Components\TextInput::make('url') TextInput::make('url')
->label('URL') ->label('URL')
->hint('This URL should point to a single json file') ->hint('This URL should point to a single json file')
->url(), ->url(),

View File

@ -4,7 +4,8 @@ namespace App\Filament\Resources\EggResource\RelationManagers;
use App\Models\Server; use App\Models\Server;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables; use Filament\Tables\Columns\SelectColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
class ServersRelationManager extends RelationManager class ServersRelationManager extends RelationManager
@ -18,21 +19,21 @@ class ServersRelationManager extends RelationManager
->emptyStateDescription('No Servers')->emptyStateHeading('No servers are assigned this egg.') ->emptyStateDescription('No Servers')->emptyStateHeading('No servers are assigned this egg.')
->searchable(false) ->searchable(false)
->columns([ ->columns([
Tables\Columns\TextColumn::make('user.username') TextColumn::make('user.username')
->label('Owner') ->label('Owner')
->icon('tabler-user') ->icon('tabler-user')
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server])) ->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server]))
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('node.name') TextColumn::make('node.name')
->icon('tabler-server-2') ->icon('tabler-server-2')
->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])), ->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])),
Tables\Columns\TextColumn::make('image') TextColumn::make('image')
->label('Docker Image'), ->label('Docker Image'),
Tables\Columns\SelectColumn::make('allocation.id') SelectColumn::make('allocation.id')
->label('Primary Allocation') ->label('Primary Allocation')
->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address]) ->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address])
->selectablePlaceholder(false) ->selectablePlaceholder(false)

View File

@ -4,11 +4,14 @@ namespace App\Filament\Resources\MountResource\Pages;
use App\Filament\Resources\MountResource; use App\Filament\Resources\MountResource;
use Filament\Forms\Components\Group; use Filament\Forms\Components\Group;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Section; use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Filament\Forms;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -23,11 +26,11 @@ class CreateMount extends CreateRecord
return $form return $form
->schema([ ->schema([
Section::make()->schema([ Section::make()->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->required() ->required()
->helperText('Unique name used to separate this mount from another.') ->helperText('Unique name used to separate this mount from another.')
->maxLength(64), ->maxLength(64),
Forms\Components\ToggleButtons::make('read_only') ToggleButtons::make('read_only')
->label('Read only?') ->label('Read only?')
->helperText('Is the mount read only inside the container?') ->helperText('Is the mount read only inside the container?')
->options([ ->options([
@ -45,15 +48,15 @@ class CreateMount extends CreateRecord
->inline() ->inline()
->default(false) ->default(false)
->required(), ->required(),
Forms\Components\TextInput::make('source') TextInput::make('source')
->required() ->required()
->helperText('File path on the host system to mount to a container.') ->helperText('File path on the host system to mount to a container.')
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('target') TextInput::make('target')
->required() ->required()
->helperText('Where the mount will be accessible inside a container.') ->helperText('Where the mount will be accessible inside a container.')
->maxLength(255), ->maxLength(255),
Forms\Components\ToggleButtons::make('user_mountable') ToggleButtons::make('user_mountable')
->hidden() ->hidden()
->label('User mountable?') ->label('User mountable?')
->options([ ->options([
@ -71,10 +74,10 @@ class CreateMount extends CreateRecord
->default(false) ->default(false)
->inline() ->inline()
->required(), ->required(),
Forms\Components\Textarea::make('description') Textarea::make('description')
->helperText('A longer description for this mount.') ->helperText('A longer description for this mount.')
->columnSpanFull(), ->columnSpanFull(),
Forms\Components\Hidden::make('user_mountable')->default(1), Hidden::make('user_mountable')->default(1),
])->columnSpan(1)->columns([ ])->columnSpan(1)->columns([
'default' => 1, 'default' => 1,
'lg' => 2, 'lg' => 2,

View File

@ -4,8 +4,10 @@ namespace App\Filament\Resources\MountResource\Pages;
use App\Filament\Resources\MountResource; use App\Filament\Resources\MountResource;
use Filament\Actions; use Filament\Actions;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Filament\Forms;
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;
@ -20,11 +22,11 @@ class EditMount extends EditRecord
return $form return $form
->schema([ ->schema([
Section::make()->schema([ Section::make()->schema([
Forms\Components\TextInput::make('name') TextInput::make('name')
->required() ->required()
->helperText('Unique name used to separate this mount from another.') ->helperText('Unique name used to separate this mount from another.')
->maxLength(64), ->maxLength(64),
Forms\Components\ToggleButtons::make('read_only') ToggleButtons::make('read_only')
->label('Read only?') ->label('Read only?')
->helperText('Is the mount read only inside the container?') ->helperText('Is the mount read only inside the container?')
->options([ ->options([
@ -42,15 +44,15 @@ class EditMount extends EditRecord
->inline() ->inline()
->default(false) ->default(false)
->required(), ->required(),
Forms\Components\TextInput::make('source') TextInput::make('source')
->required() ->required()
->helperText('File path on the host system to mount to a container.') ->helperText('File path on the host system to mount to a container.')
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('target') TextInput::make('target')
->required() ->required()
->helperText('Where the mount will be accessible inside a container.') ->helperText('Where the mount will be accessible inside a container.')
->maxLength(255), ->maxLength(255),
Forms\Components\ToggleButtons::make('user_mountable') ToggleButtons::make('user_mountable')
->hidden() ->hidden()
->label('User mountable?') ->label('User mountable?')
->options([ ->options([
@ -68,7 +70,7 @@ class EditMount extends EditRecord
->default(false) ->default(false)
->inline() ->inline()
->required(), ->required(),
Forms\Components\Textarea::make('description') Textarea::make('description')
->helperText('A longer description for this mount.') ->helperText('A longer description for this mount.')
->columnSpanFull(), ->columnSpanFull(),
])->columnSpan(1)->columns([ ])->columnSpan(1)->columns([

View File

@ -6,9 +6,13 @@ use App\Filament\Resources\MountResource;
use App\Models\Mount; use App\Models\Mount;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Filament\Tables;
class ListMounts extends ListRecords class ListMounts extends ListRecords
{ {
@ -18,31 +22,28 @@ class ListMounts extends ListRecords
return $table return $table
->searchable(false) ->searchable(false)
->columns([ ->columns([
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('source') TextColumn::make('source')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('target') TextColumn::make('target')
->searchable(), ->searchable(),
Tables\Columns\IconColumn::make('read_only') IconColumn::make('read_only')
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled') ->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
->color(fn (bool $state) => $state ? 'success' : 'danger') ->color(fn (bool $state) => $state ? 'success' : 'danger')
->sortable(), ->sortable(),
Tables\Columns\IconColumn::make('user_mountable') IconColumn::make('user_mountable')
->hidden() ->hidden()
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled') ->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
->color(fn (bool $state) => $state ? 'success' : 'danger') ->color(fn (bool $state) => $state ? 'success' : 'danger')
->sortable(), ->sortable(),
]) ])
->filters([
//
])
->actions([ ->actions([
Tables\Actions\EditAction::make(), EditAction::make(),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(), DeleteBulkAction::make(),
]), ]),
]) ])
->emptyStateIcon('tabler-layers-linked') ->emptyStateIcon('tabler-layers-linked')

View File

@ -3,7 +3,8 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\NodeResource\Pages; use App\Filament\Resources\NodeResource\Pages;
use App\Filament\Resources\NodeResource\RelationManagers; use App\Filament\Resources\NodeResource\RelationManagers\AllocationsRelationManager;
use App\Filament\Resources\NodeResource\RelationManagers\NodesRelationManager;
use App\Models\Node; use App\Models\Node;
use Filament\Resources\Resource; use Filament\Resources\Resource;
@ -23,8 +24,8 @@ class NodeResource extends Resource
public static function getRelations(): array public static function getRelations(): array
{ {
return [ return [
RelationManagers\AllocationsRelationManager::class, AllocationsRelationManager::class,
RelationManagers\NodesRelationManager::class, NodesRelationManager::class,
]; ];
} }

View File

@ -4,8 +4,15 @@ namespace App\Filament\Resources\NodeResource\Pages;
use App\Filament\Resources\NodeResource; use App\Filament\Resources\NodeResource;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Actions\Action; use Filament\Actions\Action;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Components\Wizard; use Filament\Forms\Components\Wizard;
use Filament\Forms\Components\Wizard\Step;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -23,7 +30,7 @@ class CreateNode extends CreateRecord
return $form return $form
->schema([ ->schema([
Wizard::make([ Wizard::make([
Wizard\Step::make('basic') Step::make('basic')
->label('Basic Settings') ->label('Basic Settings')
->icon('tabler-server') ->icon('tabler-server')
->columnSpanFull() ->columnSpanFull()
@ -34,7 +41,7 @@ class CreateNode extends CreateRecord
'lg' => 4, 'lg' => 4,
]) ])
->schema([ ->schema([
Forms\Components\TextInput::make('fqdn') TextInput::make('fqdn')
->columnSpan(2) ->columnSpan(2)
->required() ->required()
->autofocus() ->autofocus()
@ -67,7 +74,7 @@ class CreateNode extends CreateRecord
return ''; return '';
}) })
->afterStateUpdated(function (Forms\Set $set, ?string $state) { ->afterStateUpdated(function (Set $set, ?string $state) {
$set('dns', null); $set('dns', null);
$set('ip', null); $set('ip', null);
@ -95,17 +102,17 @@ class CreateNode extends CreateRecord
}) })
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('ip') TextInput::make('ip')
->disabled() ->disabled()
->hidden(), ->hidden(),
Forms\Components\ToggleButtons::make('dns') ToggleButtons::make('dns')
->label('DNS Record Check') ->label('DNS Record Check')
->helperText('This lets you know if your DNS record correctly points to an IP Address.') ->helperText('This lets you know if your DNS record correctly points to an IP Address.')
->disabled() ->disabled()
->inline() ->inline()
->default(null) ->default(null)
->hint(fn (Forms\Get $get) => $get('ip')) ->hint(fn (Get $get) => $get('ip'))
->hintColor('success') ->hintColor('success')
->options([ ->options([
true => 'Valid', true => 'Valid',
@ -122,7 +129,7 @@ class CreateNode extends CreateRecord
'lg' => 1, 'lg' => 1,
]), ]),
Forms\Components\TextInput::make('daemon_listen') TextInput::make('daemon_listen')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
'sm' => 1, 'sm' => 1,
@ -137,7 +144,7 @@ class CreateNode extends CreateRecord
->required() ->required()
->integer(), ->integer(),
Forms\Components\TextInput::make('name') TextInput::make('name')
->label('Display Name') ->label('Display Name')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
@ -150,7 +157,7 @@ class CreateNode extends CreateRecord
->helperText('This name is for display only and can be changed later.') ->helperText('This name is for display only and can be changed later.')
->maxLength(100), ->maxLength(100),
Forms\Components\ToggleButtons::make('scheme') ToggleButtons::make('scheme')
->label('Communicate over SSL') ->label('Communicate over SSL')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
@ -159,7 +166,7 @@ class CreateNode extends CreateRecord
'lg' => 1, 'lg' => 1,
]) ])
->inline() ->inline()
->helperText(function (Forms\Get $get) { ->helperText(function (Get $get) {
if (request()->isSecure()) { if (request()->isSecure()) {
return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.'); return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.');
} }
@ -185,7 +192,7 @@ class CreateNode extends CreateRecord
]) ])
->default(fn () => request()->isSecure() ? 'https' : 'http'), ->default(fn () => request()->isSecure() ? 'https' : 'http'),
]), ]),
Wizard\Step::make('advanced') Step::make('advanced')
->label('Advanced Settings') ->label('Advanced Settings')
->icon('tabler-server-cog') ->icon('tabler-server-cog')
->columnSpanFull() ->columnSpanFull()
@ -196,7 +203,7 @@ class CreateNode extends CreateRecord
'lg' => 4, 'lg' => 4,
]) ])
->schema([ ->schema([
Forms\Components\ToggleButtons::make('maintenance_mode') ToggleButtons::make('maintenance_mode')
->label('Maintenance Mode')->inline() ->label('Maintenance Mode')->inline()
->columnSpan(1) ->columnSpan(1)
->default(false) ->default(false)
@ -210,7 +217,7 @@ class CreateNode extends CreateRecord
true => 'danger', true => 'danger',
false => 'success', false => 'success',
]), ]),
Forms\Components\ToggleButtons::make('public') ToggleButtons::make('public')
->default(true) ->default(true)
->columnSpan(1) ->columnSpan(1)
->label('Automatic Allocation')->inline() ->label('Automatic Allocation')->inline()
@ -222,15 +229,14 @@ class CreateNode extends CreateRecord
true => 'success', true => 'success',
false => 'danger', false => 'danger',
]), ]),
Forms\Components\TagsInput::make('tags') TagsInput::make('tags')
->label('Tags') ->label('Tags')
->disabled() ->disabled()
->placeholder('Not Implemented') ->placeholder('Not Implemented')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('Not Implemented') ->hintIconTooltip('Not Implemented')
->columnSpan(2), ->columnSpan(2),
TextInput::make('upload_size')
Forms\Components\TextInput::make('upload_size')
->label('Upload Limit') ->label('Upload Limit')
->helperText('Enter the maximum size of files that can be uploaded through the web-based file manager.') ->helperText('Enter the maximum size of files that can be uploaded through the web-based file manager.')
->columnSpan(1) ->columnSpan(1)
@ -239,7 +245,7 @@ class CreateNode extends CreateRecord
->minValue(1) ->minValue(1)
->maxValue(1024) ->maxValue(1024)
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'), ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'),
Forms\Components\TextInput::make('daemon_sftp') TextInput::make('daemon_sftp')
->columnSpan(1) ->columnSpan(1)
->label('SFTP Port') ->label('SFTP Port')
->minValue(1) ->minValue(1)
@ -247,19 +253,19 @@ class CreateNode extends CreateRecord
->default(2022) ->default(2022)
->required() ->required()
->integer(), ->integer(),
Forms\Components\TextInput::make('daemon_sftp_alias') TextInput::make('daemon_sftp_alias')
->columnSpan(2) ->columnSpan(2)
->label('SFTP Alias') ->label('SFTP Alias')
->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'), ->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'),
Forms\Components\Grid::make() Grid::make()
->columns(6) ->columns(6)
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_mem') ToggleButtons::make('unlimited_mem')
->label('Memory')->inlineLabel()->inline() ->label('Memory')->inlineLabel()->inline()
->afterStateUpdated(fn (Forms\Set $set) => $set('memory', 0)) ->afterStateUpdated(fn (Set $set) => $set('memory', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('memory_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('memory_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('memory') == 0) ->formatStateUsing(fn (Get $get) => $get('memory') == 0)
->live() ->live()
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
@ -270,9 +276,9 @@ class CreateNode extends CreateRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(2), ->columnSpan(2),
Forms\Components\TextInput::make('memory') TextInput::make('memory')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) ->hidden(fn (Get $get) => $get('unlimited_mem'))
->label('Memory Limit')->inlineLabel() ->label('Memory Limit')->inlineLabel()
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB') ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
->columnSpan(2) ->columnSpan(2)
@ -280,10 +286,10 @@ class CreateNode extends CreateRecord
->minValue(0) ->minValue(0)
->default(0) ->default(0)
->required(), ->required(),
Forms\Components\TextInput::make('memory_overallocate') TextInput::make('memory_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) ->hidden(fn (Get $get) => $get('unlimited_mem'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')
->columnSpan(2) ->columnSpan(2)
@ -294,16 +300,16 @@ class CreateNode extends CreateRecord
->suffix('%') ->suffix('%')
->required(), ->required(),
]), ]),
Forms\Components\Grid::make() Grid::make()
->columns(6) ->columns(6)
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_disk') ToggleButtons::make('unlimited_disk')
->label('Disk')->inlineLabel()->inline() ->label('Disk')->inlineLabel()->inline()
->live() ->live()
->afterStateUpdated(fn (Forms\Set $set) => $set('disk', 0)) ->afterStateUpdated(fn (Set $set) => $set('disk', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('disk_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('disk_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('disk') == 0) ->formatStateUsing(fn (Get $get) => $get('disk') == 0)
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
false => 'Limited', false => 'Limited',
@ -313,9 +319,9 @@ class CreateNode extends CreateRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(2), ->columnSpan(2),
Forms\Components\TextInput::make('disk') TextInput::make('disk')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) ->hidden(fn (Get $get) => $get('unlimited_disk'))
->label('Disk Limit')->inlineLabel() ->label('Disk Limit')->inlineLabel()
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB') ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
->columnSpan(2) ->columnSpan(2)
@ -323,9 +329,9 @@ class CreateNode extends CreateRecord
->minValue(0) ->minValue(0)
->default(0) ->default(0)
->required(), ->required(),
Forms\Components\TextInput::make('disk_overallocate') TextInput::make('disk_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) ->hidden(fn (Get $get) => $get('unlimited_disk'))
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')
@ -337,16 +343,16 @@ class CreateNode extends CreateRecord
->suffix('%') ->suffix('%')
->required(), ->required(),
]), ]),
Forms\Components\Grid::make() Grid::make()
->columns(6) ->columns(6)
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_cpu') ToggleButtons::make('unlimited_cpu')
->label('CPU')->inlineLabel()->inline() ->label('CPU')->inlineLabel()->inline()
->live() ->live()
->afterStateUpdated(fn (Forms\Set $set) => $set('cpu', 0)) ->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('cpu_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('cpu_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('cpu') == 0) ->formatStateUsing(fn (Get $get) => $get('cpu') == 0)
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
false => 'Limited', false => 'Limited',
@ -356,9 +362,9 @@ class CreateNode extends CreateRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(2), ->columnSpan(2),
Forms\Components\TextInput::make('cpu') TextInput::make('cpu')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) ->hidden(fn (Get $get) => $get('unlimited_cpu'))
->label('CPU Limit')->inlineLabel() ->label('CPU Limit')->inlineLabel()
->suffix('%') ->suffix('%')
->columnSpan(2) ->columnSpan(2)
@ -366,9 +372,9 @@ class CreateNode extends CreateRecord
->default(0) ->default(0)
->minValue(0) ->minValue(0)
->required(), ->required(),
Forms\Components\TextInput::make('cpu_overallocate') TextInput::make('cpu_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) ->hidden(fn (Get $get) => $get('unlimited_cpu'))
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')

View File

@ -9,7 +9,16 @@ use App\Models\Node;
use App\Services\Nodes\NodeUpdateService; use App\Services\Nodes\NodeUpdateService;
use Filament\Actions; use Filament\Actions;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -32,10 +41,10 @@ class EditNode extends EditRecord
->persistTabInQueryString() ->persistTabInQueryString()
->columnSpanFull() ->columnSpanFull()
->tabs([ ->tabs([
Tabs\Tab::make('Basic Settings') Tab::make('Basic Settings')
->icon('tabler-server') ->icon('tabler-server')
->schema([ ->schema([
Forms\Components\TextInput::make('fqdn') TextInput::make('fqdn')
->columnSpan(2) ->columnSpan(2)
->required() ->required()
->autofocus() ->autofocus()
@ -68,7 +77,7 @@ class EditNode extends EditRecord
return ''; return '';
}) })
->afterStateUpdated(function (Forms\Set $set, ?string $state) { ->afterStateUpdated(function (Set $set, ?string $state) {
$set('dns', null); $set('dns', null);
$set('ip', null); $set('ip', null);
@ -96,17 +105,17 @@ class EditNode extends EditRecord
}) })
->maxLength(255), ->maxLength(255),
Forms\Components\TextInput::make('ip') TextInput::make('ip')
->disabled() ->disabled()
->hidden(), ->hidden(),
Forms\Components\ToggleButtons::make('dns') ToggleButtons::make('dns')
->label('DNS Record Check') ->label('DNS Record Check')
->helperText('This lets you know if your DNS record correctly points to an IP Address.') ->helperText('This lets you know if your DNS record correctly points to an IP Address.')
->disabled() ->disabled()
->inline() ->inline()
->default(null) ->default(null)
->hint(fn (Forms\Get $get) => $get('ip')) ->hint(fn (Get $get) => $get('ip'))
->hintColor('success') ->hintColor('success')
->options([ ->options([
true => 'Valid', true => 'Valid',
@ -123,7 +132,7 @@ class EditNode extends EditRecord
'lg' => 1, 'lg' => 1,
]), ]),
Forms\Components\TextInput::make('daemon_listen') TextInput::make('daemon_listen')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
'sm' => 1, 'sm' => 1,
@ -138,7 +147,7 @@ class EditNode extends EditRecord
->required() ->required()
->integer(), ->integer(),
Forms\Components\TextInput::make('name') TextInput::make('name')
->label('Display Name') ->label('Display Name')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
@ -151,7 +160,7 @@ class EditNode extends EditRecord
->helperText('This name is for display only and can be changed later.') ->helperText('This name is for display only and can be changed later.')
->maxLength(100), ->maxLength(100),
Forms\Components\ToggleButtons::make('scheme') ToggleButtons::make('scheme')
->label('Communicate over SSL') ->label('Communicate over SSL')
->columnSpan([ ->columnSpan([
'default' => 1, 'default' => 1,
@ -160,7 +169,7 @@ class EditNode extends EditRecord
'lg' => 1, 'lg' => 1,
]) ])
->inline() ->inline()
->helperText(function (Forms\Get $get) { ->helperText(function (Get $get) {
if (request()->isSecure()) { if (request()->isSecure()) {
return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.'); return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.');
} }
@ -185,27 +194,27 @@ class EditNode extends EditRecord
'https' => 'tabler-lock', 'https' => 'tabler-lock',
]) ])
->default(fn () => request()->isSecure() ? 'https' : 'http'), ]), ->default(fn () => request()->isSecure() ? 'https' : 'http'), ]),
Tabs\Tab::make('Advanced Settings') Tab::make('Advanced Settings')
->columns(['default' => 1, 'sm' => 1, 'md' => 4, 'lg' => 6]) ->columns(['default' => 1, 'sm' => 1, 'md' => 4, 'lg' => 6])
->icon('tabler-server-cog') ->icon('tabler-server-cog')
->schema([ ->schema([
Forms\Components\TextInput::make('id') TextInput::make('id')
->label('Node ID') ->label('Node ID')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
->disabled(), ->disabled(),
Forms\Components\TextInput::make('uuid') TextInput::make('uuid')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->label('Node UUID') ->label('Node UUID')
->hintAction(CopyAction::make()) ->hintAction(CopyAction::make())
->disabled(), ->disabled(),
Forms\Components\TagsInput::make('tags') TagsInput::make('tags')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
->label('Tags') ->label('Tags')
->disabled() ->disabled()
->placeholder('Not Implemented') ->placeholder('Not Implemented')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('Not Implemented'), ->hintIconTooltip('Not Implemented'),
Forms\Components\TextInput::make('upload_size') TextInput::make('upload_size')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
->label('Upload Limit') ->label('Upload Limit')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
@ -214,7 +223,7 @@ class EditNode extends EditRecord
->minValue(1) ->minValue(1)
->maxValue(1024) ->maxValue(1024)
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'), ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'),
Forms\Components\TextInput::make('daemon_sftp') TextInput::make('daemon_sftp')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
->label('SFTP Port') ->label('SFTP Port')
->minValue(1) ->minValue(1)
@ -222,11 +231,11 @@ class EditNode extends EditRecord
->default(2022) ->default(2022)
->required() ->required()
->integer(), ->integer(),
Forms\Components\TextInput::make('daemon_sftp_alias') TextInput::make('daemon_sftp_alias')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
->label('SFTP Alias') ->label('SFTP Alias')
->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'), ->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'),
Forms\Components\ToggleButtons::make('public') ToggleButtons::make('public')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
->label('Automatic Allocation')->inline() ->label('Automatic Allocation')->inline()
->options([ ->options([
@ -237,7 +246,7 @@ class EditNode extends EditRecord
true => 'success', true => 'success',
false => 'danger', false => 'danger',
]), ]),
Forms\Components\ToggleButtons::make('maintenance_mode') ToggleButtons::make('maintenance_mode')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
->label('Maintenance Mode')->inline() ->label('Maintenance Mode')->inline()
->hinticon('tabler-question-mark') ->hinticon('tabler-question-mark')
@ -250,15 +259,15 @@ class EditNode extends EditRecord
false => 'success', false => 'success',
true => 'danger', true => 'danger',
]), ]),
Forms\Components\Grid::make() Grid::make()
->columns(['default' => 1, 'sm' => 1, 'md' => 3, 'lg' => 6]) ->columns(['default' => 1, 'sm' => 1, 'md' => 3, 'lg' => 6])
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_mem') ToggleButtons::make('unlimited_mem')
->label('Memory')->inlineLabel()->inline() ->label('Memory')->inlineLabel()->inline()
->afterStateUpdated(fn (Forms\Set $set) => $set('memory', 0)) ->afterStateUpdated(fn (Set $set) => $set('memory', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('memory_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('memory_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('memory') == 0) ->formatStateUsing(fn (Get $get) => $get('memory') == 0)
->live() ->live()
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
@ -269,20 +278,20 @@ class EditNode extends EditRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]),
Forms\Components\TextInput::make('memory') TextInput::make('memory')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) ->hidden(fn (Get $get) => $get('unlimited_mem'))
->label('Memory Limit')->inlineLabel() ->label('Memory Limit')->inlineLabel()
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB') ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
->required() ->required()
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2])
->numeric() ->numeric()
->minValue(0), ->minValue(0),
Forms\Components\TextInput::make('memory_overallocate') TextInput::make('memory_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->required() ->required()
->hidden(fn (Forms\Get $get) => $get('unlimited_mem')) ->hidden(fn (Get $get) => $get('unlimited_mem'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2])
@ -291,15 +300,15 @@ class EditNode extends EditRecord
->maxValue(100) ->maxValue(100)
->suffix('%'), ->suffix('%'),
]), ]),
Forms\Components\Grid::make() Grid::make()
->columns(['default' => 1, 'sm' => 1, 'md' => 3, 'lg' => 6]) ->columns(['default' => 1, 'sm' => 1, 'md' => 3, 'lg' => 6])
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_disk') ToggleButtons::make('unlimited_disk')
->label('Disk')->inlineLabel()->inline() ->label('Disk')->inlineLabel()->inline()
->live() ->live()
->afterStateUpdated(fn (Forms\Set $set) => $set('disk', 0)) ->afterStateUpdated(fn (Set $set) => $set('disk', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('disk_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('disk_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('disk') == 0) ->formatStateUsing(fn (Get $get) => $get('disk') == 0)
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
false => 'Limited', false => 'Limited',
@ -309,18 +318,18 @@ class EditNode extends EditRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]), ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]),
Forms\Components\TextInput::make('disk') TextInput::make('disk')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) ->hidden(fn (Get $get) => $get('unlimited_disk'))
->label('Disk Limit')->inlineLabel() ->label('Disk Limit')->inlineLabel()
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB') ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
->required() ->required()
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2]) ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2])
->numeric() ->numeric()
->minValue(0), ->minValue(0),
Forms\Components\TextInput::make('disk_overallocate') TextInput::make('disk_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_disk')) ->hidden(fn (Get $get) => $get('unlimited_disk'))
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')
@ -331,16 +340,16 @@ class EditNode extends EditRecord
->maxValue(100) ->maxValue(100)
->suffix('%'), ->suffix('%'),
]), ]),
Forms\Components\Grid::make() Grid::make()
->columns(6) ->columns(6)
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Forms\Components\ToggleButtons::make('unlimited_cpu') ToggleButtons::make('unlimited_cpu')
->label('CPU')->inlineLabel()->inline() ->label('CPU')->inlineLabel()->inline()
->live() ->live()
->afterStateUpdated(fn (Forms\Set $set) => $set('cpu', 0)) ->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
->afterStateUpdated(fn (Forms\Set $set) => $set('cpu_overallocate', 0)) ->afterStateUpdated(fn (Set $set) => $set('cpu_overallocate', 0))
->formatStateUsing(fn (Forms\Get $get) => $get('cpu') == 0) ->formatStateUsing(fn (Get $get) => $get('cpu') == 0)
->options([ ->options([
true => 'Unlimited', true => 'Unlimited',
false => 'Limited', false => 'Limited',
@ -350,18 +359,18 @@ class EditNode extends EditRecord
false => 'warning', false => 'warning',
]) ])
->columnSpan(2), ->columnSpan(2),
Forms\Components\TextInput::make('cpu') TextInput::make('cpu')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) ->hidden(fn (Get $get) => $get('unlimited_cpu'))
->label('CPU Limit')->inlineLabel() ->label('CPU Limit')->inlineLabel()
->suffix('%') ->suffix('%')
->required() ->required()
->columnSpan(2) ->columnSpan(2)
->numeric() ->numeric()
->minValue(0), ->minValue(0),
Forms\Components\TextInput::make('cpu_overallocate') TextInput::make('cpu_overallocate')
->dehydratedWhenHidden() ->dehydratedWhenHidden()
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu')) ->hidden(fn (Get $get) => $get('unlimited_cpu'))
->label('Overallocate')->inlineLabel() ->label('Overallocate')->inlineLabel()
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The % allowable to go over the set limit.') ->hintIconTooltip('The % allowable to go over the set limit.')
@ -373,15 +382,15 @@ class EditNode extends EditRecord
->suffix('%'), ->suffix('%'),
]), ]),
]), ]),
Tabs\Tab::make('Configuration File') Tab::make('Configuration File')
->icon('tabler-code') ->icon('tabler-code')
->schema([ ->schema([
Forms\Components\Placeholder::make('instructions') Placeholder::make('instructions')
->columnSpanFull() ->columnSpanFull()
->content(new HtmlString(' ->content(new HtmlString('
Save this file to your <span title="usually /etc/pelican/">daemon\'s root directory</span>, named <code>config.yml</code> Save this file to your <span title="usually /etc/pelican/">daemon\'s root directory</span>, named <code>config.yml</code>
')), ')),
Forms\Components\Textarea::make('config') Textarea::make('config')
->label('/etc/pelican/config.yml') ->label('/etc/pelican/config.yml')
->disabled() ->disabled()
->rows(19) ->rows(19)

View File

@ -6,9 +6,13 @@ use App\Filament\Resources\NodeResource;
use App\Models\Node; use App\Models\Node;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\ListRecords; use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Filament\Tables;
class ListNodes extends ListRecords class ListNodes extends ListRecords
{ {
@ -20,70 +24,67 @@ class ListNodes extends ListRecords
->searchable(false) ->searchable(false)
->checkIfRecordIsSelectableUsing(fn (Node $node) => $node->servers_count <= 0) ->checkIfRecordIsSelectableUsing(fn (Node $node) => $node->servers_count <= 0)
->columns([ ->columns([
Tables\Columns\TextColumn::make('uuid') TextColumn::make('uuid')
->label('UUID') ->label('UUID')
->searchable() ->searchable()
->hidden(), ->hidden(),
Tables\Columns\IconColumn::make('health') IconColumn::make('health')
->alignCenter() ->alignCenter()
->state(fn (Node $node) => $node) ->state(fn (Node $node) => $node)
->view('livewire.columns.version-column'), ->view('livewire.columns.version-column'),
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->icon('tabler-server-2') ->icon('tabler-server-2')
->sortable() ->sortable()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('fqdn') TextColumn::make('fqdn')
->visibleFrom('md') ->visibleFrom('md')
->label('Address') ->label('Address')
->icon('tabler-network') ->icon('tabler-network')
->sortable() ->sortable()
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('memory') TextColumn::make('memory')
->visibleFrom('sm') ->visibleFrom('sm')
->icon('tabler-device-desktop-analytics') ->icon('tabler-device-desktop-analytics')
->numeric() ->numeric()
->suffix(config('panel.use_binary_prefix') ? ' GiB' : ' GB') ->suffix(config('panel.use_binary_prefix') ? ' GiB' : ' GB')
->formatStateUsing(fn ($state) => number_format($state / (config('panel.use_binary_prefix') ? 1024 : 1000), 2)) ->formatStateUsing(fn ($state) => number_format($state / (config('panel.use_binary_prefix') ? 1024 : 1000), 2))
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('disk') TextColumn::make('disk')
->visibleFrom('sm') ->visibleFrom('sm')
->icon('tabler-file') ->icon('tabler-file')
->numeric() ->numeric()
->suffix(config('panel.use_binary_prefix') ? ' GiB' : ' GB') ->suffix(config('panel.use_binary_prefix') ? ' GiB' : ' GB')
->formatStateUsing(fn ($state) => number_format($state / (config('panel.use_binary_prefix') ? 1024 : 1000), 2)) ->formatStateUsing(fn ($state) => number_format($state / (config('panel.use_binary_prefix') ? 1024 : 1000), 2))
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('cpu') TextColumn::make('cpu')
->visibleFrom('sm') ->visibleFrom('sm')
->icon('tabler-file') ->icon('tabler-file')
->numeric() ->numeric()
->suffix(' %') ->suffix(' %')
->sortable(), ->sortable(),
Tables\Columns\IconColumn::make('scheme') IconColumn::make('scheme')
->visibleFrom('xl') ->visibleFrom('xl')
->label('SSL') ->label('SSL')
->trueIcon('tabler-lock') ->trueIcon('tabler-lock')
->falseIcon('tabler-lock-open-off') ->falseIcon('tabler-lock-open-off')
->state(fn (Node $node) => $node->scheme === 'https'), ->state(fn (Node $node) => $node->scheme === 'https'),
Tables\Columns\IconColumn::make('public') IconColumn::make('public')
->visibleFrom('lg') ->visibleFrom('lg')
->trueIcon('tabler-eye-check') ->trueIcon('tabler-eye-check')
->falseIcon('tabler-eye-cancel'), ->falseIcon('tabler-eye-cancel'),
Tables\Columns\TextColumn::make('servers_count') TextColumn::make('servers_count')
->visibleFrom('sm') ->visibleFrom('sm')
->counts('servers') ->counts('servers')
->label('Servers') ->label('Servers')
->sortable() ->sortable()
->icon('tabler-brand-docker'), ->icon('tabler-brand-docker'),
]) ])
->filters([
//
])
->actions([ ->actions([
Tables\Actions\EditAction::make(), EditAction::make(),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(), DeleteBulkAction::make(),
]), ]),
]) ])
->emptyStateIcon('tabler-server-2') ->emptyStateIcon('tabler-server-2')

View File

@ -5,10 +5,16 @@ namespace App\Filament\Resources\NodeResource\RelationManagers;
use App\Models\Allocation; use App\Models\Allocation;
use App\Models\Node; use App\Models\Node;
use App\Services\Allocations\AssignmentService; use App\Services\Allocations\AssignmentService;
use Filament\Forms; use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Set;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables; use Filament\Tables;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\TextInputColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -25,7 +31,7 @@ class AllocationsRelationManager extends RelationManager
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\TextInput::make('ip') TextInput::make('ip')
->required() ->required()
->maxLength(255), ->maxLength(255),
]); ]);
@ -43,19 +49,19 @@ class AllocationsRelationManager extends RelationManager
->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null) ->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null)
->searchable() ->searchable()
->columns([ ->columns([
Tables\Columns\TextColumn::make('id'), TextColumn::make('id'),
Tables\Columns\TextColumn::make('port') TextColumn::make('port')
->searchable() ->searchable()
->label('Port'), ->label('Port'),
Tables\Columns\TextColumn::make('server.name') TextColumn::make('server.name')
->label('Server') ->label('Server')
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->searchable() ->searchable()
->url(fn (Allocation $allocation): string => $allocation->server ? route('filament.admin.resources.servers.edit', ['record' => $allocation->server]) : ''), ->url(fn (Allocation $allocation): string => $allocation->server ? route('filament.admin.resources.servers.edit', ['record' => $allocation->server]) : ''),
Tables\Columns\TextInputColumn::make('ip_alias') TextInputColumn::make('ip_alias')
->searchable() ->searchable()
->label('Alias'), ->label('Alias'),
Tables\Columns\TextInputColumn::make('ip') TextInputColumn::make('ip')
->searchable() ->searchable()
->label('IP'), ->label('IP'),
]) ])
@ -68,20 +74,20 @@ class AllocationsRelationManager extends RelationManager
->headerActions([ ->headerActions([
Tables\Actions\Action::make('create new allocation')->label('Create Allocations') Tables\Actions\Action::make('create new allocation')->label('Create Allocations')
->form(fn () => [ ->form(fn () => [
Forms\Components\TextInput::make('allocation_ip') TextInput::make('allocation_ip')
->datalist($this->getOwnerRecord()->ipAddresses()) ->datalist($this->getOwnerRecord()->ipAddresses())
->label('IP Address') ->label('IP Address')
->inlineLabel() ->inlineLabel()
->ipv4() ->ipv4()
->helperText("Usually your machine's public IP unless you are port forwarding.") ->helperText("Usually your machine's public IP unless you are port forwarding.")
->required(), ->required(),
Forms\Components\TextInput::make('allocation_alias') TextInput::make('allocation_alias')
->label('Alias') ->label('Alias')
->inlineLabel() ->inlineLabel()
->default(null) ->default(null)
->helperText('Optional display name to help you remember what these are.') ->helperText('Optional display name to help you remember what these are.')
->required(false), ->required(false),
Forms\Components\TagsInput::make('allocation_ports') TagsInput::make('allocation_ports')
->placeholder('Examples: 27015, 27017-27019') ->placeholder('Examples: 27015, 27017-27019')
->helperText(new HtmlString(' ->helperText(new HtmlString('
These are the ports that users can connect to this Server through. These are the ports that users can connect to this Server through.
@ -91,7 +97,7 @@ class AllocationsRelationManager extends RelationManager
->label('Ports') ->label('Ports')
->inlineLabel() ->inlineLabel()
->live() ->live()
->afterStateUpdated(function ($state, Forms\Set $set) { ->afterStateUpdated(function ($state, Set $set) {
$ports = collect(); $ports = collect();
$update = false; $update = false;
foreach ($state as $portEntry) { foreach ($state as $portEntry) {
@ -145,9 +151,8 @@ class AllocationsRelationManager extends RelationManager
->action(fn (array $data) => resolve(AssignmentService::class)->handle($this->getOwnerRecord(), $data)), ->action(fn (array $data) => resolve(AssignmentService::class)->handle($this->getOwnerRecord(), $data)),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ BulkActionGroup::make([
// Tables\Actions\DissociateBulkAction::make(), DeleteBulkAction::make(),
Tables\Actions\DeleteBulkAction::make(),
]), ]),
]); ]);
} }

View File

@ -3,7 +3,8 @@
namespace App\Filament\Resources\NodeResource\RelationManagers; namespace App\Filament\Resources\NodeResource\RelationManagers;
use App\Models\Server; use App\Models\Server;
use Filament\Tables; use Filament\Tables\Columns\SelectColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table; use Filament\Tables\Table;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
@ -18,34 +19,34 @@ class NodesRelationManager extends RelationManager
return $table return $table
->searchable(false) ->searchable(false)
->columns([ ->columns([
Tables\Columns\TextColumn::make('user.username') TextColumn::make('user.username')
->label('Owner') ->label('Owner')
->icon('tabler-user') ->icon('tabler-user')
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('name') TextColumn::make('name')
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server])) ->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server]))
->searchable() ->searchable()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('egg.name') TextColumn::make('egg.name')
->icon('tabler-egg') ->icon('tabler-egg')
->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->user])) ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->user]))
->sortable(), ->sortable(),
Tables\Columns\SelectColumn::make('allocation.id') SelectColumn::make('allocation.id')
->label('Primary Allocation') ->label('Primary Allocation')
->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address]) ->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address])
->selectablePlaceholder(false) ->selectablePlaceholder(false)
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('memory')->icon('tabler-device-desktop-analytics'), TextColumn::make('memory')->icon('tabler-device-desktop-analytics'),
Tables\Columns\TextColumn::make('cpu')->icon('tabler-cpu'), TextColumn::make('cpu')->icon('tabler-cpu'),
Tables\Columns\TextColumn::make('databases_count') TextColumn::make('databases_count')
->counts('databases') ->counts('databases')
->label('Databases') ->label('Databases')
->icon('tabler-database') ->icon('tabler-database')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('backups_count') TextColumn::make('backups_count')
->counts('backups') ->counts('backups')
->label('Backups') ->label('Backups')
->icon('tabler-file-download') ->icon('tabler-file-download')

View File

@ -3,7 +3,7 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages; use App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource\RelationManagers; use App\Filament\Resources\UserResource\RelationManagers\ServersRelationManager;
use App\Models\User; use App\Models\User;
use Filament\Resources\Resource; use Filament\Resources\Resource;
@ -23,7 +23,7 @@ class UserResource extends Resource
public static function getRelations(): array public static function getRelations(): array
{ {
return [ return [
RelationManagers\ServersRelationManager::class, ServersRelationManager::class,
]; ];
} }