Refactor Proxmox server views for improved UI consistency and usability

- Updated server card component to use new UI elements and improved layout.
- Enhanced status display with badges and better status indicators.
- Refined quick info row for server details with consistent styling.
- Reorganized server configuration statistics into stat cards for clarity.
- Improved help modals for statistics and storage management sections.
- Streamlined alerts and warnings for better user experience.
- Updated storage management view to utilize new UI components and improve readability.
This commit is contained in:
2025-12-17 11:24:17 -05:00
parent bf346cecca
commit e7b33a2f6c
68 changed files with 5127 additions and 650 deletions

View File

@@ -56,85 +56,36 @@
<div class="flex flex-col gap-6">
{{-- Page Header --}}
<div class="mb-6">
<h1 class="text-2xl font-bold">Firewall Management</h1>
<p class="text-sm text-base/60 mt-1">Configure firewall rules, policies, aliases, and IPSets for your virtual machine</p>
</div>
<x-proxmox::ui.section-header
title="Firewall Management"
subtitle="Configure firewall rules, policies, aliases, and IPSets for your virtual machine"
icon="ri-shield-line"
/>
{{-- Error Modal --}}
@if($error && $showErrorModal)
<div class="fixed inset-0 z-[60] bg-black/50 backdrop-blur-sm flex items-center justify-center p-4">
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
<x-proxmox::ui.modal title="Error" icon="ri-error-warning-line" icon-class="text-error" :show="true" wire:key="error-modal">
<x-slot name="header">
<button wire:click="$set('showErrorModal', false)" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
<x-ri-close-line class="size-5" />
</button>
<div class="flex items-start gap-3 mb-4">
<div class="flex-shrink-0 w-10 h-10 rounded-full bg-error/20 flex items-center justify-center">
<x-ri-error-warning-line class="size-5 text-error" />
</div>
<div>
<h3 class="text-lg font-semibold">Error</h3>
<p class="text-sm text-base/70 mt-1">{{ $error }}</p>
</div>
</div>
<div class="flex justify-end">
<button wire:click="$set('showErrorModal', false)" class="px-4 py-2 bg-background border border-neutral rounded-lg hover:bg-background-secondary transition-colors text-sm font-medium">
Close
</button>
</div>
</div>
</div>
</x-slot>
<p class="text-sm text-base/70">{{ $error }}</p>
<x-slot name="footer">
<x-proxmox::ui.button wire:click="$set('showErrorModal', false)" variant="secondary">
Close
</x-proxmox::ui.button>
</x-slot>
</x-proxmox::ui.modal>
@endif
{{-- Main Firewall Toggle & Status --}}
<div class="bg-gradient-to-br from-primary/10 to-primary/5 border border-primary/20 rounded-xl p-6 mb-6">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="w-12 h-12 rounded-xl bg-primary/20 flex items-center justify-center">
<x-ri-shield-line class="size-6 text-primary" />
</div>
<div>
<h2 class="text-xl font-semibold">Master Firewall Control</h2>
<p class="text-sm text-base/60 mt-1">
@if($firewallEnabled)
<span class="text-success font-medium">✓ Active - Your VM is protected by firewall rules</span>
@else
<span class="text-warning font-medium">⚠ Disabled - Your VM has no firewall protection</span>
@endif
</p>
</div>
</div>
<div class="flex items-center gap-2">
@if($firewallEnabled)
<button type="button"
wire:click="toggleFirewall"
wire:loading.attr="disabled"
style="padding: 0.5rem 1rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.875rem; font-weight: 500; display: flex; align-items: center; gap: 0.5rem;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
<x-ri-close-line class="size-4" />
<span wire:loading.remove wire:target="toggleFirewall">Disable Firewall</span>
<span wire:loading wire:target="toggleFirewall">Disabling...</span>
</button>
@else
<button type="button"
wire:click="toggleFirewall"
wire:loading.attr="disabled"
class="px-4 py-2 bg-success text-white rounded-lg hover:bg-success/90 transition-colors text-sm font-medium flex items-center gap-2">
<x-ri-shield-line class="size-4" />
<span wire:loading.remove wire:target="toggleFirewall">Enable Firewall</span>
<span wire:loading wire:target="toggleFirewall">Enabling...</span>
</button>
@endif
</div>
</div>
</div>
{{-- Main Firewall Toggle & Status --}}\n <div class=\"relative overflow-hidden rounded-xl border border-primary/20 bg-gradient-to-br from-primary/10 via-primary/5 to-transparent p-6 mb-6\">\n {{-- Decorative elements --}}\n <div class=\"absolute top-0 right-0 w-32 h-32 bg-primary/10 rounded-full -translate-y-1/2 translate-x-1/2 blur-2xl\"></div>\n <div class=\"absolute bottom-0 left-0 w-24 h-24 bg-primary/5 rounded-full translate-y-1/2 -translate-x-1/2 blur-xl\"></div>\n \n <div class=\"relative flex flex-col sm:flex-row sm:items-center justify-between gap-4\">\n <div class=\"flex items-center gap-4\">\n <div class=\"w-12 h-12 rounded-xl bg-primary/20 flex items-center justify-center ring-4 ring-primary/10\">\n <x-ri-shield-line class=\"size-6 text-primary\" />\n </div>\n <div>\n <h2 class=\"text-xl font-bold\">Master Firewall Control</h2>\n <p class=\"text-sm mt-1\">\n @if($firewallEnabled)\n <span class=\"inline-flex items-center gap-1.5 text-success font-medium\">\n <span class=\"relative flex h-2 w-2\">\n <span class=\"absolute inline-flex h-full w-full rounded-full bg-success opacity-75 animate-ping\"></span>\n <span class=\"relative inline-flex rounded-full h-2 w-2 bg-success\"></span>\n </span>\n Active - Your VM is protected\n </span>\n @else\n <span class=\"inline-flex items-center gap-1.5 text-warning font-medium\">\n <x-ri-error-warning-line class=\"size-4\" />\n Disabled - No firewall protection\n </span>\n @endif\n </p>\n </div>\n </div>\n <div class=\"flex items-center gap-2\">\n @if($firewallEnabled)\n <x-proxmox::ui.button \n wire:click=\"toggleFirewall\" \n wire:loading.attr=\"disabled\"\n variant=\"danger\"\n icon=\"ri-shield-off-line\">\n <span wire:loading.remove wire:target=\"toggleFirewall\">Disable</span>\n <span wire:loading wire:target=\"toggleFirewall\">Disabling...</span>\n </x-proxmox::ui.button>\n @else\n <x-proxmox::ui.button \n wire:click=\"toggleFirewall\" \n wire:loading.attr=\"disabled\"\n variant=\"success\"\n icon=\"ri-shield-check-line\">\n <span wire:loading.remove wire:target=\"toggleFirewall\">Enable Firewall</span>\n <span wire:loading wire:target=\"toggleFirewall\">Enabling...</span>\n </x-proxmox::ui.button>\n @endif\n </div>\n </div>\n </div>
{{-- Firewall Policies & Network Adapters Grid --}}
@if($firewallEnabled)
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
{{-- Default Policies Card --}}
<div class="bg-background border border-neutral rounded-xl p-6">
<x-proxmox::ui.card>
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-warning/10 flex items-center justify-center">
@@ -151,35 +102,36 @@
</div>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-2">Incoming Traffic (Policy In)</label>
<select wire:model="policyIn" class="w-full px-3 py-2 border border-neutral rounded-lg bg-background text-sm">
<option value="ACCEPT">Accept</option>
<option value="REJECT">Reject</option>
<option value="DROP">Drop</option>
</select>
<p class="text-xs text-base/60 mt-1">Default action for incoming traffic not matching any rule</p>
</div>
<x-proxmox::ui.select
wire:model="policyIn"
label="Incoming Traffic (Policy In)"
help="Default action for incoming traffic not matching any rule">
<option value="ACCEPT">Accept</option>
<option value="REJECT">Reject</option>
<option value="DROP">Drop</option>
</x-proxmox::ui.select>
<div>
<label class="block text-sm font-medium mb-2">Outgoing Traffic (Policy Out)</label>
<select wire:model="policyOut" class="w-full px-3 py-2 border border-neutral rounded-lg bg-background text-sm">
<option value="ACCEPT">Accept</option>
<option value="REJECT">Reject</option>
<option value="DROP">Drop</option>
</select>
<p class="text-xs text-base/60 mt-1">Default action for outgoing traffic not matching any rule</p>
</div>
<x-proxmox::ui.select
wire:model="policyOut"
label="Outgoing Traffic (Policy Out)"
help="Default action for outgoing traffic not matching any rule">
<option value="ACCEPT">Accept</option>
<option value="REJECT">Reject</option>
<option value="DROP">Drop</option>
</x-proxmox::ui.select>
<button type="button" wire:click="updatePolicies" wire:loading.attr="disabled" class="w-full px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors text-sm font-medium mt-4">
<x-proxmox::ui.button
wire:click="updatePolicies"
wire:loading.attr="disabled"
class="w-full mt-4">
<span wire:loading.remove wire:target="updatePolicies">Update Policies</span>
<span wire:loading wire:target="updatePolicies">Updating...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</x-proxmox::ui.card>
{{-- Network Adapters --}}
<div class="bg-background border border-neutral rounded-xl p-6">
<x-proxmox::ui.card>
<div class="flex items-center gap-3 mb-4">
<div class="w-10 h-10 rounded-lg bg-success/10 flex items-center justify-center">
<x-ri-router-line class="size-5 text-success" />
@@ -198,11 +150,9 @@
<div class="flex-1">
<div class="flex items-center gap-2 mb-1">
<span class="font-semibold text-sm">{{ $adapter['name'] }}</span>
@if($adapterFirewallStates[$adapter['name']] ?? false)
<span class="px-2 py-0.5 bg-success/20 text-success text-xs font-medium rounded-full">Active</span>
@else
<span class="px-2 py-0.5 bg-base/20 text-base/60 text-xs font-medium rounded-full">Off</span>
@endif
<x-proxmox::ui.badge :variant="($adapterFirewallStates[$adapter['name']] ?? false) ? 'success' : 'secondary'">
{{ ($adapterFirewallStates[$adapter['name']] ?? false) ? 'Active' : 'Off' }}
</x-proxmox::ui.badge>
</div>
<div class="text-xs text-base/60">
{{ ucfirst($adapter['model'] ?? 'Unknown') }}
@@ -213,27 +163,27 @@
</div>
<div class="flex items-center gap-2">
@if($adapterFirewallStates[$adapter['name']] ?? false)
<button type="button"
wire:click="toggleAdapterFirewall('{{ $adapter['name'] }}')"
wire:loading.attr="disabled"
wire:key="adapter-{{ $adapter['name'] }}"
style="padding: 0.375rem 0.75rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.75rem; font-weight: 500; display: flex; align-items: center; gap: 0.375rem;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
<x-ri-close-line class="size-3.5" />
<x-proxmox::ui.button
wire:click="toggleAdapterFirewall('{{ $adapter['name'] }}')"
wire:loading.attr="disabled"
wire:key="adapter-{{ $adapter['name'] }}"
variant="danger"
size="sm"
icon="ri-close-line">
<span wire:loading.remove wire:target="toggleAdapterFirewall('{{ $adapter['name'] }}')">Disable</span>
<span wire:loading wire:target="toggleAdapterFirewall('{{ $adapter['name'] }}')">...</span>
</button>
</x-proxmox::ui.button>
@else
<button type="button"
wire:click="toggleAdapterFirewall('{{ $adapter['name'] }}')"
wire:loading.attr="disabled"
wire:key="adapter-{{ $adapter['name'] }}"
class="px-3 py-1.5 bg-success text-white rounded-lg hover:bg-success/90 transition-colors text-xs font-medium flex items-center gap-1.5">
<x-ri-shield-line class="size-3.5" />
<x-proxmox::ui.button
wire:click="toggleAdapterFirewall('{{ $adapter['name'] }}')"
wire:loading.attr="disabled"
wire:key="adapter-{{ $adapter['name'] }}"
variant="success"
size="sm"
icon="ri-shield-line">
<span wire:loading.remove wire:target="toggleAdapterFirewall('{{ $adapter['name'] }}')">Enable</span>
<span wire:loading wire:target="toggleAdapterFirewall('{{ $adapter['name'] }}')">...</span>
</button>
</x-proxmox::ui.button>
@endif
</div>
</div>
@@ -241,12 +191,12 @@
@endforeach
</div>
@else
<div class="text-center py-4 text-base/60 text-sm">
<x-ri-router-line class="size-8 mx-auto mb-2 opacity-50" />
<p>No network adapters found</p>
</div>
<x-proxmox::ui.empty-state
icon="ri-router-line"
title="No Network Adapters"
description="No network adapters found on this VM" />
@endif
</div>
</x-proxmox::ui.card>
</div>
{{-- Policy Info Modal --}}
@@ -1817,19 +1767,14 @@
</div>
</div>
</div>
<div style="display: flex; gap: 12px; justify-content: flex-end;">
<button wire:click="cancelDeleteRule"
type="button"
style="padding: 8px 16px; background-color: rgba(var(--background), 1); border: 1px solid rgba(var(--neutral), 0.3); border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s;">
<div class="flex gap-3 justify-end">
<x-proxmox::ui.button wire:click="cancelDeleteRule" variant="secondary">
Cancel
</button>
<button wire:click="deleteRule"
wire:loading.attr="disabled"
type="button"
style="padding: 8px 16px; background-color: #ef4444; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s;">
</x-proxmox::ui.button>
<x-proxmox::ui.button wire:click="deleteRule" wire:loading.attr="disabled" variant="danger">
<span wire:loading.remove wire:target="deleteRule">Delete Rule</span>
<span wire:loading wire:target="deleteRule">Deleting...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</div>
@@ -1894,16 +1839,13 @@
</div>
</div>
<div class="flex gap-3 justify-end">
<button wire:click="cancelDeleteAlias" class="px-4 py-2 bg-background border border-neutral rounded-lg hover:bg-background-secondary transition-colors text-sm font-medium">
<x-proxmox::ui.button wire:click="cancelDeleteAlias" variant="secondary">
Cancel
</button>
<button wire:click="deleteAlias" wire:loading.attr="disabled"
style="padding: 0.5rem 1rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.875rem; font-weight: 500;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
</x-proxmox::ui.button>
<x-proxmox::ui.button wire:click="deleteAlias" wire:loading.attr="disabled" variant="danger">
<span wire:loading.remove wire:target="deleteAlias">Delete</span>
<span wire:loading wire:target="deleteAlias">Deleting...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</div>
@@ -1966,16 +1908,13 @@
</div>
</div>
<div class="flex gap-3 justify-end">
<button wire:click="cancelDeleteIPSet" class="px-4 py-2 bg-background border border-neutral rounded-lg hover:bg-background-secondary transition-colors text-sm font-medium">
<x-proxmox::ui.button wire:click="cancelDeleteIPSet" variant="secondary">
Cancel
</button>
<button wire:click="deleteIPSet" wire:loading.attr="disabled"
style="padding: 0.5rem 1rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.875rem; font-weight: 500;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
</x-proxmox::ui.button>
<x-proxmox::ui.button wire:click="deleteIPSet" wire:loading.attr="disabled" variant="danger">
<span wire:loading.remove wire:target="deleteIPSet">Delete</span>
<span wire:loading wire:target="deleteIPSet">Deleting...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</div>
@@ -2041,16 +1980,13 @@
</div>
</div>
<div class="flex gap-3 justify-end">
<button wire:click="cancelDeleteIPSetMember" class="px-4 py-2 bg-background border border-neutral rounded-lg hover:bg-background-secondary transition-colors text-sm font-medium">
<x-proxmox::ui.button wire:click="cancelDeleteIPSetMember" variant="secondary">
Cancel
</button>
<button wire:click="deleteIPSetMember" wire:loading.attr="disabled"
style="padding: 0.5rem 1rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.875rem; font-weight: 500;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
</x-proxmox::ui.button>
<x-proxmox::ui.button wire:click="deleteIPSetMember" wire:loading.attr="disabled" variant="danger">
<span wire:loading.remove wire:target="deleteIPSetMember">Remove</span>
<span wire:loading wire:target="deleteIPSetMember">Removing...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</div>
@@ -2334,16 +2270,13 @@
</div>
</div>
<div class="flex gap-3 justify-end">
<button wire:click="cancelDeleteConfiguration" class="px-4 py-2 bg-background border border-neutral rounded-lg hover:bg-background-secondary transition-colors text-sm font-medium">
<x-proxmox::ui.button wire:click="cancelDeleteConfiguration" variant="secondary">
Cancel
</button>
<button wire:click="deleteConfiguration" wire:loading.attr="disabled"
style="padding: 0.5rem 1rem; background-color: #ef4444; color: white; border-radius: 0.5rem; transition: all 0.2s; font-size: 0.875rem; font-weight: 500;"
onmouseover="this.style.backgroundColor='#dc2626'"
onmouseout="this.style.backgroundColor='#ef4444'">
</x-proxmox::ui.button>
<x-proxmox::ui.button wire:click="deleteConfiguration" wire:loading.attr="disabled" variant="danger">
<span wire:loading.remove wire:target="deleteConfiguration">Delete</span>
<span wire:loading wire:target="deleteConfiguration">Deleting...</span>
</button>
</x-proxmox::ui.button>
</div>
</div>
</div>