feat: enhance error handling in Proxmox Firewall component by adding detailed error messages and modal display for improved user feedback

This commit is contained in:
2025-12-01 13:17:47 -05:00
parent 7628da6a32
commit 4a29e25eeb
2 changed files with 121 additions and 26 deletions

View File

@@ -15,6 +15,7 @@ class Firewall extends Component
public array $ipsets = [];
public bool $loading = false;
public string $error = '';
public bool $showErrorModal = false;
// Rule creation/editing
public ?int $editingRulePos = null;
@@ -88,7 +89,18 @@ class Firewall extends Component
$this->firewallEnabled = isset($data['enable']) && $data['enable'] == 1;
$this->error = '';
} catch (\Exception $e) {
$this->error = 'Failed to load firewall options: ' . $e->getMessage();
$errorMessage = $e->getMessage();
// Try to extract more detailed error from response if available
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to load firewall options: ' . $errorMessage;
$this->showErrorModal = true;
$this->firewallEnabled = false;
}
}
@@ -130,11 +142,13 @@ class Firewall extends Component
$errorMessage = $errorData['message'];
}
}
$this->notify('Failed to toggle firewall: ' . $errorMessage, 'error');
$this->error = 'Failed to toggle firewall: ' . $errorMessage;
$this->showErrorModal = true;
// Reload to ensure UI matches actual state
$this->loadFirewallOptions();
} catch (\Exception $e) {
$this->notify('Failed to toggle firewall: ' . $e->getMessage(), 'error');
$this->error = 'Failed to toggle firewall: ' . $e->getMessage();
$this->showErrorModal = true;
// Reload to ensure UI matches actual state
$this->loadFirewallOptions();
} finally {
@@ -152,7 +166,18 @@ class Firewall extends Component
$this->rules = is_array($data) ? $data : [];
$this->error = '';
} catch (\Exception $e) {
$this->error = 'Failed to load firewall rules: ' . $e->getMessage();
$errorMessage = $e->getMessage();
// Try to extract more detailed error from response if available
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to load firewall rules: ' . $errorMessage;
$this->showErrorModal = true;
$this->rules = [];
}
}
@@ -238,10 +263,21 @@ class Firewall extends Component
$this->loadFirewallRules();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to save rule: ' . $message, 'error');
$this->error = 'Failed to save rule: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to save rule: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to save rule: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}
@@ -261,10 +297,21 @@ class Firewall extends Component
$this->loadFirewallRules();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to delete rule: ' . $message, 'error');
$this->error = 'Failed to delete rule: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to delete rule: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to delete rule: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}
@@ -286,7 +333,8 @@ class Firewall extends Component
public function createAlias(): void
{
if (empty($this->aliasName) || empty($this->aliasCidr)) {
$this->notify('Name and CIDR are required', 'error');
$this->error = 'Name and CIDR are required';
$this->showErrorModal = true;
return;
}
@@ -314,10 +362,21 @@ class Firewall extends Component
$this->loadAliases();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to create alias: ' . $message, 'error');
$this->error = 'Failed to create alias: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to create alias: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to create alias: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}
@@ -337,10 +396,21 @@ class Firewall extends Component
$this->loadAliases();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to delete alias: ' . $message, 'error');
$this->error = 'Failed to delete alias: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to delete alias: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to delete alias: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}
@@ -362,7 +432,8 @@ class Firewall extends Component
public function createIpset(): void
{
if (empty($this->ipsetName)) {
$this->notify('Name is required', 'error');
$this->error = 'Name is required';
$this->showErrorModal = true;
return;
}
@@ -388,10 +459,21 @@ class Firewall extends Component
$this->loadIpsets();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to create IP set: ' . $message, 'error');
$this->error = 'Failed to create IP set: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to create IP set: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to create IP set: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}
@@ -411,10 +493,21 @@ class Firewall extends Component
$this->loadIpsets();
} else {
$message = $response->json()['errors'][0]['message'] ?? 'Unknown error';
$this->notify('Failed to delete IP set: ' . $message, 'error');
$this->error = 'Failed to delete IP set: ' . $message;
$this->showErrorModal = true;
}
} catch (\Exception $e) {
$this->notify('Failed to delete IP set: ' . $e->getMessage(), 'error');
$errorMessage = $e->getMessage();
if (method_exists($e, 'response') && $e->response()) {
$errorData = $e->response()->json();
if (isset($errorData['errors']) && is_array($errorData['errors']) && !empty($errorData['errors'])) {
$errorMessage = $errorData['errors'][0]['message'] ?? $errorMessage;
} elseif (isset($errorData['message'])) {
$errorMessage = $errorData['message'];
}
}
$this->error = 'Failed to delete IP set: ' . $errorMessage;
$this->showErrorModal = true;
} finally {
$this->loading = false;
}

View File

@@ -51,18 +51,20 @@
</style>
<div class="space-y-6">
<!-- Error Message - Centered on Page -->
@if($error)
<div class="fixed inset-0 flex items-center justify-center z-50 bg-black/50 backdrop-blur-sm" wire:click="$set('error', '')">
<div class="bg-error/20 border-2 border-error rounded-lg p-6 shadow-lg max-w-2xl w-full mx-4" wire:click.stop>
<!-- Error Message - Centered Modal -->
@if($error || $showErrorModal)
<div class="fixed inset-0 flex items-center justify-center z-50 bg-black/50 backdrop-blur-sm" wire:click="$set('error', ''); $set('showErrorModal', false)">
<div class="bg-error/20 border-2 border-error rounded-lg p-6 shadow-lg max-w-3xl w-full mx-4 max-h-[80vh] overflow-y-auto" wire:click.stop>
<div class="flex items-start gap-3">
<x-ri-error-warning-fill class="size-6 text-error flex-shrink-0 mt-0.5" />
<div class="flex-1 text-center">
<h3 class="text-lg font-semibold text-error mb-2">Firewall Error</h3>
<p class="text-sm text-error/90 leading-relaxed">{{ $error }}</p>
<div class="flex-1">
<h3 class="text-lg font-semibold text-error mb-2 text-center">Firewall Error</h3>
<div class="bg-background/50 rounded p-3 border border-error/30">
<p class="text-sm text-error/90 leading-relaxed whitespace-pre-wrap break-words">{{ $error }}</p>
</div>
</div>
<button
wire:click="$set('error', '')"
wire:click="$set('error', ''); $set('showErrorModal', false)"
class="text-error/70 hover:text-error transition-colors flex-shrink-0">
<x-ri-close-line class="size-5" />
</button>