New Blade layout, copy, and visual system for the monitoring tab; RRD hosts use data-statistics-chart hooks; tables use pxStatTableKit and data-statistics-data-row; network and comparison panels use new selectors; CSV helpers renamed (pxExport*); modals and telemetry refreshed. Made-with: Cursor
180 lines
10 KiB
PHP
180 lines
10 KiB
PHP
<x-proxmox::layout :server="$server" view="statistics" :status="$status" :status-polling="true" :status-polling-interval="'2s'">
|
|
@once
|
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts" onload="window.apexChartsLoaded = true"></script>
|
|
@endonce
|
|
<script data-navigate-track>
|
|
if (typeof window.copyToClipboard === 'undefined') {
|
|
window.copyToClipboard = function(text, el) {
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
const icon = el.querySelector('svg');
|
|
if (icon) {
|
|
icon.classList.add('text-success');
|
|
setTimeout(() => icon.classList.remove('text-success'), 1500);
|
|
}
|
|
window.dispatchEvent(new CustomEvent('toast', {
|
|
detail: { message: 'Value copied to clipboard', type: 'success' }
|
|
}));
|
|
}).catch(() => {});
|
|
};
|
|
}
|
|
</script>
|
|
|
|
<div class="flex min-w-0 max-w-full flex-col gap-8" data-server-id="{{ $server->id }}" wire:key="proxmox-statistics-v2-root">
|
|
|
|
<header class="space-y-2">
|
|
<div class="flex items-center gap-3 flex-wrap">
|
|
<div class="flex items-center gap-2 min-w-0">
|
|
<h2 class="text-2xl font-semibold tracking-tight break-words">Insight console</h2>
|
|
<div class="relative" x-data="{ open: false }" x-cloak>
|
|
<button type="button" @click="open = true" class="text-base/50 hover:text-base/70 transition-colors" aria-label="Explain this workspace">
|
|
<x-ri-question-line class="size-4" />
|
|
</button>
|
|
<div x-show="open"
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0"
|
|
x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0"
|
|
@click="open = false"
|
|
@keydown.escape.window="open = false"
|
|
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
|
style="display: none;">
|
|
</div>
|
|
<div x-show="open"
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0 scale-95"
|
|
x-transition:enter-end="opacity-100 scale-100"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="opacity-100 scale-100"
|
|
x-transition:leave-end="opacity-0 scale-95"
|
|
@click.self="open = false"
|
|
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
|
style="display: none;">
|
|
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
|
<button type="button" @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors" aria-label="Close explainer">
|
|
<x-ri-close-line class="size-5" />
|
|
</button>
|
|
<div class="flex items-center gap-3 mb-4 pr-8">
|
|
<div class="flex items-center justify-center w-10 h-10 rounded-lg bg-primary/12">
|
|
<x-ri-dashboard-line class="size-5 text-primary" />
|
|
</div>
|
|
<h6 class="font-sans text-lg font-semibold leading-tight">What lives on this screen</h6>
|
|
</div>
|
|
<p class="block font-sans text-sm font-normal leading-relaxed text-base/90 mb-4">
|
|
A single pane that stitches together live polls, Proxmox RRD graphs, archived samples, job consoles, lifecycle highlights, period math, and—when configured—Core Router session intelligence.
|
|
</p>
|
|
<ul class="list-disc space-y-2 pl-5 text-xs text-base/75">
|
|
<li><span class="font-semibold text-base/90">Pulse tiles</span> — instant CPU/RAM from the same status feed as Overview, plus archive and signal counts.</li>
|
|
<li><span class="font-semibold text-base/90">RRD studio</span> — interactive charts with horizon, blend mode, and CSV extracts.</li>
|
|
<li><span class="font-semibold text-base/90">Evidence lockers</span> — tabular archives for samples, UPIDs, and distilled lifecycle beats.</li>
|
|
<li><span class="font-semibold text-base/90">Contrast & fabric</span> — compare eras side-by-side, then inspect live sessions, peers, and ports.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="text-sm text-base/70 max-w-3xl leading-relaxed">
|
|
Align what the hypervisor reports right now with what it recorded yesterday—without hopping tabs.
|
|
</p>
|
|
</header>
|
|
|
|
@php
|
|
$statCpuCores = max(1, (int) ($status?->cpus ?? 1));
|
|
$statLiveCpuPct = round(max(0, ($status?->cpu ?? 0) * 100), 1);
|
|
$statMemMax = (int) ($status?->maxmem ?? 0);
|
|
$statMemUsed = (int) ($status?->mem ?? 0);
|
|
$statLiveMemPct = $statMemMax > 0 ? round(($statMemUsed / $statMemMax) * 100, 1) : 0;
|
|
$statSnapshotCount = $this->statistics->total();
|
|
$statTaskBufferCount = count($this->taskHistory ?? []);
|
|
$statLifecyclePreview = count($this->chartEvents ?? []);
|
|
|
|
$statGlanceCards = [
|
|
[
|
|
'label' => 'CPU pulse',
|
|
'value' => $statLiveCpuPct . '%',
|
|
'hint' => $statCpuCores . ' vCPU budget',
|
|
'icon' => 'x-ri-cpu-line',
|
|
'tone' => 'sky',
|
|
],
|
|
[
|
|
'label' => 'RAM pulse',
|
|
'value' => $statLiveMemPct . '%',
|
|
'hint' => $statMemMax > 0
|
|
? \Illuminate\Support\Number::fileSize(bytes: $statMemUsed) . ' of ' . \Illuminate\Support\Number::fileSize(bytes: $statMemMax)
|
|
: 'RAM cap unknown',
|
|
'icon' => 'x-ri-database-2-line',
|
|
'tone' => 'emerald',
|
|
],
|
|
[
|
|
'label' => 'Stored samples',
|
|
'value' => number_format($statSnapshotCount),
|
|
'hint' => 'Hourly automation + five manual pins',
|
|
'icon' => 'x-ri-stack-line',
|
|
'tone' => 'violet',
|
|
],
|
|
[
|
|
'label' => 'Signals loaded',
|
|
'value' => number_format($statTaskBufferCount) . ' jobs',
|
|
'hint' => $statLifecyclePreview . ' lifecycle beats mapped',
|
|
'icon' => 'x-ri-pulse-line',
|
|
'tone' => 'amber',
|
|
],
|
|
];
|
|
$toneRing = [
|
|
'sky' => 'ring-sky-500/30 bg-sky-500/[0.04]',
|
|
'emerald' => 'ring-emerald-500/30 bg-emerald-500/[0.04]',
|
|
'violet' => 'ring-violet-500/30 bg-violet-500/[0.04]',
|
|
'amber' => 'ring-amber-500/30 bg-amber-500/[0.04]',
|
|
];
|
|
@endphp
|
|
|
|
<section class="rounded-2xl ring-1 ring-neutral/40 bg-background-secondary/80 p-6 shadow-sm" aria-labelledby="px-stat-pulse-heading">
|
|
<div class="flex flex-col gap-2 md:flex-row md:items-center md:justify-between mb-6">
|
|
<div>
|
|
<h3 id="px-stat-pulse-heading" class="text-lg font-semibold tracking-tight">Live pulse tiles</h3>
|
|
<p class="text-sm text-base/70">Numbers mirror the Overview status ticker; charts underneath carry the longer story.</p>
|
|
</div>
|
|
<p class="text-xs text-base/50">Point-in-time only—scroll for RRD and archives.</p>
|
|
</div>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4">
|
|
@foreach ($statGlanceCards as $card)
|
|
<div class="rounded-2xl p-4 ring-1 {{ $toneRing[$card['tone']] ?? 'ring-neutral/30' }} flex flex-col gap-3 transition hover:shadow-md">
|
|
<div class="flex items-center justify-between gap-2">
|
|
<p class="text-xs font-semibold tracking-wide uppercase text-base/60">{{ $card['label'] }}</p>
|
|
<div class="flex size-9 items-center justify-center rounded-xl bg-background/90 ring-1 ring-neutral/30">
|
|
<x-dynamic-component :component="$card['icon']" class="size-4 text-primary" />
|
|
</div>
|
|
</div>
|
|
<p class="text-2xl font-semibold leading-tight">{{ $card['value'] }}</p>
|
|
<p class="text-xs text-base/60 leading-relaxed">{{ $card['hint'] }}</p>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</section>
|
|
|
|
@include('proxmox::partials.statistics.telemetry-inner')
|
|
|
|
@include('proxmox::partials.statistics.history-inner')
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-10 md:items-stretch">
|
|
<div class="grid gap-10 items-start min-w-0">
|
|
@include('proxmox::partials.statistics.tasks-inner')
|
|
</div>
|
|
<div class="grid gap-10 items-start min-w-0">
|
|
@include('proxmox::partials.statistics.lifecycle-inner')
|
|
</div>
|
|
</div>
|
|
|
|
@include('proxmox::partials.statistics.comparison-inner')
|
|
|
|
@include('proxmox::partials.statistics.network-inner')
|
|
|
|
@include('proxmox::partials.statistics.modals-inner')
|
|
|
|
@include('proxmox::partials.statistics.scripts-inner')
|
|
|
|
</div>
|
|
</x-proxmox::layout>
|