feat: implement enhanced styling and functionality for firewall log filters, improving user interaction with action and protocol selections

This commit is contained in:
2025-12-03 17:03:19 -05:00
parent 0d6fe220c9
commit 500c3a52be

View File

@@ -77,6 +77,150 @@
.firewall-log-search-input {
padding-left: 2.75rem !important;
}
/* Firewall Log Filter Buttons */
.firewall-filter-label {
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: rgba(var(--color-base), 0.5);
margin-right: 0.25rem;
}
.firewall-filter-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.375rem 0.75rem;
font-size: 0.75rem;
font-weight: 500;
border-radius: 0.5rem;
border: 1px solid rgba(var(--color-neutral), 1);
background-color: rgba(var(--color-background), 1);
color: rgba(var(--color-base), 0.7);
cursor: pointer;
transition: all 0.15s ease;
}
.firewall-filter-btn:hover {
border-color: rgba(var(--color-primary), 0.5);
color: rgba(var(--color-base), 1);
}
.firewall-filter-btn-count {
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.625rem;
font-weight: 700;
background-color: rgba(var(--color-base), 0.1);
}
/* Active states for Policy filters */
.firewall-filter-btn.active-all {
background-color: rgba(var(--color-primary), 1);
border-color: rgba(var(--color-primary), 1);
color: white;
}
.firewall-filter-btn.active-all .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn.active-blocked {
background-color: #ef4444;
border-color: #ef4444;
color: white;
}
.firewall-filter-btn.active-blocked .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn:not(.active-blocked) .firewall-filter-btn-count.count-blocked {
background-color: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.firewall-filter-btn.active-allowed {
background-color: #22c55e;
border-color: #22c55e;
color: white;
}
.firewall-filter-btn.active-allowed .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn:not(.active-allowed) .firewall-filter-btn-count.count-allowed {
background-color: rgba(34, 197, 94, 0.1);
color: #22c55e;
}
/* Active states for Protocol filters */
.firewall-filter-btn.active-proto-all {
background-color: rgba(var(--color-secondary), 1);
border-color: rgba(var(--color-secondary), 1);
color: white;
}
.firewall-filter-btn.active-proto-all .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn.active-tcp {
background-color: #3b82f6;
border-color: #3b82f6;
color: white;
}
.firewall-filter-btn.active-tcp .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn:not(.active-tcp) .firewall-filter-btn-count.count-tcp {
background-color: rgba(59, 130, 246, 0.1);
color: #3b82f6;
}
.firewall-filter-btn.active-udp {
background-color: #f59e0b;
border-color: #f59e0b;
color: white;
}
.firewall-filter-btn.active-udp .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn:not(.active-udp) .firewall-filter-btn-count.count-udp {
background-color: rgba(245, 158, 11, 0.1);
color: #f59e0b;
}
.firewall-filter-btn.active-icmp {
background-color: #a855f7;
border-color: #a855f7;
color: white;
}
.firewall-filter-btn.active-icmp .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-btn:not(.active-icmp) .firewall-filter-btn-count.count-icmp {
background-color: rgba(168, 85, 247, 0.1);
color: #a855f7;
}
.firewall-filter-btn.active-other {
background-color: rgba(var(--color-base), 0.7);
border-color: rgba(var(--color-base), 0.7);
color: white;
}
.firewall-filter-btn.active-other .firewall-filter-btn-count {
background-color: rgba(255, 255, 255, 0.2);
}
.firewall-filter-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
}
.firewall-filter-divider {
padding-top: 0.5rem;
border-top: 1px solid rgba(var(--color-neutral), 0.3);
}
</style>
<div class="space-y-6">
@@ -513,109 +657,110 @@
class="space-y-4"
>
<!-- Filter Tabs -->
<div class="flex flex-col gap-4 mb-4">
<div style="display: flex; flex-direction: column; gap: 1rem; margin-bottom: 1rem;">
<!-- Action Filter -->
<div class="flex flex-wrap items-center gap-2">
<span class="text-xs font-semibold text-base/60 uppercase tracking-wider mr-1">Policy:</span>
<div class="firewall-filter-row">
<span class="firewall-filter-label">Policy:</span>
<button
type="button"
@click="setActionFilter('all')"
:class="actionFilter === 'all' ? 'bg-primary text-white border-primary' : 'bg-background border-neutral text-base/70 hover:border-primary/50 hover:text-base'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
<x-ri-list-check class="size-3.5" />
:class="actionFilter === 'all' ? 'active-all' : ''"
class="firewall-filter-btn">
<x-ri-list-check style="width: 14px; height: 14px;" />
All
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="actionFilter === 'all' ? 'bg-white/20' : 'bg-base/10'" x-text="actionCounts.all"></span>
<span class="firewall-filter-btn-count" x-text="actionCounts.all"></span>
</button>
<button
type="button"
@click="setActionFilter('blocked')"
:class="actionFilter === 'blocked' ? 'bg-error text-white border-error' : 'bg-background border-neutral text-base/70 hover:border-error/50 hover:text-error'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
<x-ri-shield-cross-line class="size-3.5" />
:class="actionFilter === 'blocked' ? 'active-blocked' : ''"
class="firewall-filter-btn">
<x-ri-shield-cross-line style="width: 14px; height: 14px;" />
Blocked
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="actionFilter === 'blocked' ? 'bg-white/20' : 'bg-error/10 text-error'" x-text="actionCounts.blocked"></span>
<span class="firewall-filter-btn-count count-blocked" x-text="actionCounts.blocked"></span>
</button>
<button
type="button"
@click="setActionFilter('allowed')"
:class="actionFilter === 'allowed' ? 'bg-success text-white border-success' : 'bg-background border-neutral text-base/70 hover:border-success/50 hover:text-success'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
<x-ri-shield-check-line class="size-3.5" />
:class="actionFilter === 'allowed' ? 'active-allowed' : ''"
class="firewall-filter-btn">
<x-ri-shield-check-line style="width: 14px; height: 14px;" />
Allowed
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="actionFilter === 'allowed' ? 'bg-white/20' : 'bg-success/10 text-success'" x-text="actionCounts.allowed"></span>
<span class="firewall-filter-btn-count count-allowed" x-text="actionCounts.allowed"></span>
</button>
</div>
<!-- Protocol Filter -->
<div class="flex flex-wrap items-center gap-2">
<span class="text-xs font-semibold text-base/60 uppercase tracking-wider mr-1">Protocol:</span>
<div class="firewall-filter-row">
<span class="firewall-filter-label">Protocol:</span>
<button
type="button"
@click="setProtocolFilter('all')"
:class="protocolFilter === 'all' ? 'bg-secondary text-white border-secondary' : 'bg-background border-neutral text-base/70 hover:border-secondary/50'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
:class="protocolFilter === 'all' ? 'active-proto-all' : ''"
class="firewall-filter-btn">
All
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="protocolFilter === 'all' ? 'bg-white/20' : 'bg-base/10'" x-text="protocolCounts.all"></span>
<span class="firewall-filter-btn-count" x-text="protocolCounts.all"></span>
</button>
<button
type="button"
@click="setProtocolFilter('tcp')"
:class="protocolFilter === 'tcp' ? 'bg-info text-white border-info' : 'bg-background border-neutral text-base/70 hover:border-info/50'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
:class="protocolFilter === 'tcp' ? 'active-tcp' : ''"
class="firewall-filter-btn">
TCP
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="protocolFilter === 'tcp' ? 'bg-white/20' : 'bg-info/10 text-info'" x-text="protocolCounts.tcp"></span>
<span class="firewall-filter-btn-count count-tcp" x-text="protocolCounts.tcp"></span>
</button>
<button
type="button"
@click="setProtocolFilter('udp')"
:class="protocolFilter === 'udp' ? 'bg-warning text-white border-warning' : 'bg-background border-neutral text-base/70 hover:border-warning/50'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
:class="protocolFilter === 'udp' ? 'active-udp' : ''"
class="firewall-filter-btn">
UDP
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="protocolFilter === 'udp' ? 'bg-white/20' : 'bg-warning/10 text-warning'" x-text="protocolCounts.udp"></span>
<span class="firewall-filter-btn-count count-udp" x-text="protocolCounts.udp"></span>
</button>
<button
type="button"
@click="setProtocolFilter('icmp')"
:class="protocolFilter === 'icmp' ? 'bg-purple-500 text-white border-purple-500' : 'bg-background border-neutral text-base/70 hover:border-purple-500/50'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
:class="protocolFilter === 'icmp' ? 'active-icmp' : ''"
class="firewall-filter-btn">
ICMP
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="protocolFilter === 'icmp' ? 'bg-white/20' : 'bg-purple-500/10 text-purple-500'" x-text="protocolCounts.icmp"></span>
<span class="firewall-filter-btn-count count-icmp" x-text="protocolCounts.icmp"></span>
</button>
<button
type="button"
@click="setProtocolFilter('other')"
x-show="protocolCounts.other > 0"
:class="protocolFilter === 'other' ? 'bg-base/80 text-white border-base/80' : 'bg-background border-neutral text-base/70 hover:border-base/50'"
class="px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5">
:class="protocolFilter === 'other' ? 'active-other' : ''"
class="firewall-filter-btn">
Other
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="protocolFilter === 'other' ? 'bg-white/20' : 'bg-base/10'" x-text="protocolCounts.other"></span>
<span class="firewall-filter-btn-count" x-text="protocolCounts.other"></span>
</button>
</div>
<!-- Search and Stats Row -->
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 pt-2 border-t border-neutral/30">
<div class="relative w-full md:w-72">
<x-ri-search-line class="size-4 absolute left-3 top-1/2 -translate-y-1/2 text-base/40" />
<div class="firewall-filter-divider" style="display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.75rem;">
<div style="position: relative; width: 100%; max-width: 18rem;">
<x-ri-search-line style="width: 16px; height: 16px; position: absolute; left: 12px; top: 50%; transform: translateY(-50%); opacity: 0.4;" />
<input
type="text"
x-model="searchTerm"
@input="currentPage = 1"
placeholder="Search logs..."
class="firewall-log-search-input w-full pr-4 py-2 border border-neutral rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/40"
class="firewall-log-search-input"
style="width: 100%; padding: 0.5rem 1rem; border: 1px solid rgba(var(--color-neutral), 1); border-radius: 0.5rem; background-color: rgba(var(--color-background), 1);"
/>
</div>
<div class="flex items-center gap-4 text-sm">
<div class="px-3 py-1.5 bg-background-secondary border border-neutral/30 rounded-lg">
<span class="text-base/70">Showing </span>
<span class="font-semibold text-primary" x-text="paginatedLogs.length"></span>
<span class="text-base/70"> of </span>
<span class="font-semibold" x-text="filteredLogs.length"></span>
<div style="display: flex; align-items: center; gap: 1rem; font-size: 0.875rem;">
<div style="padding: 0.375rem 0.75rem; background-color: rgba(var(--color-background-secondary), 1); border: 1px solid rgba(var(--color-neutral), 0.3); border-radius: 0.5rem;">
<span style="opacity: 0.7;">Showing </span>
<span style="font-weight: 600; color: rgba(var(--color-primary), 1);" x-text="paginatedLogs.length"></span>
<span style="opacity: 0.7;"> of </span>
<span style="font-weight: 600;" x-text="filteredLogs.length"></span>
</div>
<div class="px-3 py-1.5 bg-background-secondary border border-neutral/30 rounded-lg">
<span class="text-base/70">Page </span>
<span class="font-semibold text-primary" x-text="currentPage"></span>
<span class="text-base/70"> / </span>
<span class="font-semibold" x-text="totalPages || 1"></span>
<div style="padding: 0.375rem 0.75rem; background-color: rgba(var(--color-background-secondary), 1); border: 1px solid rgba(var(--color-neutral), 0.3); border-radius: 0.5rem;">
<span style="opacity: 0.7;">Page </span>
<span style="font-weight: 600; color: rgba(var(--color-primary), 1);" x-text="currentPage"></span>
<span style="opacity: 0.7;"> / </span>
<span style="font-weight: 600;" x-text="totalPages || 1"></span>
</div>
</div>
</div>