feat(proxmox): add smart firewall workflow and UI refresh
Introduce starter firewall rule templates, one-click rule creation from log entries, and quick log filter presets to speed up incident response. Add a shared quick actions hub plus refreshed help and overview surfaces to improve discoverability and make key VPS tasks faster. Made-with: Cursor
This commit is contained in:
@@ -360,7 +360,7 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-file-list-3-line class="size-4" />
|
||||
<span>Firewall Logs</span>
|
||||
<span class="ml-1.5 inline-flex items-center justify-center px-1.5 py-0.5 text-[10px] font-bold rounded-full bg-primary/15 text-primary min-w-[1.25rem]">{{ count($firewallLogs) }}</span>
|
||||
<span class="ml-1.5 inline-flex items-center justify-center px-1.5 py-0.5 text-[10px] font-bold rounded-full bg-primary/15 text-primary min-w-[1.25rem]">{{ count($this->filteredLogs) }}</span>
|
||||
</div>
|
||||
<div x-show="activeTab === 'logs'" class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary rounded-t"></div>
|
||||
</button>
|
||||
@@ -389,6 +389,20 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-5">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-base/60 mb-2">Starter templates</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-2">
|
||||
@foreach($this->ruleTemplates as $templateKey => $template)
|
||||
<button type="button"
|
||||
wire:click="applyRuleTemplate('{{ $templateKey }}')"
|
||||
class="text-left p-3 rounded-lg border border-neutral/30 bg-background-secondary/40 hover:border-primary/40 hover:bg-primary/5 transition-colors">
|
||||
<p class="text-sm font-semibold text-base">{{ $template['label'] }}</p>
|
||||
<p class="text-xs text-base/60 mt-0.5">{{ $template['description'] }}</p>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(count($rules) > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
@@ -825,7 +839,7 @@
|
||||
<button type="button"
|
||||
x-data
|
||||
@click="
|
||||
const logs = @js($firewallLogs);
|
||||
const logs = @js($this->filteredLogs);
|
||||
if (!logs || logs.length === 0) {
|
||||
alert('No logs to export');
|
||||
return;
|
||||
@@ -874,7 +888,20 @@
|
||||
<span wire:loading wire:target="loadFirewallLogs">Loading...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-base/60 mb-2">Quick filters</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@foreach($this->logPresets as $presetKey => $presetLabel)
|
||||
<button type="button"
|
||||
wire:click="setLogPreset('{{ $presetKey }}')"
|
||||
class="px-3 py-1.5 rounded-full border text-xs font-semibold transition-colors {{ $activeLogPreset === $presetKey ? 'border-primary/60 text-primary bg-primary/10' : 'border-neutral/30 text-base/70 hover:border-primary/40 hover:text-primary' }}">
|
||||
{{ $presetLabel }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(!empty($logError))
|
||||
<div class="bg-warning/10 border border-warning/30 rounded-lg p-4 mb-4">
|
||||
@@ -885,12 +912,12 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(!$logsLoaded && count($firewallLogs) === 0)
|
||||
@if(!$logsLoaded && count($this->filteredLogs) === 0)
|
||||
<div class="text-center py-12 text-base/60">
|
||||
<div class="fw-loader-xl text-primary mx-auto mb-4"></div>
|
||||
<p class="text-sm">Loading firewall logs...</p>
|
||||
</div>
|
||||
@elseif(count($firewallLogs) > 0)
|
||||
@elseif(count($this->filteredLogs) > 0)
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
@@ -903,6 +930,7 @@
|
||||
<th class="text-left py-3 px-4 text-xs font-semibold text-base/70 uppercase">Src Port</th>
|
||||
<th class="text-left py-3 px-4 text-xs font-semibold text-base/70 uppercase">Dest Port</th>
|
||||
<th class="text-center py-3 px-4 text-xs font-semibold text-base/70 uppercase">Analysis</th>
|
||||
<th class="text-center py-3 px-4 text-xs font-semibold text-base/70 uppercase">Rule</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -1386,6 +1414,18 @@
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
@php
|
||||
$logAbsoluteIndex = (($currentPage - 1) * $perPage) + $loop->index;
|
||||
@endphp
|
||||
<button type="button"
|
||||
wire:click="startCreateRuleFromLog({{ $logAbsoluteIndex }})"
|
||||
class="inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-semibold border border-primary/30 text-primary bg-primary/10 hover:bg-primary/15 transition-colors"
|
||||
title="Create firewall rule from this log">
|
||||
<x-ri-add-circle-line class="size-3.5" />
|
||||
Rule
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@@ -1410,7 +1450,7 @@
|
||||
{{-- Page info and navigation --}}
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="text-sm text-base/60">
|
||||
Showing {{ (($currentPage - 1) * $perPage) + 1 }} - {{ min($currentPage * $perPage, count($firewallLogs)) }} of {{ count($firewallLogs) }} logs
|
||||
Showing {{ (($currentPage - 1) * $perPage) + 1 }} - {{ min($currentPage * $perPage, count($this->filteredLogs)) }} of {{ count($this->filteredLogs) }} logs
|
||||
</span>
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
|
||||
Reference in New Issue
Block a user