{{-- resources/views/dashboard.blade.php --}} @extends('layouts.app') @section('header_actions')@endsection @section('content') @php $memPct = ($memory_total_mb ?? 0) > 0 ? round(($memory_used_mb ?? 0) / $memory_total_mb * 100, 1) : 0; $memUsedGb = ($memory_used_mb ?? 0) > 0 ? round(($memory_used_mb ?? 0) / 1024, 2) : 0; $memTotalGb = ($memory_total_mb ?? 0) > 0 ? round(($memory_total_mb ?? 0) / 1024, 2) : 0; $cpuPct = min(max(($cpu_load ?? 0) * 20, 0), 100); $diskUsedPct = 100 - ($disk_free_percent ?? 100); $acdSeconds = $today_stats['acd'] ?? 0; $acdHuman = $acdSeconds > 0 ? floor($acdSeconds / 60) . 'm ' . ($acdSeconds % 60) . 's' : '0s'; $totalCalls = $today_stats['total_calls'] ?? 0; $answered = $today_stats['answered_calls'] ?? 0; $noAnswer = $today_stats['no_answer_calls'] ?? 0; $busy = $today_stats['busy_calls'] ?? 0; $failed = $today_stats['failed_calls'] ?? 0; $answeredPct = $totalCalls > 0 ? round($answered / $totalCalls * 100) : 0; $noAnswerPct = $totalCalls > 0 ? round($noAnswer / $totalCalls * 100) : 0; $busyPct = $totalCalls > 0 ? round($busy / $totalCalls * 100) : 0; $failedPct = $totalCalls > 0 ? round($failed / $totalCalls * 100) : 0; $totalExt = ($reachable_extensions ?? 0) + ($unreachable_extensions ?? 0); $regPct = $totalExt > 0 ? round(($registered_extensions ?? 0) / $totalExt * 100, 1) : 0; $unregPct = $totalExt > 0 ? round(($unreachable_extensions ?? 0) / $totalExt * 100, 1) : 0; $trunkUp = collect($trunks ?? [])->where('status', 'Reachable')->count(); $trunkTotal = count($trunks ?? []); $trunkDown = $trunkTotal - $trunkUp; @endphp {{-- ── PAGE HEADER ── --}}

Dashboard

