feat: implement enhanced styling and functionality for firewall log filters, improving user interaction with action and protocol selections
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user