columns([ 'default' => 2, 'sm' => 2, 'md' => 4, 'lg' => 6, ]) ->schema([ Forms\Components\ToggleButtons::make('docker') ->label('Container Status') ->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, ]) ->inline(), Forms\Components\ToggleButtons::make('status') ->label('Server State') ->helperText('') ->inlineLabel() ->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, ]) ->inline(), 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)) ->color('primary') ->action(function (Forms\Set $set, Forms\Get $get) { $egg = Egg::find($get('egg_id')); $prefix = $egg ? str($egg->name)->lower()->kebab() . '-' : ''; $set('name', $prefix . fake()->domainWord); })) ->columnSpan([ 'default' => 2, 'sm' => 4, 'md' => 2, 'lg' => 3, ]) ->required() ->maxLength(191), Forms\Components\Select::make('owner_id') ->prefixIcon('tabler-user') ->default(auth()->user()->id) ->label('Owner') ->columnSpan([ 'default' => 2, 'sm' => 4, 'md' => 2, 'lg' => 3, ]) ->relationship('user', 'username') ->searchable() ->preload() ->required(), Forms\Components\Textarea::make('description') ->hidden() ->default('') ->required() ->columnSpanFull(), Forms\Components\Select::make('egg_id') ->disabledOn('edit') ->prefixIcon('tabler-egg') ->columnSpan([ 'default' => 2, 'sm' => 2, 'md' => 2, 'lg' => 6, ]) ->relationship('egg', 'name') ->searchable() ->preload() ->required(), Forms\Components\ToggleButtons::make('skip_scripts') ->label('Run Egg Install Script?') ->default(false) ->options([ false => 'Yes', true => 'Skip', ]) ->colors([ false => 'primary', true => 'danger', ]) ->icons([ false => 'tabler-code', true => 'tabler-code-off', ]) ->inline() ->required(), Forms\Components\ToggleButtons::make('custom_image') ->live() ->label('Custom Image?') ->default(false) ->formatStateUsing(function ($state, Forms\Get $get) { if ($state !== null) { return $state; } $images = Egg::find($get('egg_id'))->docker_images ?? []; return !in_array($get('image'), $images); }) ->options([ false => 'No', true => 'Yes', ]) ->colors([ false => 'primary', true => 'danger', ]) ->icons([ false => 'tabler-settings-cancel', true => 'tabler-settings-check', ]) ->inline(), Forms\Components\TextInput::make('image') ->hidden(fn (Forms\Get $get) => !$get('custom_image')) ->disabled(fn (Forms\Get $get) => !$get('custom_image')) ->label('Docker Image') ->placeholder('Enter a custom Image') ->columnSpan([ 'default' => 2, 'sm' => 2, 'md' => 2, 'lg' => 4, ]) ->required(), Forms\Components\Select::make('image') ->hidden(fn (Forms\Get $get) => $get('custom_image')) ->disabled(fn (Forms\Get $get) => $get('custom_image')) ->label('Docker Image') ->prefixIcon('tabler-brand-docker') ->options(function (Forms\Get $get, Forms\Set $set) { $images = Egg::find($get('egg_id'))->docker_images ?? []; $set('image', collect($images)->first()); return $images; }) ->disabled(fn (Forms\Components\Select $component) => empty($component->getOptions())) ->selectablePlaceholder(false) ->columnSpan([ 'default' => 2, 'sm' => 2, 'md' => 2, 'lg' => 4, ]) ->required(), Forms\Components\Fieldset::make('Application 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() ->default(0), Forms\Components\TextInput::make('database_limit') ->suffixIcon('tabler-database') ->required() ->numeric() ->default(0), Forms\Components\TextInput::make('backup_limit') ->suffixIcon('tabler-copy-check') ->required() ->numeric() ->default(0), ]), 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')->default(true), 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') ->label('') ->relationship('serverVariables') ->grid() ->deletable(false) ->addable(false) ->schema([ Forms\Components\TextInput::make('variable_value') ->rules([ fn (ServerVariable $variable): Closure => function (string $attribute, $value, Closure $fail) use ($variable) { $validator = Validator::make(['validatorkey' => $value], [ 'validatorkey' => $variable->variable->rules, ]); if ($validator->fails()) { $message = str($validator->errors()->first())->replace('validatorkey', $variable->variable->name); $fail($message); } }, ]) ->label(fn (ServerVariable $variable) => $variable->variable->name) ->hintIcon('tabler-code') ->hintIconTooltip(fn (ServerVariable $variable) => $variable->variable->rules) ->prefix(fn (ServerVariable $variable) => '{{' . $variable->variable->env_variable . '}}') ->helperText(fn (ServerVariable $variable) => $variable->variable->description ?: '—') ->maxLength(191), Forms\Components\Hidden::make('variable_id'), ]) ->columnSpan(2), ]), Forms\Components\Section::make('Resource Management') ->collapsed() ->icon('tabler-server-cog') ->iconColor('primary') ->columns(2) ->columnSpan(([ 'default' => 2, 'sm' => 4, 'md' => 4, 'lg' => 6, ])) ->schema([ Forms\Components\TextInput::make('memory') ->default(0) ->label('Allocated Memory') ->suffix('MB') ->required() ->numeric(), Forms\Components\TextInput::make('swap') ->default(0) ->label('Swap Memory') ->suffix('MB') ->helperText('0 disables swap and -1 allows unlimited swap') ->minValue(-1) ->required() ->numeric(), Forms\Components\TextInput::make('disk') ->default(0) ->label('Disk Space Limit') ->suffix('MB') ->required() ->numeric(), Forms\Components\TextInput::make('cpu') ->default(0) ->label('CPU Limit') ->suffix('%') ->required() ->numeric(), Forms\Components\Hidden::make('io') ->helperText('The IO performance relative to other running containers') ->label('Block IO Proportion') ->required() // ->numeric() // ->minValue(0) // ->maxValue(1000) // ->step(10) ->default(0), Forms\Components\ToggleButtons::make('oom_disabled') ->label('OOM Killer') ->inline() ->default(false) ->options([ false => 'Disabled', true => 'Enabled', ]) ->colors([ false => 'success', true => 'danger', ]) ->icons([ false => 'tabler-sword-off', true => 'tabler-sword', ]) ->required(), ]), ]); } protected function getHeaderActions(): array { return [ Actions\DeleteAction::make('Force Delete') ->label('Force Delete') ->successRedirectUrl(route('filament.admin.resources.servers.index')) ->color('danger') ->after(fn (Server $server) => resolve(ServerDeletionService::class)->withForce()->handle($server)) ->requiresConfirmation(), Actions\DeleteAction::make('Delete') ->successRedirectUrl(route('filament.admin.resources.servers.index')) ->color('danger') ->after(fn (Server $server) => resolve(ServerDeletionService::class)->handle($server)) ->requiresConfirmation(), ]; } protected function mutateFormDataBeforeSave(array $data): array { unset($data['docker'], $data['status']); return $data; } public function getRelationManagers(): array { return [ ServerResource\RelationManagers\AllocationsRelationManager::class, ]; } }