Enhance Proxmox views with improved loading states and UI updates

- Updated serverplaceholder.blade.php to enhance loading skeletons for server details.
- Added navigation breadcrumbs to statistics, subdomain, and system views for better user experience.
- Improved loading indicators for CPU, network, memory, and disk charts in statistics.blade.php.
- Refined storage.blade.php layout with section dividers and improved drive display, including bus type indicators and quota usage.
- Enhanced VNC and Xterm popups with a new header design, loading animations, and reconnect functionality.
- Added error handling for VNC and Xterm connections to inform users when unable to connect.
This commit is contained in:
2026-02-24 19:51:46 -05:00
parent af62a16354
commit 16cd5f05de
40 changed files with 1423 additions and 475 deletions

View File

@@ -408,6 +408,13 @@ class Firewall extends Component
public function toggleAdapterFirewall(string $adapter): void
{
// Validate adapter name format to prevent arbitrary config key injection
if (!preg_match('/^net\d+$/', $adapter)) {
$this->error = 'Invalid network adapter name';
$this->showErrorModal = true;
return;
}
$this->loading = true;
try {
@@ -531,6 +538,18 @@ class Firewall extends Component
$this->loading = true;
try {
$allowedPolicies = ['ACCEPT', 'DROP', 'REJECT'];
if (!in_array($this->policyIn, $allowedPolicies, true)) {
$this->error = 'Invalid inbound policy. Must be one of: ' . implode(', ', $allowedPolicies);
$this->showErrorModal = true;
return;
}
if (!in_array($this->policyOut, $allowedPolicies, true)) {
$this->error = 'Invalid outbound policy. Must be one of: ' . implode(', ', $allowedPolicies);
$this->showErrorModal = true;
return;
}
$response = $this->firewallRequest(
'/nodes/' . $this->server->node->name . '/qemu/' . $this->server->vm_id . '/firewall/options',
'put',
@@ -649,6 +668,25 @@ class Firewall extends Component
$this->loading = true;
try {
$allowedActions = ['ACCEPT', 'DROP', 'REJECT'];
if (!in_array($this->ruleAction, $allowedActions, true)) {
$this->error = 'Invalid rule action. Must be one of: ' . implode(', ', $allowedActions);
$this->showErrorModal = true;
return;
}
$allowedTypes = ['in', 'out', 'group'];
if (!in_array($this->ruleType, $allowedTypes, true)) {
$this->error = 'Invalid rule type. Must be one of: ' . implode(', ', $allowedTypes);
$this->showErrorModal = true;
return;
}
$allowedLogLevels = ['nolog', 'emerg', 'alert', 'crit', 'err', 'warning', 'notice', 'info', 'debug'];
if (!in_array($this->ruleLog, $allowedLogLevels, true)) {
$this->ruleLog = 'nolog';
}
$payload = [
'action' => $this->ruleAction,
'type' => $this->ruleType,
@@ -891,7 +929,7 @@ class Firewall extends Component
public function saveAlias(): void
{
$this->validate([
'aliasName' => 'required|string|max:64',
'aliasName' => 'required|string|max:64|regex:/^[a-zA-Z][a-zA-Z0-9_\-]*$/',
'aliasCidr' => 'required|string',
]);
@@ -954,6 +992,13 @@ class Firewall extends Component
return;
}
// Validate alias name format to prevent path traversal
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9_\-]*$/', $this->deletingAliasName)) {
$this->error = 'Invalid alias name format';
$this->showErrorModal = true;
return;
}
$this->loading = true;
$this->showDeleteAliasModal = false;
@@ -1026,7 +1071,7 @@ class Firewall extends Component
public function saveIPSet(): void
{
$this->validate([
'ipsetName' => 'required|string|max:64',
'ipsetName' => 'required|string|max:64|regex:/^[a-zA-Z][a-zA-Z0-9_\-]*$/',
]);
$this->loading = true;
@@ -1078,6 +1123,13 @@ class Firewall extends Component
return;
}
// Validate IPSet name format to prevent path traversal
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9_\-]*$/', $this->deletingIPSetName)) {
$this->error = 'Invalid IPSet name format';
$this->showErrorModal = true;
return;
}
$this->loading = true;
$this->showDeleteIPSetModal = false;
@@ -1132,6 +1184,13 @@ class Firewall extends Component
public function selectIPSet(string $name): void
{
// Validate IPSet name format to prevent path traversal
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9_\-]*$/', $name)) {
$this->error = 'Invalid IPSet name format';
$this->showErrorModal = true;
return;
}
$this->selectedIPSetName = $name;
$this->loadIPSetMembers($name);
}