All systems operational
{{-- ── ROW 1: Metric cards ── --}}
System Uptime
{{ $uptime_human ?? '—' }}
100% availability
CPU Load
{{ $cpu_load ?? 0 }}%
{{ $cpuPct < 50 ? 'Low' : ($cpuPct < 80 ? 'Medium' : 'High') }}
{{ $cpuPct < 80 ? '8' : '—' }} Cores
Memory Usage
{{ $memUsedGb }} GB / {{ $memTotalGb }} GB
{{ $memPct }}% used
Disk Usage
{{ $disk_free_gb ?? 0 }} GB / {{ $disk_total_gb ?? 0 }} GB
{{ $disk_free_percent ?? 0 }}% free
{{-- ── ROW 2: Live Calls | Call Distribution | Recent Alerts ── --}}
{{-- Live Call Activity --}}
Live Call Activity LIVE
{{ $active_calls ?? 0 }}
Active Calls
0
Calls Ringing
0
Calls In Queue
Loading…
{{-- Call Distribution --}}
Call Distribution (Today)
{{-- SVG Donut --}}
@php $r = 54; $cx = 65; $cy = 65; $circ = 2 * M_PI * $r; $slices = [ ['pct' => $totalCalls > 0 ? $answered / $totalCalls : 0, 'color' => '#22c55e'], ['pct' => $totalCalls > 0 ? $noAnswer / $totalCalls : 0, 'color' => '#f59e0b'], ['pct' => $totalCalls > 0 ? $busy / $totalCalls : 0, 'color' => '#6366f1'], ['pct' => $totalCalls > 0 ? $failed / $totalCalls : 0, 'color' => '#ef4444'], ]; $offset = 0; $paths = ''; foreach ($slices as $s) { $dash = $s['pct'] * $circ; $paths .= ""; $offset += $dash; } @endphp {!! $totalCalls > 0 ? $paths : '' !!} @if($totalCalls === 0) @endif
{{ $totalCalls }}
Total Calls
{{-- Legend --}}
Answered
{{ $answered }} ({{ $answeredPct }}%)
No Answer
{{ $noAnswer }} ({{ $noAnswerPct }}%)
Busy
{{ $busy }} ({{ $busyPct }}%)
Failed
{{ $failed }} ({{ $failedPct }}%)
{{-- Recent Alerts --}}
Recent Alerts
View all alerts
@if(($cpu_load ?? 0) > 4)
High CPU Usage
CPU load is above 85%
Now
Critical
@endif @if($trunkDown > 0)
SIP Trunk Unreachable
{{ $trunkDown }} trunk(s) unreachable
Now
Warning
@endif @php $failedToday = (int) ($today_stats['failed_calls'] ?? 0); $totalToday = (int) ($today_stats['total_calls'] ?? 0); $failRate = $totalToday > 0 ? round($failedToday / $totalToday * 100, 1) : 0; @endphp @if($failedToday > 0 && $failRate >= 10)
Call Failures Detected
{{ $failRate }}% failed today ({{ $failedToday }} of {{ $totalToday }})
Today
Warning
@endif
System Running
PBX is operational
Now
Info
{{-- ── ROW 3: Extensions Health | Trunks Health | System Overview ── --}}
{{-- Extensions Health --}}
Extensions Health LIVE
{{ $totalExt }}
Total Extensions
Registered {{ $registered_extensions ?? 0 }} ({{ $regPct }}%)
Unregistered {{ $unreachable_extensions ?? 0 }} ({{ $unregPct }}%)
Inactive 0 (0%)
{{-- Trunks Health --}}
Trunks Health LIVE
{{ $trunkTotal }}
Total Trunks
Up {{ $trunkUp }} ({{ $trunkTotal > 0 ? round($trunkUp/$trunkTotal*100,1) : 0 }}%)
Degraded 0 (0%)
Down {{ $trunkDown }} ({{ $trunkTotal > 0 ? round($trunkDown/$trunkTotal*100,1) : 0 }}%)
{{-- System Overview --}}
System Overview
V-Connect Version {{ $asterisk_version ?? '22.x' }}
PBX Uptime {{ $uptime_human ?? '—' }}
System Time {{ now()->format('M j, Y H:i') }}
Time Zone {{ config('app.timezone', 'UTC') }}
Active Calls {{ $active_calls ?? 0 }}
Calls Today {{ $today_stats['total_calls'] ?? 0 }}
{{-- ── Network Quality Widget ── --}} @php // Parse RTT from Asterisk CLI (in-memory data, not DB — realtime doesn't write RTT back) $netRtts = []; $netOutput = @shell_exec('/usr/sbin/asterisk -rx "pjsip show contacts" 2>/dev/null'); if ($netOutput) { foreach (preg_split('/\r?\n/', $netOutput) as $line) { if (preg_match('/Contact:\s+(\S+)\/.*\s(Avail|NonQual)\s+([0-9.]+)\s*$/', $line, $m)) { $rtt = (float) $m[3]; if ($rtt > 0 && $rtt < 10000) { // sanity check $netRtts[] = $rtt; } } } } $netAvg = !empty($netRtts) ? round(array_sum($netRtts) / count($netRtts), 1) : null; $netMax = !empty($netRtts) ? round(max($netRtts), 1) : null; $netMin = !empty($netRtts) ? round(min($netRtts), 1) : null; $netCount = count($netRtts); $netGrade = $netAvg === null ? '—' : ($netAvg < 50 ? 'Excellent' : ($netAvg < 100 ? 'Good' : ($netAvg < 200 ? 'Fair' : 'Poor'))); $netColor = $netAvg === null ? '#94a3b8' : ($netAvg < 50 ? '#16a34a' : ($netAvg < 100 ? '#16a34a' : ($netAvg < 200 ? '#d97706' : '#dc2626'))); $netPct = $netAvg === null ? 0 : max(5, min(100, 100 - ($netAvg / 3))); @endphp
Network Quality
Live from {{ $netCount }} endpoints
{{-- Gauge arc with grade --}}
{{-- Background arc --}} {{-- Coloured fill arc --}} @if($netAvg !== null) @endif {{-- Center score text --}} {{ $netGrade }}
{{-- Metric cards --}}
Avg RTT
{{ $netAvg ?? '—' }}ms
Best
{{ $netMin ?? '—' }}ms
Worst
{{ $netMax ?? '—' }}ms
Endpoints
{{ $netCount }}
Trunks Overview LIVE
@forelse($trunks ?? [] as $trunk) @php $st = $trunk['status'] ?? 'Unknown'; $rtt = $trunk['rtt'] ?? null; $rttMs = $rtt !== null ? round($rtt) : null; $rttClass = $rttMs === null ? '' : ($rttMs < 150 ? 'db-rtt-good' : ($rttMs < 300 ? 'db-rtt-med' : 'db-rtt-bad')); $name = $trunk['name'] ?? '—'; $isTeams = stripos($name, 'team') !== false; $type = $isTeams ? 'TEAMS' : 'SIP (ITSP)'; $typeColor = $isTeams ? '#7c3aed' : '#2563eb'; $isUp = $st === 'Reachable' || $st === 'Avail'; $isDeg = $st === 'Unknown'; @endphp @empty @endforelse
Trunk Name Type Status Registration Calls (Active) Calls (24h) Avg RTT Actions
{{ $name }} {{ $type }} @if($isUp) Up @elseif($isDeg) Degraded @else Down @endif @if($isUp) Registered @else Unregistered @endif {{ $active_calls ?? 0 }} {{ $trunk['calls_today'] ?? 0 }} {{ $rttMs !== null ? $rttMs . ' ms' : '—' }}
No trunk data available.
Showing 1 to {{ count($trunks ?? []) }} of {{ count($trunks ?? []) }} trunks
@endsection