mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-20 23:54:44 +02:00
Rework Edit Server Page
a WIP, Also functional
This commit is contained in:
parent
15caac51fb
commit
dec1cf8e74
@ -3,7 +3,9 @@
|
|||||||
namespace App\Filament\Resources\ServerResource\Pages;
|
namespace App\Filament\Resources\ServerResource\Pages;
|
||||||
|
|
||||||
use App\Filament\Resources\ServerResource;
|
use App\Filament\Resources\ServerResource;
|
||||||
|
use App\Http\Controllers\Admin\ServersController;
|
||||||
use App\Services\Servers\RandomWordService;
|
use App\Services\Servers\RandomWordService;
|
||||||
|
use App\Services\Servers\SuspensionService;
|
||||||
use Filament\Actions;
|
use Filament\Actions;
|
||||||
use Filament\Forms;
|
use Filament\Forms;
|
||||||
use App\Enums\ContainerStatus;
|
use App\Enums\ContainerStatus;
|
||||||
@ -13,10 +15,12 @@ use App\Models\Server;
|
|||||||
use App\Models\ServerVariable;
|
use App\Models\ServerVariable;
|
||||||
use App\Repositories\Daemon\DaemonServerRepository;
|
use App\Repositories\Daemon\DaemonServerRepository;
|
||||||
use App\Services\Servers\ServerDeletionService;
|
use App\Services\Servers\ServerDeletionService;
|
||||||
|
use Filament\Forms\Components\Tabs;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
|
||||||
|
|
||||||
class EditServer extends EditRecord
|
class EditServer extends EditRecord
|
||||||
{
|
{
|
||||||
@ -25,12 +29,6 @@ class EditServer extends EditRecord
|
|||||||
public function form(Form $form): Form
|
public function form(Form $form): Form
|
||||||
{
|
{
|
||||||
return $form
|
return $form
|
||||||
->columns([
|
|
||||||
'default' => 2,
|
|
||||||
'sm' => 2,
|
|
||||||
'md' => 4,
|
|
||||||
'lg' => 6,
|
|
||||||
])
|
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\ToggleButtons::make('docker')
|
Forms\Components\ToggleButtons::make('docker')
|
||||||
->label('Container Status')->inline()->inlineLabel()
|
->label('Container Status')->inline()->inlineLabel()
|
||||||
@ -82,10 +80,18 @@ class EditServer extends EditRecord
|
|||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
]),
|
]),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('external_id')
|
Tabs::make('Tabs')
|
||||||
->maxLength(191)
|
->persistTabInQueryString()
|
||||||
->hidden(),
|
->columnSpan(6)
|
||||||
|
->columns([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->tabs([
|
||||||
|
Tabs\Tab::make('Information')
|
||||||
|
->schema([
|
||||||
Forms\Components\TextInput::make('name')
|
Forms\Components\TextInput::make('name')
|
||||||
->prefixIcon('tabler-server')
|
->prefixIcon('tabler-server')
|
||||||
->label('Display Name')
|
->label('Display Name')
|
||||||
@ -101,7 +107,7 @@ class EditServer extends EditRecord
|
|||||||
}))
|
}))
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 4,
|
'sm' => 2,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
@ -113,7 +119,7 @@ class EditServer extends EditRecord
|
|||||||
->label('Owner')
|
->label('Owner')
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 4,
|
'sm' => 2,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
@ -123,138 +129,49 @@ class EditServer extends EditRecord
|
|||||||
->required(),
|
->required(),
|
||||||
|
|
||||||
Forms\Components\Textarea::make('description')
|
Forms\Components\Textarea::make('description')
|
||||||
->hidden()
|
->label('Description')
|
||||||
->required()
|
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
|
|
||||||
Forms\Components\Select::make('egg_id')
|
Forms\Components\TextInput::make('uuid')
|
||||||
->disabledOn('edit')
|
->hintAction(CopyAction::make())
|
||||||
->prefixIcon('tabler-egg')
|
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 2,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 5,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
->relationship('egg', 'name')
|
->readOnly(),
|
||||||
->searchable()
|
Forms\Components\TextInput::make('uuid_short')
|
||||||
->preload()
|
->label('Short UUID')
|
||||||
->required(),
|
->hintAction(CopyAction::make())
|
||||||
|
|
||||||
Forms\Components\ToggleButtons::make('skip_scripts')
|
|
||||||
->label('Run Egg Install Script?')->inline()
|
|
||||||
->options([
|
|
||||||
false => 'Yes',
|
|
||||||
true => 'Skip',
|
|
||||||
])
|
|
||||||
->colors([
|
|
||||||
false => 'primary',
|
|
||||||
true => 'danger',
|
|
||||||
])
|
|
||||||
->icons([
|
|
||||||
false => 'tabler-code',
|
|
||||||
true => 'tabler-code-off',
|
|
||||||
])
|
|
||||||
->required(),
|
|
||||||
|
|
||||||
Forms\Components\Textarea::make('startup')
|
|
||||||
->hintIcon('tabler-code')
|
|
||||||
->label('Startup Command')
|
|
||||||
->required()
|
|
||||||
->live()
|
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 4,
|
'sm' => 2,
|
||||||
'md' => 4,
|
'md' => 2,
|
||||||
'lg' => 6,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
->rows(function ($state) {
|
->readOnly(),
|
||||||
return str($state)->explode("\n")->reduce(
|
Forms\Components\TextInput::make('external_id')
|
||||||
fn (int $carry, $line) => $carry + floor(strlen($line) / 125),
|
->label('External ID')
|
||||||
0
|
->columnSpan([
|
||||||
);
|
|
||||||
}),
|
|
||||||
|
|
||||||
Forms\Components\Hidden::make('start_on_completion'),
|
|
||||||
|
|
||||||
Forms\Components\Section::make('Egg Variables')
|
|
||||||
->icon('tabler-eggs')
|
|
||||||
->iconColor('primary')
|
|
||||||
->collapsible()
|
|
||||||
->collapsed()
|
|
||||||
->columnSpan(([
|
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 4,
|
'sm' => 2,
|
||||||
'md' => 4,
|
'md' => 2,
|
||||||
'lg' => 6,
|
'lg' => 3,
|
||||||
]))
|
])
|
||||||
->schema([
|
->maxLength(191),
|
||||||
Forms\Components\Repeater::make('server_variables')
|
Forms\Components\Select::make('node_id')
|
||||||
->relationship('serverVariables')
|
->label('Node')
|
||||||
->grid()
|
->relationship('node', 'name')
|
||||||
->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array {
|
->columnSpan([
|
||||||
foreach ($data as $key => $value) {
|
'default' => 2,
|
||||||
if (!isset($data['variable_value'])) {
|
'sm' => 2,
|
||||||
$data['variable_value'] = '';
|
'md' => 2,
|
||||||
}
|
'lg' => 3,
|
||||||
}
|
])
|
||||||
|
->disabled(),
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
->reorderable(false)->addable(false)->deletable(false)
|
|
||||||
->schema(function () {
|
|
||||||
|
|
||||||
$text = Forms\Components\TextInput::make('variable_value')
|
|
||||||
->hidden($this->shouldHideComponent(...))
|
|
||||||
->maxLength(191)
|
|
||||||
->rules([
|
|
||||||
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
|
|
||||||
$validator = Validator::make(['validatorkey' => $value], [
|
|
||||||
'validatorkey' => $serverVariable->variable->rules,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);
|
|
||||||
|
|
||||||
$fail($message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
$select = Forms\Components\Select::make('variable_value')
|
|
||||||
->hidden($this->shouldHideComponent(...))
|
|
||||||
->options($this->getSelectOptionsFromRules(...))
|
|
||||||
->selectablePlaceholder(false);
|
|
||||||
|
|
||||||
$components = [$text, $select];
|
|
||||||
|
|
||||||
/** @var Forms\Components\Component $component */
|
|
||||||
foreach ($components as &$component) {
|
|
||||||
$component = $component
|
|
||||||
->live(onBlur: true)
|
|
||||||
->hintIcon('tabler-code')
|
|
||||||
->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name)
|
|
||||||
->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules)
|
|
||||||
->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}')
|
|
||||||
->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
})
|
|
||||||
->columnSpan(2),
|
|
||||||
]),
|
]),
|
||||||
|
Tabs\Tab::make('Environment')
|
||||||
Forms\Components\Section::make('Environment Management')
|
|
||||||
->collapsed()
|
|
||||||
->icon('tabler-server-cog')
|
|
||||||
->iconColor('primary')
|
|
||||||
->columns([
|
|
||||||
'default' => 2,
|
|
||||||
'sm' => 4,
|
|
||||||
'md' => 4,
|
|
||||||
'lg' => 4,
|
|
||||||
])
|
|
||||||
->columnSpanFull()
|
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Fieldset::make('Resource Limits')
|
Forms\Components\Fieldset::make('Resource Limits')
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
@ -509,7 +426,7 @@ class EditServer extends EditRecord
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
->placeholder('Enter a custom Image')
|
->placeholder('Enter a custom Image')
|
||||||
->columnSpan(1),
|
->columnSpan(2),
|
||||||
|
|
||||||
Forms\Components\KeyValue::make('docker_labels')
|
Forms\Components\KeyValue::make('docker_labels')
|
||||||
->label('Container Labels')
|
->label('Container Labels')
|
||||||
@ -518,6 +435,201 @@ class EditServer extends EditRecord
|
|||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
Tabs\Tab::make('Egg')
|
||||||
|
->columns([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 3,
|
||||||
|
'md' => 3,
|
||||||
|
'lg' => 5,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Select::make('egg_id')
|
||||||
|
->disabledOn('edit')
|
||||||
|
->prefixIcon('tabler-egg')
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 3,
|
||||||
|
'md' => 3,
|
||||||
|
'lg' => 5,
|
||||||
|
])
|
||||||
|
->relationship('egg', 'name')
|
||||||
|
->searchable()
|
||||||
|
->preload()
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\ToggleButtons::make('skip_scripts')
|
||||||
|
->label('Run Egg Install Script?')->inline()
|
||||||
|
->options([
|
||||||
|
false => 'Yes',
|
||||||
|
true => 'Skip',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
false => 'primary',
|
||||||
|
true => 'danger',
|
||||||
|
])
|
||||||
|
->icons([
|
||||||
|
false => 'tabler-code',
|
||||||
|
true => 'tabler-code-off',
|
||||||
|
])
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\Textarea::make('startup')
|
||||||
|
->label('Startup Command')
|
||||||
|
->required()
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->rows(function ($state) {
|
||||||
|
return str($state)->explode("\n")->reduce(
|
||||||
|
fn (int $carry, $line) => $carry + floor(strlen($line) / 125),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
Forms\Components\Textarea::make('defaultStartup')
|
||||||
|
->hintAction(CopyAction::make())
|
||||||
|
->label('Default Startup Command')
|
||||||
|
->disabled()
|
||||||
|
->formatStateUsing(function ($state, Forms\Get $get, Forms\Set $set) {
|
||||||
|
$egg = Egg::query()->find($get('egg_id'));
|
||||||
|
|
||||||
|
return $egg->startup;
|
||||||
|
})
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Repeater::make('server_variables')
|
||||||
|
->relationship('serverVariables')
|
||||||
|
->grid()
|
||||||
|
->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array {
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (!isset($data['variable_value'])) {
|
||||||
|
$data['variable_value'] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
})
|
||||||
|
->reorderable(false)->addable(false)->deletable(false)
|
||||||
|
->schema(function () {
|
||||||
|
|
||||||
|
$text = Forms\Components\TextInput::make('variable_value')
|
||||||
|
->hidden($this->shouldHideComponent(...))
|
||||||
|
->maxLength(191)
|
||||||
|
->rules([
|
||||||
|
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
|
||||||
|
$validator = Validator::make(['validatorkey' => $value], [
|
||||||
|
'validatorkey' => $serverVariable->variable->rules,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);
|
||||||
|
|
||||||
|
$fail($message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$select = Forms\Components\Select::make('variable_value')
|
||||||
|
->hidden($this->shouldHideComponent(...))
|
||||||
|
->options($this->getSelectOptionsFromRules(...))
|
||||||
|
->selectablePlaceholder(false);
|
||||||
|
|
||||||
|
$components = [$text, $select];
|
||||||
|
|
||||||
|
/** @var Forms\Components\Component $component */
|
||||||
|
foreach ($components as &$component) {
|
||||||
|
$component = $component
|
||||||
|
->live(onBlur: true)
|
||||||
|
->hintIcon('tabler-code')
|
||||||
|
->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name)
|
||||||
|
->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules)
|
||||||
|
->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}')
|
||||||
|
->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $components;
|
||||||
|
})
|
||||||
|
->columnSpan(6),
|
||||||
|
]),
|
||||||
|
Tabs\Tab::make('Mounts'),
|
||||||
|
Tabs\Tab::make('Databases'),
|
||||||
|
Tabs\Tab::make('Actions')
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Fieldset::make('Server Actions')
|
||||||
|
->columns([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columnSpan(3)
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Actions::make([
|
||||||
|
Forms\Components\Actions\Action::make('toggleInstall')
|
||||||
|
->label('Toggle Status')
|
||||||
|
->action(fn (ServersController $serversController, Server $server) => $serversController->toggleInstall($server)),
|
||||||
|
])->fullWidth(),
|
||||||
|
Forms\Components\ToggleButtons::make('')
|
||||||
|
->hint('If you need to change the install status from uninstalled to installed, or vice versa, you may do so with this button.'),
|
||||||
|
]),
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columnSpan(3)
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Actions::make([
|
||||||
|
Forms\Components\Actions\Action::make('toggleSuspend')
|
||||||
|
->label('Suspend')
|
||||||
|
->color('warning')
|
||||||
|
->hidden(fn (Server $server) => $server->isSuspended())
|
||||||
|
->action(fn (SuspensionService $suspensionService, Server $server) => $suspensionService->toggle($server, 'suspend')),
|
||||||
|
Forms\Components\Actions\Action::make('toggleUnsuspend')
|
||||||
|
->label('Unsuspend')
|
||||||
|
->color('success')
|
||||||
|
->hidden(fn (Server $server) => !$server->isSuspended())
|
||||||
|
->action(fn (SuspensionService $suspensionService, Server $server) => $suspensionService->toggle($server, 'unsuspend')),
|
||||||
|
])->fullWidth(),
|
||||||
|
Forms\Components\ToggleButtons::make('')
|
||||||
|
->hidden(fn (Server $server) => $server->isSuspended())
|
||||||
|
->hint('This will suspend the server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the server through the panel or API.'),
|
||||||
|
Forms\Components\ToggleButtons::make('')
|
||||||
|
->hidden(fn (Server $server) => !$server->isSuspended())
|
||||||
|
->hint('This will unsuspend the server and restore normal user access.'),
|
||||||
|
]),
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columnSpan(3)
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Actions::make([
|
||||||
|
Forms\Components\Actions\Action::make('transfer')
|
||||||
|
->label('Transfer'),
|
||||||
|
])->fullWidth(),
|
||||||
|
Forms\Components\ToggleButtons::make('')
|
||||||
|
->hint('Transfer this server to another node connected to this panel. Warning! This feature has not been fully tested and may have bugs.'),
|
||||||
|
]),
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columnSpan(3)
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Actions::make([
|
||||||
|
Forms\Components\Actions\Action::make('reinstall')
|
||||||
|
->label('Reinstall')
|
||||||
|
->color('danger')
|
||||||
|
->requiresConfirmation()
|
||||||
|
->action(fn (ServersController $serversController, Server $server) => $serversController->reinstallServer($server)),
|
||||||
|
])->fullWidth(),
|
||||||
|
Forms\Components\ToggleButtons::make('')
|
||||||
|
->hint('This will reinstall the server with the assigned egg scripts. Danger! This could overwrite server data.'),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
@ -543,6 +655,10 @@ class EditServer extends EditRecord
|
|||||||
|
|
||||||
protected function mutateFormDataBeforeSave(array $data): array
|
protected function mutateFormDataBeforeSave(array $data): array
|
||||||
{
|
{
|
||||||
|
if (!isset($data['description'])) {
|
||||||
|
$data['description'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
unset($data['docker'], $data['status']);
|
unset($data['docker'], $data['status']);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
588
app/Filament/Resources/ServerResource/Pages/EditServerOrg.php
Normal file
588
app/Filament/Resources/ServerResource/Pages/EditServerOrg.php
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\ServerResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\ServerResource;
|
||||||
|
use App\Services\Servers\RandomWordService;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Forms;
|
||||||
|
use App\Enums\ContainerStatus;
|
||||||
|
use App\Enums\ServerState;
|
||||||
|
use App\Models\Egg;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\ServerVariable;
|
||||||
|
use App\Repositories\Daemon\DaemonServerRepository;
|
||||||
|
use App\Services\Servers\ServerDeletionService;
|
||||||
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class EditServerOrg extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = ServerResource::class;
|
||||||
|
|
||||||
|
public function form(Form $form): Form
|
||||||
|
{
|
||||||
|
return $form
|
||||||
|
->columns([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('docker')
|
||||||
|
->label('Container Status')->inline()->inlineLabel()
|
||||||
|
->formatStateUsing(function ($state, Server $server) {
|
||||||
|
if ($server->node_id === null) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var DaemonServerRepository $service */
|
||||||
|
$service = resolve(DaemonServerRepository::class);
|
||||||
|
$details = $service->setServer($server)->getDetails();
|
||||||
|
|
||||||
|
return $details['state'] ?? 'unknown';
|
||||||
|
})
|
||||||
|
->options(fn ($state) => collect(ContainerStatus::cases())->filter(fn ($containerStatus) => $containerStatus->value === $state)->mapWithKeys(
|
||||||
|
fn (ContainerStatus $state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()]
|
||||||
|
))
|
||||||
|
->colors(collect(ContainerStatus::cases())->mapWithKeys(
|
||||||
|
fn (ContainerStatus $status) => [$status->value => $status->color()]
|
||||||
|
))
|
||||||
|
->icons(collect(ContainerStatus::cases())->mapWithKeys(
|
||||||
|
fn (ContainerStatus $status) => [$status->value => $status->icon()]
|
||||||
|
))
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 3,
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\ToggleButtons::make('status')
|
||||||
|
->label('Server State')->inline()->inlineLabel()
|
||||||
|
->helperText('')
|
||||||
|
|
||||||
|
->formatStateUsing(fn ($state) => $state ?? ServerState::Normal)
|
||||||
|
->options(fn ($state) => collect(ServerState::cases())->filter(fn ($serverState) => $serverState->value === $state)->mapWithKeys(
|
||||||
|
fn (ServerState $state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()]
|
||||||
|
))
|
||||||
|
->colors(collect(ServerState::cases())->mapWithKeys(
|
||||||
|
fn (ServerState $state) => [$state->value => $state->color()]
|
||||||
|
))
|
||||||
|
->icons(collect(ServerState::cases())->mapWithKeys(
|
||||||
|
fn (ServerState $state) => [$state->value => $state->icon()]
|
||||||
|
))
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 3,
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('external_id')
|
||||||
|
->maxLength(191)
|
||||||
|
->hidden(),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('name')
|
||||||
|
->prefixIcon('tabler-server')
|
||||||
|
->label('Display Name')
|
||||||
|
->suffixAction(Forms\Components\Actions\Action::make('random')
|
||||||
|
->icon('tabler-dice-' . random_int(1, 6))
|
||||||
|
->action(function (Forms\Set $set, Forms\Get $get) {
|
||||||
|
$egg = Egg::find($get('egg_id'));
|
||||||
|
$prefix = $egg ? str($egg->name)->lower()->kebab() . '-' : '';
|
||||||
|
|
||||||
|
$word = (new RandomWordService())->word();
|
||||||
|
|
||||||
|
$set('name', $prefix . $word);
|
||||||
|
}))
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 3,
|
||||||
|
])
|
||||||
|
->required()
|
||||||
|
->maxLength(191),
|
||||||
|
|
||||||
|
Forms\Components\Select::make('owner_id')
|
||||||
|
->prefixIcon('tabler-user')
|
||||||
|
->label('Owner')
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 3,
|
||||||
|
])
|
||||||
|
->relationship('user', 'username')
|
||||||
|
->searchable()
|
||||||
|
->preload()
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\Textarea::make('description')
|
||||||
|
->hidden()
|
||||||
|
->required()
|
||||||
|
->columnSpanFull(),
|
||||||
|
|
||||||
|
Forms\Components\Select::make('egg_id')
|
||||||
|
->disabledOn('edit')
|
||||||
|
->prefixIcon('tabler-egg')
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 2,
|
||||||
|
'lg' => 5,
|
||||||
|
])
|
||||||
|
->relationship('egg', 'name')
|
||||||
|
->searchable()
|
||||||
|
->preload()
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\ToggleButtons::make('skip_scripts')
|
||||||
|
->label('Run Egg Install Script?')->inline()
|
||||||
|
->options([
|
||||||
|
false => 'Yes',
|
||||||
|
true => 'Skip',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
false => 'primary',
|
||||||
|
true => 'danger',
|
||||||
|
])
|
||||||
|
->icons([
|
||||||
|
false => 'tabler-code',
|
||||||
|
true => 'tabler-code-off',
|
||||||
|
])
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\Textarea::make('startup')
|
||||||
|
->hintIcon('tabler-code')
|
||||||
|
->label('Startup Command')
|
||||||
|
->required()
|
||||||
|
->live()
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->rows(function ($state) {
|
||||||
|
return str($state)->explode("\n")->reduce(
|
||||||
|
fn (int $carry, $line) => $carry + floor(strlen($line) / 125),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
Forms\Components\Hidden::make('start_on_completion'),
|
||||||
|
|
||||||
|
Forms\Components\Section::make('Egg Variables')
|
||||||
|
->icon('tabler-eggs')
|
||||||
|
->iconColor('primary')
|
||||||
|
->collapsible()
|
||||||
|
->collapsed()
|
||||||
|
->columnSpan(([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
]))
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Repeater::make('server_variables')
|
||||||
|
->relationship('serverVariables')
|
||||||
|
->grid()
|
||||||
|
->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array {
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (!isset($data['variable_value'])) {
|
||||||
|
$data['variable_value'] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
})
|
||||||
|
->reorderable(false)->addable(false)->deletable(false)
|
||||||
|
->schema(function () {
|
||||||
|
|
||||||
|
$text = Forms\Components\TextInput::make('variable_value')
|
||||||
|
->hidden($this->shouldHideComponent(...))
|
||||||
|
->maxLength(191)
|
||||||
|
->rules([
|
||||||
|
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
|
||||||
|
$validator = Validator::make(['validatorkey' => $value], [
|
||||||
|
'validatorkey' => $serverVariable->variable->rules,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);
|
||||||
|
|
||||||
|
$fail($message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$select = Forms\Components\Select::make('variable_value')
|
||||||
|
->hidden($this->shouldHideComponent(...))
|
||||||
|
->options($this->getSelectOptionsFromRules(...))
|
||||||
|
->selectablePlaceholder(false);
|
||||||
|
|
||||||
|
$components = [$text, $select];
|
||||||
|
|
||||||
|
/** @var Forms\Components\Component $component */
|
||||||
|
foreach ($components as &$component) {
|
||||||
|
$component = $component
|
||||||
|
->live(onBlur: true)
|
||||||
|
->hintIcon('tabler-code')
|
||||||
|
->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name)
|
||||||
|
->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules)
|
||||||
|
->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}')
|
||||||
|
->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $components;
|
||||||
|
})
|
||||||
|
->columnSpan(2),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Section::make('Environment Management')
|
||||||
|
->collapsed()
|
||||||
|
->icon('tabler-server-cog')
|
||||||
|
->iconColor('primary')
|
||||||
|
->columns([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 4,
|
||||||
|
])
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Fieldset::make('Resource Limits')
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->columns([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 3,
|
||||||
|
'lg' => 3,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columns(4)
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('unlimited_mem')
|
||||||
|
->label('Memory')->inlineLabel()->inline()
|
||||||
|
->afterStateUpdated(fn (Forms\Set $set) => $set('memory', 0))
|
||||||
|
->formatStateUsing(fn (Forms\Get $get) => $get('memory') == 0)
|
||||||
|
->live()
|
||||||
|
->options([
|
||||||
|
true => 'Unlimited',
|
||||||
|
false => 'Limited',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
true => 'primary',
|
||||||
|
false => 'warning',
|
||||||
|
])
|
||||||
|
->columnSpan(2),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('memory')
|
||||||
|
->dehydratedWhenHidden()
|
||||||
|
->hidden(fn (Forms\Get $get) => $get('unlimited_mem'))
|
||||||
|
->label('Memory Limit')->inlineLabel()
|
||||||
|
->suffix('MiB')
|
||||||
|
->required()
|
||||||
|
->columnSpan(2)
|
||||||
|
->numeric()
|
||||||
|
->minValue(0),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columns(4)
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('unlimited_disk')
|
||||||
|
->label('Disk Space')->inlineLabel()->inline()
|
||||||
|
->live()
|
||||||
|
->afterStateUpdated(fn (Forms\Set $set) => $set('disk', 0))
|
||||||
|
->formatStateUsing(fn (Forms\Get $get) => $get('disk') == 0)
|
||||||
|
->options([
|
||||||
|
true => 'Unlimited',
|
||||||
|
false => 'Limited',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
true => 'primary',
|
||||||
|
false => 'warning',
|
||||||
|
])
|
||||||
|
->columnSpan(2),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('disk')
|
||||||
|
->dehydratedWhenHidden()
|
||||||
|
->hidden(fn (Forms\Get $get) => $get('unlimited_disk'))
|
||||||
|
->label('Disk Space Limit')->inlineLabel()
|
||||||
|
->suffix('MiB')
|
||||||
|
->required()
|
||||||
|
->columnSpan(2)
|
||||||
|
->numeric()
|
||||||
|
->minValue(0),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columns(4)
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('unlimited_cpu')
|
||||||
|
->label('CPU')->inlineLabel()->inline()
|
||||||
|
->afterStateUpdated(fn (Forms\Set $set) => $set('cpu', 0))
|
||||||
|
->formatStateUsing(fn (Forms\Get $get) => $get('cpu') == 0)
|
||||||
|
->live()
|
||||||
|
->options([
|
||||||
|
true => 'Unlimited',
|
||||||
|
false => 'Limited',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
true => 'primary',
|
||||||
|
false => 'warning',
|
||||||
|
])
|
||||||
|
->columnSpan(2),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('cpu')
|
||||||
|
->dehydratedWhenHidden()
|
||||||
|
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu'))
|
||||||
|
->label('CPU Limit')->inlineLabel()
|
||||||
|
->suffix('%')
|
||||||
|
->required()
|
||||||
|
->columnSpan(2)
|
||||||
|
->numeric()
|
||||||
|
->minValue(0),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columns(4)
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('swap_support')
|
||||||
|
->live()
|
||||||
|
->label('Enable Swap Memory')->inlineLabel()->inline()
|
||||||
|
->columnSpan(2)
|
||||||
|
->afterStateUpdated(function ($state, Forms\Set $set) {
|
||||||
|
$value = match ($state) {
|
||||||
|
'unlimited' => -1,
|
||||||
|
'disabled' => 0,
|
||||||
|
'limited' => 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
$set('swap', $value);
|
||||||
|
})
|
||||||
|
->formatStateUsing(function (Forms\Get $get) {
|
||||||
|
return match (true) {
|
||||||
|
$get('swap') > 0 => 'limited',
|
||||||
|
$get('swap') == 0 => 'disabled',
|
||||||
|
$get('swap') < 0 => 'unlimited',
|
||||||
|
};
|
||||||
|
})
|
||||||
|
->options([
|
||||||
|
'unlimited' => 'Unlimited',
|
||||||
|
'limited' => 'Limited',
|
||||||
|
'disabled' => 'Disabled',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
'unlimited' => 'primary',
|
||||||
|
'limited' => 'warning',
|
||||||
|
'disabled' => 'danger',
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('swap')
|
||||||
|
->dehydratedWhenHidden()
|
||||||
|
->hidden(fn (Forms\Get $get) => match ($get('swap_support')) {
|
||||||
|
'disabled', 'unlimited', true => true,
|
||||||
|
'limited', false => false,
|
||||||
|
})
|
||||||
|
->label('Swap Memory')->inlineLabel()
|
||||||
|
->suffix('MiB')
|
||||||
|
->minValue(-1)
|
||||||
|
->columnSpan(2)
|
||||||
|
->required()
|
||||||
|
->integer(),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Hidden::make('io')
|
||||||
|
->helperText('The IO performance relative to other running containers')
|
||||||
|
->label('Block IO Proportion'),
|
||||||
|
|
||||||
|
Forms\Components\Grid::make()
|
||||||
|
->columns(4)
|
||||||
|
->columnSpanFull()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\ToggleButtons::make('oom_killer')
|
||||||
|
->label('OOM Killer')->inlineLabel()->inline()
|
||||||
|
->columnSpan(2)
|
||||||
|
->options([
|
||||||
|
false => 'Disabled',
|
||||||
|
true => 'Enabled',
|
||||||
|
])
|
||||||
|
->colors([
|
||||||
|
false => 'success',
|
||||||
|
true => 'danger',
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('oom_disabled_hidden')
|
||||||
|
->hidden(),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
Forms\Components\Fieldset::make('Feature Limits')
|
||||||
|
->inlineLabel()
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->columns([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 3,
|
||||||
|
'lg' => 3,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\TextInput::make('allocation_limit')
|
||||||
|
->suffixIcon('tabler-network')
|
||||||
|
->required()
|
||||||
|
->numeric(),
|
||||||
|
Forms\Components\TextInput::make('database_limit')
|
||||||
|
->suffixIcon('tabler-database')
|
||||||
|
->required()
|
||||||
|
->numeric(),
|
||||||
|
Forms\Components\TextInput::make('backup_limit')
|
||||||
|
->suffixIcon('tabler-copy-check')
|
||||||
|
->required()
|
||||||
|
->numeric(),
|
||||||
|
]),
|
||||||
|
Forms\Components\Fieldset::make('Docker Settings')
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 4,
|
||||||
|
'md' => 4,
|
||||||
|
'lg' => 6,
|
||||||
|
])
|
||||||
|
->columns([
|
||||||
|
'default' => 1,
|
||||||
|
'sm' => 2,
|
||||||
|
'md' => 3,
|
||||||
|
'lg' => 3,
|
||||||
|
])
|
||||||
|
->schema([
|
||||||
|
Forms\Components\Select::make('select_image')
|
||||||
|
->label('Image Name')
|
||||||
|
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('image', $state))
|
||||||
|
->options(function ($state, Forms\Get $get, Forms\Set $set) {
|
||||||
|
$egg = Egg::query()->find($get('egg_id'));
|
||||||
|
$images = $egg->docker_images ?? [];
|
||||||
|
|
||||||
|
$currentImage = $get('image');
|
||||||
|
if (!$currentImage && $images) {
|
||||||
|
$defaultImage = collect($images)->first();
|
||||||
|
$set('image', $defaultImage);
|
||||||
|
$set('select_image', $defaultImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_flip($images) + ['ghcr.io/custom-image' => 'Custom Image'];
|
||||||
|
})
|
||||||
|
->selectablePlaceholder(false)
|
||||||
|
->columnSpan(1),
|
||||||
|
|
||||||
|
Forms\Components\TextInput::make('image')
|
||||||
|
->label('Image')
|
||||||
|
->debounce(500)
|
||||||
|
->afterStateUpdated(function ($state, Forms\Get $get, Forms\Set $set) {
|
||||||
|
$egg = Egg::query()->find($get('egg_id'));
|
||||||
|
$images = $egg->docker_images ?? [];
|
||||||
|
|
||||||
|
if (in_array($state, $images)) {
|
||||||
|
$set('select_image', $state);
|
||||||
|
} else {
|
||||||
|
$set('select_image', 'ghcr.io/custom-image');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->placeholder('Enter a custom Image')
|
||||||
|
->columnSpan(1),
|
||||||
|
|
||||||
|
Forms\Components\KeyValue::make('docker_labels')
|
||||||
|
->label('Container Labels')
|
||||||
|
->keyLabel('Label Name')
|
||||||
|
->valueLabel('Label Description')
|
||||||
|
->columnSpanFull(),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\DeleteAction::make('Delete')
|
||||||
|
->successRedirectUrl(route('filament.admin.resources.servers.index'))
|
||||||
|
->color('danger')
|
||||||
|
->after(fn (Server $server) => resolve(ServerDeletionService::class)->handle($server))
|
||||||
|
->requiresConfirmation(),
|
||||||
|
Actions\Action::make('console')
|
||||||
|
->label('Console')
|
||||||
|
->icon('tabler-terminal')
|
||||||
|
->url(fn (Server $server) => "/server/$server->uuid_short"),
|
||||||
|
$this->getSaveFormAction()->formId('form'),
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
protected function getFormActions(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mutateFormDataBeforeSave(array $data): array
|
||||||
|
{
|
||||||
|
unset($data['docker'], $data['status']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelationManagers(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
ServerResource\RelationManagers\AllocationsRelationManager::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldHideComponent(Forms\Get $get, Forms\Components\Component $component): bool
|
||||||
|
{
|
||||||
|
$containsRuleIn = str($get('rules'))->explode('|')->reduce(
|
||||||
|
fn ($result, $value) => $result === true && !str($value)->startsWith('in:'), true
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($component instanceof Forms\Components\Select) {
|
||||||
|
return $containsRuleIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($component instanceof Forms\Components\TextInput) {
|
||||||
|
return !$containsRuleIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception('Component type not supported: ' . $component::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSelectOptionsFromRules(Forms\Get $get): array
|
||||||
|
{
|
||||||
|
$inRule = str($get('rules'))->explode('|')->reduce(
|
||||||
|
fn ($result, $value) => str($value)->startsWith('in:') ? $value : $result, ''
|
||||||
|
);
|
||||||
|
|
||||||
|
return str($inRule)
|
||||||
|
->after('in:')
|
||||||
|
->explode(',')
|
||||||
|
->each(fn ($value) => str($value)->trim())
|
||||||
|
->mapWithKeys(fn ($value) => [$value => $value])
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Enums\ServerState;
|
use App\Enums\ServerState;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -70,7 +71,7 @@ class ServersController extends Controller
|
|||||||
* @throws \App\Exceptions\DisplayException
|
* @throws \App\Exceptions\DisplayException
|
||||||
* @throws \App\Exceptions\Model\DataValidationException
|
* @throws \App\Exceptions\Model\DataValidationException
|
||||||
*/
|
*/
|
||||||
public function toggleInstall(Server $server): RedirectResponse
|
public function toggleInstall(Server $server)
|
||||||
{
|
{
|
||||||
if ($server->status === ServerState::InstallFailed) {
|
if ($server->status === ServerState::InstallFailed) {
|
||||||
throw new DisplayException(trans('admin/server.exceptions.marked_as_failed'));
|
throw new DisplayException(trans('admin/server.exceptions.marked_as_failed'));
|
||||||
@ -79,9 +80,13 @@ class ServersController extends Controller
|
|||||||
$server->status = $server->isInstalled() ? ServerState::Installing : null;
|
$server->status = $server->isInstalled() ? ServerState::Installing : null;
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
$this->alert->success(trans('admin/server.alerts.install_toggled'))->flash();
|
Notification::make()
|
||||||
|
->title('Success!')
|
||||||
|
->body(trans('admin/server.alerts.install_toggled'))
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
|
|
||||||
return redirect()->route('admin.servers.view.manage', $server->id);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,12 +95,15 @@ class ServersController extends Controller
|
|||||||
* @throws \App\Exceptions\DisplayException
|
* @throws \App\Exceptions\DisplayException
|
||||||
* @throws \App\Exceptions\Model\DataValidationException
|
* @throws \App\Exceptions\Model\DataValidationException
|
||||||
*/
|
*/
|
||||||
public function reinstallServer(Server $server): RedirectResponse
|
public function reinstallServer(Server $server)
|
||||||
{
|
{
|
||||||
$this->reinstallService->handle($server);
|
$this->reinstallService->handle($server);
|
||||||
$this->alert->success(trans('admin/server.alerts.server_reinstalled'))->flash();
|
|
||||||
|
|
||||||
return redirect()->route('admin.servers.view.manage', $server->id);
|
Notification::make()
|
||||||
|
->title('Success!')
|
||||||
|
->body(trans('admin/server.alerts.server_reinstalled'))
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Services\Servers;
|
namespace App\Services\Servers;
|
||||||
|
|
||||||
use App\Enums\ServerState;
|
use App\Enums\ServerState;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Webmozart\Assert\Assert;
|
use Webmozart\Assert\Assert;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Repositories\Daemon\DaemonServerRepository;
|
use App\Repositories\Daemon\DaemonServerRepository;
|
||||||
@ -26,7 +27,7 @@ class SuspensionService
|
|||||||
*
|
*
|
||||||
* @throws \Throwable
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function toggle(Server $server, string $action = self::ACTION_SUSPEND): void
|
public function toggle(Server $server, string $action = self::ACTION_SUSPEND)
|
||||||
{
|
{
|
||||||
Assert::oneOf($action, [self::ACTION_SUSPEND, self::ACTION_UNSUSPEND]);
|
Assert::oneOf($action, [self::ACTION_SUSPEND, self::ACTION_UNSUSPEND]);
|
||||||
|
|
||||||
@ -35,11 +36,12 @@ class SuspensionService
|
|||||||
// suspended in the database. Additionally, nothing needs to happen if the server
|
// suspended in the database. Additionally, nothing needs to happen if the server
|
||||||
// is not suspended, and we try to un-suspend the instance.
|
// is not suspended, and we try to un-suspend the instance.
|
||||||
if ($isSuspending === $server->isSuspended()) {
|
if ($isSuspending === $server->isSuspended()) {
|
||||||
return;
|
return Notification::make()->danger()->title('Failed!')->body('Server is already suspended!')->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the server is currently being transferred.
|
// Check if the server is currently being transferred.
|
||||||
if (!is_null($server->transfer)) {
|
if (!is_null($server->transfer)) {
|
||||||
|
Notification::make()->danger()->title('Failed!')->body('Server is currently being transferred.')->send();
|
||||||
throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.');
|
throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user