refactor(validation): implement centralized validation patterns across components

- Introduced `ValidationPatterns` class to standardize validation rules and messages for various fields across multiple components.
- Updated components including `General`, `StackForm`, `Create`, and `Show` to utilize the new validation patterns, ensuring consistent validation logic.
- Enhanced error messages for required fields and added regex validation for names and descriptions to improve user feedback.
- Adjusted styling in the `create.blade.php` view for better visual hierarchy.
This commit is contained in:
Andras Bacsai
2025-08-19 14:15:31 +02:00
parent eaee87d008
commit 5c4a265542
19 changed files with 659 additions and 250 deletions

View File

@@ -5,9 +5,9 @@ namespace App\Livewire\Server\New;
use App\Enums\ProxyTypes;
use App\Models\Server;
use App\Models\Team;
use App\Support\ValidationPatterns;
use Illuminate\Support\Collection;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
use Livewire\Component;
class ByIp extends Component
@@ -18,43 +18,30 @@ class ByIp extends Component
#[Locked]
public $limit_reached;
#[Validate('nullable|integer', as: 'Private Key')]
public ?int $private_key_id = null;
#[Validate('nullable|string', as: 'Private Key Name')]
public $new_private_key_name;
#[Validate('nullable|string', as: 'Private Key Description')]
public $new_private_key_description;
#[Validate('nullable|string', as: 'Private Key Value')]
public $new_private_key_value;
#[Validate('required|string', as: 'Name')]
public string $name;
#[Validate('nullable|string', as: 'Description')]
public ?string $description = null;
#[Validate('required|string', as: 'IP Address/Domain')]
public string $ip;
#[Validate('required|string', as: 'User')]
public string $user = 'root';
#[Validate('required|integer|between:1,65535', as: 'Port')]
public int $port = 22;
#[Validate('required|boolean', as: 'Swarm Manager')]
public bool $is_swarm_manager = false;
#[Validate('required|boolean', as: 'Swarm Worker')]
public bool $is_swarm_worker = false;
#[Validate('nullable|integer', as: 'Swarm Cluster')]
public $selected_swarm_cluster = null;
#[Validate('required|boolean', as: 'Build Server')]
public bool $is_build_server = false;
#[Locked]
@@ -70,6 +57,50 @@ class ByIp extends Component
}
}
protected function rules(): array
{
return [
'private_key_id' => 'nullable|integer',
'new_private_key_name' => 'nullable|string',
'new_private_key_description' => 'nullable|string',
'new_private_key_value' => 'nullable|string',
'name' => ValidationPatterns::nameRules(),
'description' => ValidationPatterns::descriptionRules(),
'ip' => 'required|string',
'user' => 'required|string',
'port' => 'required|integer|between:1,65535',
'is_swarm_manager' => 'required|boolean',
'is_swarm_worker' => 'required|boolean',
'selected_swarm_cluster' => 'nullable|integer',
'is_build_server' => 'required|boolean',
];
}
protected function messages(): array
{
return array_merge(ValidationPatterns::combinedMessages(), [
'private_key_id.integer' => 'The Private Key field must be an integer.',
'private_key_id.nullable' => 'The Private Key field is optional.',
'new_private_key_name.string' => 'The Private Key Name must be a string.',
'new_private_key_description.string' => 'The Private Key Description must be a string.',
'new_private_key_value.string' => 'The Private Key Value must be a string.',
'ip.required' => 'The IP Address/Domain is required.',
'ip.string' => 'The IP Address/Domain must be a string.',
'user.required' => 'The User field is required.',
'user.string' => 'The User field must be a string.',
'port.required' => 'The Port field is required.',
'port.integer' => 'The Port field must be an integer.',
'port.between' => 'The Port field must be between 1 and 65535.',
'is_swarm_manager.required' => 'The Swarm Manager field is required.',
'is_swarm_manager.boolean' => 'The Swarm Manager field must be true or false.',
'is_swarm_worker.required' => 'The Swarm Worker field is required.',
'is_swarm_worker.boolean' => 'The Swarm Worker field must be true or false.',
'selected_swarm_cluster.integer' => 'The Swarm Cluster field must be an integer.',
'is_build_server.required' => 'The Build Server field is required.',
'is_build_server.boolean' => 'The Build Server field must be true or false.',
]);
}
public function setPrivateKey(string $private_key_id)
{
$this->private_key_id = $private_key_id;

View File

@@ -6,82 +6,60 @@ use App\Actions\Server\StartSentinel;
use App\Actions\Server\StopSentinel;
use App\Events\ServerReachabilityChanged;
use App\Models\Server;
use App\Support\ValidationPatterns;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
use Livewire\Component;
class Show extends Component
{
public Server $server;
#[Validate(['required'])]
public string $name;
#[Validate(['nullable'])]
public ?string $description = null;
#[Validate(['required'])]
public string $ip;
#[Validate(['required'])]
public string $user;
#[Validate(['required'])]
public string $port;
#[Validate(['nullable'])]
public ?string $validationLogs = null;
#[Validate(['nullable', 'url'])]
public ?string $wildcardDomain = null;
#[Validate(['required'])]
public bool $isReachable;
#[Validate(['required'])]
public bool $isUsable;
#[Validate(['required'])]
public bool $isSwarmManager;
#[Validate(['required'])]
public bool $isSwarmWorker;
#[Validate(['required'])]
public bool $isBuildServer;
#[Locked]
public bool $isBuildServerLocked = false;
#[Validate(['required'])]
public bool $isMetricsEnabled;
#[Validate(['required'])]
public string $sentinelToken;
#[Validate(['nullable'])]
public ?string $sentinelUpdatedAt = null;
#[Validate(['required', 'integer', 'min:1'])]
public int $sentinelMetricsRefreshRateSeconds;
#[Validate(['required', 'integer', 'min:1'])]
public int $sentinelMetricsHistoryDays;
#[Validate(['required', 'integer', 'min:10'])]
public int $sentinelPushIntervalSeconds;
#[Validate(['nullable', 'url'])]
public ?string $sentinelCustomUrl = null;
#[Validate(['required'])]
public bool $isSentinelEnabled;
#[Validate(['required'])]
public bool $isSentinelDebugEnabled;
#[Validate(['required'])]
public string $serverTimezone;
public function getListeners()
@@ -91,6 +69,59 @@ class Show extends Component
];
}
protected function rules(): array
{
return [
'name' => ValidationPatterns::nameRules(),
'description' => ValidationPatterns::descriptionRules(),
'ip' => 'required',
'user' => 'required',
'port' => 'required',
'validationLogs' => 'nullable',
'wildcardDomain' => 'nullable|url',
'isReachable' => 'required',
'isUsable' => 'required',
'isSwarmManager' => 'required',
'isSwarmWorker' => 'required',
'isBuildServer' => 'required',
'isMetricsEnabled' => 'required',
'sentinelToken' => 'required',
'sentinelUpdatedAt' => 'nullable',
'sentinelMetricsRefreshRateSeconds' => 'required|integer|min:1',
'sentinelMetricsHistoryDays' => 'required|integer|min:1',
'sentinelPushIntervalSeconds' => 'required|integer|min:10',
'sentinelCustomUrl' => 'nullable|url',
'isSentinelEnabled' => 'required',
'isSentinelDebugEnabled' => 'required',
'serverTimezone' => 'required',
];
}
protected function messages(): array
{
return array_merge(
ValidationPatterns::combinedMessages(),
[
'ip.required' => 'The IP Address field is required.',
'user.required' => 'The User field is required.',
'port.required' => 'The Port field is required.',
'wildcardDomain.url' => 'The Wildcard Domain must be a valid URL.',
'sentinelToken.required' => 'The Sentinel Token field is required.',
'sentinelMetricsRefreshRateSeconds.required' => 'The Metrics Refresh Rate field is required.',
'sentinelMetricsRefreshRateSeconds.integer' => 'The Metrics Refresh Rate must be an integer.',
'sentinelMetricsRefreshRateSeconds.min' => 'The Metrics Refresh Rate must be at least 1 second.',
'sentinelMetricsHistoryDays.required' => 'The Metrics History Days field is required.',
'sentinelMetricsHistoryDays.integer' => 'The Metrics History Days must be an integer.',
'sentinelMetricsHistoryDays.min' => 'The Metrics History Days must be at least 1 day.',
'sentinelPushIntervalSeconds.required' => 'The Push Interval field is required.',
'sentinelPushIntervalSeconds.integer' => 'The Push Interval must be an integer.',
'sentinelPushIntervalSeconds.min' => 'The Push Interval must be at least 10 seconds.',
'sentinelCustomUrl.url' => 'The Custom Sentinel URL must be a valid URL.',
'serverTimezone.required' => 'The Server Timezone field is required.',
]
);
}
public function mount(string $server_uuid)
{
try {