feat: enhance Proxmox firewall log view with new tabbed interface for detailed event analysis and improved log parsing functionality
This commit is contained in:
@@ -1601,126 +1601,458 @@
|
||||
@click="showStateModal = false"
|
||||
@keydown.escape.window="showStateModal = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div @click.stop class="relative w-full max-w-lg bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl max-h-[90vh] overflow-y-auto">
|
||||
style="display: none;"
|
||||
x-data="{
|
||||
activeTab: 'overview',
|
||||
parseRawLog(raw) {
|
||||
if (!raw) return {};
|
||||
const fields = {};
|
||||
// Parse common firewall log fields
|
||||
const patterns = {
|
||||
LEN: /LEN=(\d+)/,
|
||||
TOS: /TOS=(0x[0-9A-Fa-f]+)/,
|
||||
PREC: /PREC=(0x[0-9A-Fa-f]+)/,
|
||||
TTL: /TTL=(\d+)/,
|
||||
ID: /ID=(\d+)/,
|
||||
DF: /\bDF\b/,
|
||||
MF: /\bMF\b/,
|
||||
FRAG: /FRAG=(\d+)/,
|
||||
WINDOW: /WINDOW=(\d+)/,
|
||||
RES: /RES=(0x[0-9A-Fa-f]+)/,
|
||||
SYN: /\bSYN\b/,
|
||||
ACK: /\bACK\b/,
|
||||
FIN: /\bFIN\b/,
|
||||
RST: /\bRST\b/,
|
||||
PSH: /\bPSH\b/,
|
||||
URG: /\bURG\b/,
|
||||
URGP: /URGP=(\d+)/,
|
||||
SEQ: /SEQ=(\d+)/,
|
||||
TYPE: /TYPE=(\d+)/,
|
||||
CODE: /CODE=(\d+)/
|
||||
};
|
||||
|
||||
for (const [key, pattern] of Object.entries(patterns)) {
|
||||
const match = raw.match(pattern);
|
||||
if (match) {
|
||||
fields[key] = match[1] || 'Yes';
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}">
|
||||
<div @click.stop class="relative w-full max-w-3xl bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl max-h-[90vh] overflow-hidden flex flex-col">
|
||||
<button @click="showStateModal = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors z-10">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
|
||||
<div class="p-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center gap-3 mb-6 pb-4 border-b border-neutral/20">
|
||||
<div class="p-2 rounded-lg" :class="log.action === 'DROP' || log.action === 'REJECT' ? 'bg-danger/20' : 'bg-success/20'">
|
||||
<!-- Header with gradient -->
|
||||
<div class="p-6 pb-4 bg-gradient-to-br from-background via-background-secondary to-background border-b border-neutral/20">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="p-3 rounded-xl shadow-lg" :class="log.action === 'DROP' || log.action === 'REJECT' ? 'bg-danger/20 ring-2 ring-danger/30' : 'bg-success/20 ring-2 ring-success/30'">
|
||||
<template x-if="log.action === 'DROP' || log.action === 'REJECT'">
|
||||
<x-ri-shield-cross-line class="size-6 text-danger" />
|
||||
<x-ri-shield-cross-line class="size-7 text-danger" />
|
||||
</template>
|
||||
<template x-if="log.action === 'ACCEPT'">
|
||||
<x-ri-shield-check-line class="size-6 text-success" />
|
||||
<x-ri-shield-check-line class="size-7 text-success" />
|
||||
</template>
|
||||
<template x-if="log.action !== 'DROP' && log.action !== 'REJECT' && log.action !== 'ACCEPT'">
|
||||
<x-ri-shield-line class="size-6 text-base/70" />
|
||||
<x-ri-shield-line class="size-7 text-base/70" />
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold">Connection State</h3>
|
||||
<p class="text-sm text-base/60" x-text="log.timestamp_display || 'Unknown time'"></p>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-3 mb-1">
|
||||
<h3 class="text-xl font-bold">Firewall Event Details</h3>
|
||||
<span class="px-3 py-1 rounded-lg text-xs font-bold" :class="log.action_badge_class" x-text="log.action || 'UNKNOWN'"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm text-base/60">
|
||||
<x-ri-time-line class="size-4" />
|
||||
<span x-text="log.timestamp_display || 'Unknown time'"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Badge -->
|
||||
<div class="mb-4">
|
||||
<span class="px-3 py-1.5 rounded-lg text-sm font-semibold" :class="log.action_badge_class" x-text="log.action || 'UNKNOWN'"></span>
|
||||
<!-- Tab Navigation -->
|
||||
<div class="flex border-b border-neutral/20 bg-background px-6">
|
||||
<button @click="activeTab = 'overview'"
|
||||
class="px-4 py-3 text-sm font-semibold transition-all relative"
|
||||
:class="activeTab === 'overview' ? 'text-primary' : 'text-base/60 hover:text-base'">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-dashboard-line class="size-4" />
|
||||
<span>Overview</span>
|
||||
</div>
|
||||
<div x-show="activeTab === 'overview'"
|
||||
class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary"></div>
|
||||
</button>
|
||||
<button @click="activeTab = 'packet'"
|
||||
class="px-4 py-3 text-sm font-semibold transition-all relative"
|
||||
:class="activeTab === 'packet' ? 'text-primary' : 'text-base/60 hover:text-base'">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-file-code-line class="size-4" />
|
||||
<span>Packet Details</span>
|
||||
</div>
|
||||
<div x-show="activeTab === 'packet'"
|
||||
class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary"></div>
|
||||
</button>
|
||||
<button @click="activeTab = 'raw'"
|
||||
class="px-4 py-3 text-sm font-semibold transition-all relative"
|
||||
:class="activeTab === 'raw' ? 'text-primary' : 'text-base/60 hover:text-base'">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-code-line class="size-4" />
|
||||
<span>Raw Data</span>
|
||||
</div>
|
||||
<div x-show="activeTab === 'raw'"
|
||||
class="absolute bottom-0 left-0 right-0 h-0.5 bg-primary"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Connection Details Grid -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<!-- Source Section -->
|
||||
<div class="col-span-2 sm:col-span-1 p-4 bg-background rounded-lg border border-neutral/20">
|
||||
<!-- Tab Content with scroll -->
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
|
||||
<!-- Overview Tab -->
|
||||
<div x-show="activeTab === 'overview'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
|
||||
|
||||
<!-- Connection Flow -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-route-line class="size-5 text-primary" />
|
||||
<h4 class="text-sm font-bold text-base/80 uppercase tracking-wide">Connection Flow</h4>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Source -->
|
||||
<div class="flex-1 p-4 bg-gradient-to-br from-info/10 to-info/5 rounded-xl border border-info/30">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<div class="p-1.5 bg-info/20 rounded-lg">
|
||||
<x-ri-arrow-right-up-line class="size-4 text-info" />
|
||||
<span class="text-xs font-semibold text-base/60 uppercase tracking-wide">Source</span>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-info uppercase tracking-wide">Source</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div>
|
||||
<span class="text-xs text-base/50">IP Address</span>
|
||||
<p class="font-mono text-sm font-medium break-all" x-text="log.source || '-'"></p>
|
||||
<div class="text-xs text-base/50 mb-0.5">IP Address</div>
|
||||
<div class="font-mono text-sm font-semibold break-all" x-text="log.source || '-'"></div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-base/50">Port</span>
|
||||
<p class="font-mono text-sm font-medium" x-text="log.source_port || '-'"></p>
|
||||
<div class="text-xs text-base/50 mb-0.5">Port</div>
|
||||
<div class="font-mono text-sm font-semibold" x-text="log.source_port || '-'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Destination Section -->
|
||||
<div class="col-span-2 sm:col-span-1 p-4 bg-background rounded-lg border border-neutral/20">
|
||||
<!-- Arrow -->
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<x-ri-arrow-right-line class="size-6 text-base/40" />
|
||||
<div class="px-2 py-0.5 bg-primary/10 rounded text-xs font-bold text-primary" x-text="log.protocol || 'N/A'"></div>
|
||||
</div>
|
||||
|
||||
<!-- Destination -->
|
||||
<div class="flex-1 p-4 bg-gradient-to-br from-warning/10 to-warning/5 rounded-xl border border-warning/30">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<div class="p-1.5 bg-warning/20 rounded-lg">
|
||||
<x-ri-arrow-right-down-line class="size-4 text-warning" />
|
||||
<span class="text-xs font-semibold text-base/60 uppercase tracking-wide">Destination</span>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-warning uppercase tracking-wide">Destination</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div>
|
||||
<span class="text-xs text-base/50">IP Address</span>
|
||||
<p class="font-mono text-sm font-medium break-all" x-text="log.destination || '-'"></p>
|
||||
<div class="text-xs text-base/50 mb-0.5">IP Address</div>
|
||||
<div class="font-mono text-sm font-semibold break-all" x-text="log.destination || '-'"></div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-base/50">Port</span>
|
||||
<p class="font-mono text-sm font-medium" x-text="log.destination_port || '-'"></p>
|
||||
<div class="text-xs text-base/50 mb-0.5">Port</div>
|
||||
<div class="font-mono text-sm font-semibold" x-text="log.destination_port || '-'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Protocol & Level -->
|
||||
<div class="col-span-2 p-4 bg-background rounded-lg border border-neutral/20">
|
||||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-4">
|
||||
<div>
|
||||
<span class="text-xs text-base/50">Protocol</span>
|
||||
<p class="text-sm font-semibold" x-text="log.protocol || '-'"></p>
|
||||
<!-- Connection Metadata -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="text-xs text-base/50 mb-1">Protocol</div>
|
||||
<div class="text-base font-bold" x-text="log.protocol || '-'"></div>
|
||||
</div>
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="text-xs text-base/50 mb-1">Level</div>
|
||||
<div>
|
||||
<span class="text-xs text-base/50">Level</span>
|
||||
<p class="text-sm">
|
||||
<span class="px-2 py-0.5 rounded text-xs font-semibold uppercase" :class="log.level_badge_class" x-text="log.level_label || '-'"></span>
|
||||
</p>
|
||||
<span class="px-2 py-1 rounded-lg text-xs font-bold uppercase" :class="log.level_badge_class" x-text="log.level_label || '-'"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-base/50">Interface</span>
|
||||
<p class="font-mono text-sm font-medium" x-text="log.interface || '-'"></p>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-base/50">MAC Address</span>
|
||||
<p class="font-mono text-xs font-medium break-all" x-text="log.mac || '-'"></p>
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="text-xs text-base/50 mb-1">Interface</div>
|
||||
<div class="font-mono text-sm font-semibold" x-text="log.interface || '-'"></div>
|
||||
</div>
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="text-xs text-base/50 mb-1">MAC Address</div>
|
||||
<div class="font-mono text-xs font-semibold break-all" x-text="log.mac || '-'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Raw Log (if available) -->
|
||||
<template x-if="log.raw">
|
||||
<div class="col-span-2 p-4 bg-background rounded-lg border border-neutral/20">
|
||||
<!-- Packet Details Tab -->
|
||||
<div x-show="activeTab === 'packet'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0"
|
||||
x-data="{ parsedFields: {} }"
|
||||
x-init="parsedFields = parseRawLog(log.raw)">
|
||||
|
||||
<!-- IP Header Information -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-global-line class="size-5 text-primary" />
|
||||
<h4 class="text-sm font-bold text-base/80 uppercase tracking-wide">IP Header</h4>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<template x-if="parsedFields.LEN">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-code-line class="size-4 text-base/50" />
|
||||
<span class="text-xs font-semibold text-base/60 uppercase tracking-wide">Raw Log Entry</span>
|
||||
<x-ri-ruler-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Packet Length</div>
|
||||
</div>
|
||||
<pre class="text-xs font-mono text-base/70 whitespace-pre-wrap break-all bg-background-secondary p-3 rounded-lg border border-neutral/10 max-h-32 overflow-y-auto" x-text="log.raw"></pre>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.LEN + ' bytes'"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.TTL">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-time-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Time to Live (TTL)</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.TTL"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.ID">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-hashtag class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Packet ID</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.ID"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.TOS">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-service-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Type of Service (TOS)</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.TOS"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.PREC">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-medal-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Precedence</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.PREC"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Fragmentation Flags -->
|
||||
<template x-if="parsedFields.DF || parsedFields.MF || parsedFields.FRAG">
|
||||
<div class="mt-4 p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<x-ri-file-damage-line class="size-4 text-warning" />
|
||||
<div class="text-xs font-bold text-base/70 uppercase tracking-wide">Fragmentation</div>
|
||||
</div>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
<template x-if="parsedFields.DF">
|
||||
<span class="px-3 py-1.5 bg-info/20 text-info rounded-lg text-xs font-bold">Don't Fragment (DF)</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.MF">
|
||||
<span class="px-3 py-1.5 bg-warning/20 text-warning rounded-lg text-xs font-bold">More Fragments (MF)</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.FRAG">
|
||||
<span class="px-3 py-1.5 bg-base/20 text-base rounded-lg text-xs font-bold">Fragment Offset: <span x-text="parsedFields.FRAG"></span></span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- TCP Specific Information -->
|
||||
<template x-if="log.protocol && log.protocol.toUpperCase() === 'TCP'">
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-flashlight-line class="size-5 text-success" />
|
||||
<h4 class="text-sm font-bold text-base/80 uppercase tracking-wide">TCP Information</h4>
|
||||
</div>
|
||||
|
||||
<!-- TCP Flags -->
|
||||
<template x-if="parsedFields.SYN || parsedFields.ACK || parsedFields.FIN || parsedFields.RST || parsedFields.PSH || parsedFields.URG">
|
||||
<div class="mb-4 p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<x-ri-flag-line class="size-4 text-primary" />
|
||||
<div class="text-xs font-bold text-base/70 uppercase tracking-wide">TCP Flags</div>
|
||||
</div>
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
<template x-if="parsedFields.SYN">
|
||||
<span class="px-3 py-1.5 bg-info/20 text-info rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-play-circle-line class="size-3" />
|
||||
SYN
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.ACK">
|
||||
<span class="px-3 py-1.5 bg-success/20 text-success rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-checkbox-circle-line class="size-3" />
|
||||
ACK
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.FIN">
|
||||
<span class="px-3 py-1.5 bg-warning/20 text-warning rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-stop-circle-line class="size-3" />
|
||||
FIN
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.RST">
|
||||
<span class="px-3 py-1.5 bg-danger/20 text-danger rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-close-circle-line class="size-3" />
|
||||
RST
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.PSH">
|
||||
<span class="px-3 py-1.5 bg-primary/20 text-primary rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-send-plane-line class="size-3" />
|
||||
PSH
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="parsedFields.URG">
|
||||
<span class="px-3 py-1.5 bg-danger/20 text-danger rounded-lg text-xs font-bold flex items-center gap-1">
|
||||
<x-ri-alert-line class="size-3" />
|
||||
URG
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- TCP Details -->
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<template x-if="parsedFields.WINDOW">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-window-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Window Size</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.WINDOW + ' bytes'"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.SEQ">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-sort-number-asc class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Sequence Number</div>
|
||||
</div>
|
||||
<div class="font-mono text-sm font-bold break-all" x-text="parsedFields.SEQ"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.URGP">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-alert-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Urgent Pointer</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.URGP"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.RES">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-reserved-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">Reserved</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.RES"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ICMP Specific Information -->
|
||||
<template x-if="log.protocol && log.protocol.toUpperCase() === 'ICMP'">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-pulse-line class="size-5 text-info" />
|
||||
<h4 class="text-sm font-bold text-base/80 uppercase tracking-wide">ICMP Information</h4>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<template x-if="parsedFields.TYPE">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-file-list-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">ICMP Type</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.TYPE"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="parsedFields.CODE">
|
||||
<div class="p-4 bg-background rounded-xl border border-neutral/20">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<x-ri-code-s-slash-line class="size-4 text-base/50" />
|
||||
<div class="text-xs text-base/50">ICMP Code</div>
|
||||
</div>
|
||||
<div class="font-mono text-base font-bold" x-text="parsedFields.CODE"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- No additional details message -->
|
||||
<template x-if="Object.keys(parsedFields).length === 0">
|
||||
<div class="text-center py-12">
|
||||
<x-ri-file-info-line class="size-12 mx-auto mb-3 text-base/30" />
|
||||
<p class="text-base/60 text-sm">No additional packet details available</p>
|
||||
<p class="text-base/40 text-xs mt-1">Switch to Raw Data tab to view complete log entry</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Raw Data Tab -->
|
||||
<div x-show="activeTab === 'raw'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
|
||||
<template x-if="log.raw">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-code-box-line class="size-5 text-primary" />
|
||||
<h4 class="text-sm font-bold text-base/80 uppercase tracking-wide">Complete Log Entry</h4>
|
||||
</div>
|
||||
<button @click="navigator.clipboard.writeText(log.raw).then(() => alert('Copied to clipboard!'))"
|
||||
class="px-3 py-1.5 text-xs font-semibold bg-primary/10 text-primary border border-primary/30 rounded-lg hover:bg-primary/20 transition-colors inline-flex items-center gap-2">
|
||||
<x-ri-file-copy-line class="size-3" />
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-background rounded-xl border border-neutral/20 p-4">
|
||||
<pre class="text-xs font-mono text-base/80 whitespace-pre-wrap break-all leading-relaxed" x-text="log.raw"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!log.raw">
|
||||
<div class="text-center py-12">
|
||||
<x-ri-file-damage-line class="size-12 mx-auto mb-3 text-base/30" />
|
||||
<p class="text-base/60 text-sm">No raw log data available</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Actions -->
|
||||
<div class="mt-6 pt-4 border-t border-neutral/20 flex justify-end gap-2">
|
||||
<div class="p-4 bg-background border-t border-neutral/20 flex flex-wrap justify-between gap-3">
|
||||
<a :href="'{{ route('proxmox.server.statistics', ['server' => $server->id]) }}?network_search=' + encodeURIComponent(log.source || '') + '#network-analysis-card'"
|
||||
class="px-4 py-2 text-sm font-medium bg-primary/10 text-primary border border-primary/30 rounded-lg hover:bg-primary/20 transition-colors inline-flex items-center gap-2">
|
||||
class="px-4 py-2.5 text-sm font-semibold bg-primary text-white rounded-lg hover:bg-primary/90 transition-all inline-flex items-center gap-2 shadow-lg shadow-primary/20">
|
||||
<x-ri-line-chart-line class="size-4" />
|
||||
View in Network Analysis
|
||||
</a>
|
||||
<button @click="showStateModal = false" class="px-4 py-2 text-sm font-medium bg-base/10 text-base/70 border border-neutral/30 rounded-lg hover:bg-base/20 transition-colors">
|
||||
<button @click="showStateModal = false"
|
||||
class="px-4 py-2.5 text-sm font-semibold bg-base/10 text-base/80 border border-neutral/30 rounded-lg hover:bg-base/20 transition-colors">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user