Files
newznab-tmux-NNTmux/resources/views/admin/dashboard.blade.php
T
2026-08-28 00:59:02 +02:00

535 lines
34 KiB
PHP

@extends('layouts.admin')
@section('content')
@php
$dashboardLastRefreshedAt = now()->format('H:i:s');
$dashboardStatusBadgeClasses = static function (int $status): string {
return match ($status) {
\App\Models\Settings::REGISTER_STATUS_OPEN => 'border border-emerald-500/30 bg-emerald-600 text-white shadow-sm dark:border-emerald-300/20 dark:bg-emerald-500 dark:text-slate-950',
\App\Models\Settings::REGISTER_STATUS_INVITE => 'border border-amber-500/30 bg-amber-500 text-slate-950 shadow-sm dark:border-amber-200/20 dark:bg-amber-400 dark:text-slate-950',
default => 'border border-rose-500/30 bg-rose-600 text-white shadow-sm dark:border-rose-200/20 dark:bg-rose-500 dark:text-white',
};
};
@endphp
<div x-data="adminDashboard"
id="adminDashboard"
class="admin-dashboard-page"
data-data-url="{{ route('admin.api.dashboard-data') }}"
data-refresh-interval="{{ 60 * 1000 }}">
<div class="admin-dashboard-page__content space-y-6" data-dashboard-content>
<x-admin.page-header title="Admin Dashboard" icon="fas fa-gauge-high" subtitle="Monitor index health, users, releases, and site activity from one workspace." class="admin-dashboard-page__hero">
<x-slot:actions>
<div class="rounded-xl border border-gray-200 bg-white/70 px-4 py-2 text-sm text-gray-600 dark:border-gray-600 dark:bg-gray-800/70 dark:text-gray-300 lg:text-right">
<p class="font-medium text-gray-700 dark:text-gray-200">
<i class="fas fa-sync-alt mr-1"></i> Last dashboard refresh: <span data-stat="last-refresh">{{ $dashboardLastRefreshedAt }}</span>
</p>
<p class="mt-1 text-xs text-green-600 dark:text-green-400">Auto-refreshes every minute</p>
</div>
</x-slot:actions>
</x-admin.page-header>
<!-- Stats Grid -->
<div class="admin-dashboard-page__stats-grid grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
<!-- Total Releases -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Total Releases</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="releases">{{ number_format($stats['releases'] ?? 0) }}</p>
</div>
<div class="w-12 h-12 bg-blue-100 dark:bg-blue-900 rounded-lg flex items-center justify-center">
<i class="fas fa-download text-2xl text-blue-600 dark:text-blue-400"></i>
</div>
</div>
<div class="mt-4">
<span class="text-sm text-green-600 dark:text-green-400">
<i class="fas fa-arrow-up"></i> <span data-stat="releases-today">{{ number_format($stats['releases_today'] ?? 0) }}</span> today
</span>
</div>
</div>
<!-- Active Users -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Active Users</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="users">{{ number_format($stats['users'] ?? 0) }}</p>
</div>
<div class="w-12 h-12 bg-green-100 dark:bg-green-900 rounded-lg flex items-center justify-center">
<i class="fas fa-users text-2xl text-green-600 dark:text-green-400"></i>
</div>
</div>
<div class="mt-4">
<span class="text-sm text-blue-600 dark:text-blue-400">
<i class="fas fa-user-plus"></i> <span data-stat="users-today">{{ $stats['users_today'] ?? 0 }}</span> registered today
</span>
</div>
</div>
<!-- Active Groups -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Active Groups</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="active-groups">{{ number_format($stats['active_groups'] ?? 0) }}</p>
</div>
<div class="w-12 h-12 bg-purple-100 dark:bg-purple-900 rounded-lg flex items-center justify-center">
<i class="fas fa-layer-group text-2xl text-purple-600 dark:text-purple-400"></i>
</div>
</div>
<div class="mt-4">
<span class="text-sm text-gray-600 dark:text-gray-400">
<span data-stat="groups">{{ number_format($stats['groups'] ?? 0) }}</span> total groups
</span>
</div>
</div>
<!-- Failed Releases -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Failed Releases</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="failed">{{ number_format($stats['failed'] ?? 0) }}</p>
</div>
<div class="w-12 h-12 bg-red-100 dark:bg-red-900 rounded-lg flex items-center justify-center">
<i class="fas fa-exclamation-triangle text-2xl text-red-600 dark:text-red-400"></i>
</div>
</div>
<div class="mt-4">
<a href="{{ url('/admin/failrel-list') }}" class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">
View failed releases <i class="fas fa-arrow-right"></i>
</a>
</div>
</div>
<!-- Reported Releases -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Reported Releases</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="reported">{{ number_format($stats['reported'] ?? 0) }}</p>
</div>
<div class="w-12 h-12 bg-orange-100 dark:bg-orange-900 rounded-lg flex items-center justify-center">
<i class="fas fa-flag text-2xl text-orange-600 dark:text-orange-400"></i>
</div>
</div>
<div class="mt-4">
<a href="{{ url('/admin/release-reports') }}" class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">
View reports <i class="fas fa-arrow-right"></i>
</a>
</div>
</div>
<!-- Deleted Users -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-500 dark:text-gray-400 mb-1">Deleted Users</p>
<p class="text-3xl font-bold text-gray-800 dark:text-gray-200" data-stat="deleted-users-total">{{ number_format(($stats['soft_deleted_users'] ?? 0) + ($stats['permanently_deleted_users'] ?? 0)) }}</p>
</div>
<div class="w-12 h-12 bg-red-100 dark:bg-red-900 rounded-lg flex items-center justify-center">
<i class="fas fa-user-slash text-2xl text-red-600 dark:text-red-400"></i>
</div>
</div>
<div class="mt-4 space-y-1">
<span class="text-sm text-yellow-600 dark:text-yellow-400 block">
<i class="fas fa-trash"></i> <span data-stat="soft-deleted-users">{{ number_format($stats['soft_deleted_users'] ?? 0) }}</span> soft deleted
</span>
<span class="text-sm text-red-600 dark:text-red-400 block">
<i class="fas fa-trash-alt"></i> <span data-stat="permanently-deleted-users">{{ number_format($stats['permanently_deleted_users'] ?? 0) }}</span> permanently deleted
</span>
</div>
<div class="mt-2">
<a href="{{ route('admin.deleted.users.index') }}" class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300">
View deleted users <i class="fas fa-arrow-right"></i>
</a>
</div>
</div>
</div>
<!-- Site Status & Active Incidents (deferred populated by Alpine on mount) -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="site-status">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center justify-between">
<span>
<i class="fas fa-signal mr-2 text-blue-600 dark:text-blue-400"></i>
Site Status
</span>
<a href="{{ route('admin.status.index') }}" class="text-xs text-blue-600 dark:text-blue-400 hover:underline font-normal">Manage &rarr;</a>
</h3>
<div data-widget-loading class="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-4">
<div class="h-14 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
<div class="h-14 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
<div class="h-14 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
</div>
<div data-widget-content class="hidden">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-4" data-services-grid></div>
<div class="border-t border-gray-200 dark:border-gray-700 pt-3" data-incidents-region></div>
</div>
</div>
<!-- Registration Status Widget -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="registration-status">
<div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div>
<h3 class="text-xl font-semibold text-gray-800 dark:text-gray-200 flex items-center">
<i class="fas fa-user-plus mr-2 text-blue-600 dark:text-blue-400"></i>
Site Registration Status
</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
Live registration availability, manual baseline, and the current schedule summary.
</p>
</div>
<a href="{{ route('admin.registrations.index') }}"
class="inline-flex items-center rounded-lg border border-blue-700 bg-blue-600 px-4 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:border-blue-300/20 dark:bg-blue-500 dark:text-white dark:hover:bg-blue-400 dark:focus:ring-offset-gray-900">
<i class="fas fa-arrow-up-right-from-square mr-2"></i>Manage Registrations
</a>
</div>
<div class="mt-6 grid grid-cols-1 gap-4 xl:grid-cols-3">
<div class="rounded-xl border border-gray-200 bg-gray-50 p-5 dark:border-gray-700 dark:bg-gray-900">
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Effective Status</p>
<div class="mt-3 flex flex-wrap items-center gap-2">
<span data-registration="effective-badge"
class="inline-flex items-center justify-center rounded-full px-3 py-1.5 text-sm font-semibold {{ $dashboardStatusBadgeClasses($registrationStatus['effective_status']) }}">
{{ $registrationStatus['effective_status_label'] }}
</span>
<span data-registration="scheduled-override"
@class([
'inline-flex items-center justify-center rounded-full border border-blue-500/30 bg-blue-600 px-3 py-1.5 text-xs font-semibold text-white shadow-sm dark:border-blue-300/20 dark:bg-blue-500 dark:text-white',
'hidden' => ! $registrationStatus['scheduled_override_active'],
])>
Scheduled Override
</span>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400" data-registration="message">{{ $registrationStatus['message'] }}</p>
</div>
<div class="rounded-xl border border-gray-200 bg-gray-50 p-5 dark:border-gray-700 dark:bg-gray-900">
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Manual Baseline</p>
<div class="mt-3">
<span data-registration="manual-badge"
class="inline-flex items-center justify-center rounded-full px-3 py-1.5 text-sm font-semibold {{ $dashboardStatusBadgeClasses($registrationStatus['manual_status']) }}">
{{ $registrationStatus['manual_status_label'] }}
</span>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400">
Used whenever no scheduled open period is currently active.
</p>
</div>
<div class="rounded-xl border border-gray-200 bg-gray-50 p-5 dark:border-gray-700 dark:bg-gray-900">
@if($registrationStatus['active_period'])
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Active Open Period</p>
<div class="mt-3">
<p class="text-base font-semibold text-gray-900 dark:text-gray-100">{{ $registrationStatus['active_period']->name }}</p>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ formatDateTime($registrationStatus['active_period']->starts_at) }} to
{{ formatDateTime($registrationStatus['active_period']->ends_at) }}
</p>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400">This window is active on the public registration form right now.</p>
@elseif($nextRegistrationPeriod)
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Next Scheduled Open Period</p>
<div class="mt-3">
<p class="text-base font-semibold text-gray-900 dark:text-gray-100">{{ $nextRegistrationPeriod->name }}</p>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ formatDateTime($nextRegistrationPeriod->starts_at) }} to
{{ formatDateTime($nextRegistrationPeriod->ends_at) }}
</p>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400">The next temporary public signup window is already scheduled.</p>
@else
<p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Scheduled Open Periods</p>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400">
No active or upcoming open-registration periods are currently scheduled.
</p>
@endif
</div>
</div>
</div>
<!-- User Statistics Widget (deferred) -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="user-stats">
<h3 class="text-xl font-semibold text-gray-800 dark:text-gray-200 mb-6 flex items-center">
<i class="fas fa-chart-line mr-2 text-blue-600 dark:text-blue-400"></i>
User Statistics
</h3>
<div data-widget-loading class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
@for($i = 0; $i < 5; $i++)
<div class="h-24 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
@for($i = 0; $i < 4; $i++)
<div class="h-64 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
</div>
<div data-widget-content class="hidden">
<!-- Summary Stats Row -->
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 mb-6" data-summary-grid></div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Users by Role Table -->
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-user-tag mr-2 text-indigo-600 dark:text-indigo-400"></i>
Users by Role
</h4>
<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead><tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Role</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Count</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Percentage</th>
</tr></thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700" data-roles-tbody></tbody>
</table></div>
</div>
<!-- Top Downloaders Table -->
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-trophy mr-2 text-yellow-600 dark:text-yellow-400"></i>
Top Downloaders (Last 7 Days)
</h4>
<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead><tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Rank</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Username</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Downloads</th>
</tr></thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700" data-downloaders-tbody></tbody>
</table></div>
</div>
<!-- Charts -->
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-chart-bar mr-2 text-green-600 dark:text-green-400"></i>
Downloads (Last 7 Days - Hourly)
</h4>
<div class="chart-container"><canvas id="downloadsChart"></canvas></div>
</div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-chart-area mr-2 text-purple-600 dark:text-purple-400"></i>
API/RSS Hits (Last 7 Days - Hourly)
</h4>
<div class="chart-container"><canvas id="apiHitsChart"></canvas></div>
</div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-chart-line mr-2 text-green-600 dark:text-green-400"></i>
Downloads (Last 60 Minutes)
</h4>
<div class="chart-container"><canvas id="downloadsMinuteChart"></canvas></div>
</div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h4 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
<i class="fas fa-chart-line mr-2 text-purple-600 dark:text-purple-400"></i>
API/RSS Hits (Last 60 Minutes)
</h4>
<div class="chart-container"><canvas id="apiHitsMinuteChart"></canvas></div>
</div>
</div>
</div>
</div>
<!-- System Metrics (CPU & RAM) deferred -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="system-metrics">
<h3 class="text-xl font-semibold text-gray-800 dark:text-gray-200 mb-6 flex items-center">
<i class="fas fa-server mr-2 text-orange-600 dark:text-orange-400"></i>
System Resources
</h3>
<div data-widget-loading class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="h-40 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
<div class="h-40 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
@for($i = 0; $i < 4; $i++)
<div class="h-56 rounded-lg bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
</div>
<div data-widget-content class="hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<!-- CPU card -->
<div class="bg-linear-to-br from-orange-50 to-orange-100 dark:from-orange-900 dark:to-orange-800 rounded-lg p-4">
<div class="flex items-center justify-between mb-3">
<div>
<p class="text-sm text-orange-600 dark:text-orange-300 font-medium mb-1">CPU Usage</p>
<p class="text-3xl font-bold text-orange-800 dark:text-orange-100" data-metric="cpu-current"></p>
</div>
<div class="w-12 h-12 bg-orange-200 dark:bg-orange-700 rounded-lg flex items-center justify-center">
<i class="fas fa-microchip text-2xl text-orange-600 dark:text-orange-300"></i>
</div>
</div>
<div class="border-t border-orange-200 dark:border-orange-700 pt-3 space-y-2 text-xs">
<div class="flex justify-between"><span class="text-orange-600 dark:text-orange-300">Cores:</span><span class="font-semibold text-orange-800 dark:text-orange-100" data-metric="cpu-cores"></span></div>
<div class="flex justify-between"><span class="text-orange-600 dark:text-orange-300">Threads:</span><span class="font-semibold text-orange-800 dark:text-orange-100" data-metric="cpu-threads"></span></div>
<div class="flex justify-between"><span class="text-orange-600 dark:text-orange-300">Load (1m):</span><span class="font-semibold text-orange-800 dark:text-orange-100" data-metric="cpu-load-1min"></span></div>
<div class="flex justify-between"><span class="text-orange-600 dark:text-orange-300">Load (5m):</span><span class="font-semibold text-orange-800 dark:text-orange-100" data-metric="cpu-load-5min"></span></div>
<div class="flex justify-between"><span class="text-orange-600 dark:text-orange-300">Load (15m):</span><span class="font-semibold text-orange-800 dark:text-orange-100" data-metric="cpu-load-15min"></span></div>
<div class="pt-2 border-t border-orange-200 dark:border-orange-700">
<p class="text-xs text-orange-600 dark:text-orange-300 truncate" data-metric="cpu-model"></p>
</div>
</div>
</div>
<!-- RAM card -->
<div class="bg-linear-to-br from-cyan-50 to-cyan-100 dark:from-cyan-900 dark:to-cyan-800 rounded-lg p-4">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-cyan-600 dark:text-cyan-300 font-medium mb-1">RAM Usage</p>
<p class="text-3xl font-bold text-cyan-800 dark:text-cyan-100" data-metric="ram-current"></p>
<p class="text-xs text-cyan-600 dark:text-cyan-300 mt-1" data-metric="ram-details"></p>
</div>
<div class="w-12 h-12 bg-cyan-200 dark:bg-cyan-700 rounded-lg flex items-center justify-center">
<i class="fas fa-memory text-2xl text-cyan-600 dark:text-cyan-300"></i>
</div>
</div>
</div>
</div>
<div class="space-y-6">
<div>
<h4 class="text-md font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
<i class="fas fa-clock mr-2 text-blue-600 dark:text-blue-400"></i>
Last 24 Hours (Hour by Hour)
</h4>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h5 class="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-3"><i class="fas fa-microchip mr-2 text-orange-600 dark:text-orange-400"></i>CPU Usage</h5>
<div class="chart-container"><canvas id="cpuHistory24hChart" data-chart-label="CPU Usage %"></canvas></div>
</div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h5 class="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-3"><i class="fas fa-memory mr-2 text-cyan-600 dark:text-cyan-400"></i>RAM Usage</h5>
<div class="chart-container"><canvas id="ramHistory24hChart" data-chart-label="RAM Usage %"></canvas></div>
</div>
</div>
</div>
<div>
<h4 class="text-md font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center">
<i class="fas fa-calendar-alt mr-2 text-purple-600 dark:text-purple-400"></i>
Last 30 Days (Day by Day)
</h4>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h5 class="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-3"><i class="fas fa-microchip mr-2 text-orange-600 dark:text-orange-400"></i>CPU Usage</h5>
<div class="chart-container"><canvas id="cpuHistory30dChart" data-chart-label="CPU Usage %"></canvas></div>
</div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<h5 class="text-sm font-semibold text-gray-800 dark:text-gray-200 mb-3"><i class="fas fa-memory mr-2 text-cyan-600 dark:text-cyan-400"></i>RAM Usage</h5>
<div class="chart-container"><canvas id="ramHistory30dChart" data-chart-label="RAM Usage %"></canvas></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- System Status (deferred) -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="system-status">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">System Status</h3>
<div data-widget-loading class="space-y-3">
@for($i = 0; $i < 4; $i++)
<div class="h-6 rounded bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
<div data-widget-content class="hidden space-y-3" data-system-services></div>
</div>
<!-- Recent Activity (deferred) -->
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="recent-activity">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center justify-between">
<span>
<i class="fas fa-history mr-2 text-indigo-600 dark:text-indigo-400"></i>
Recent User Activity
</span>
<span class="text-xs text-gray-500 dark:text-gray-400" id="activity-last-updated">
<i class="fas fa-sync-alt"></i> <span data-metric="activity-updated">loading…</span>
</span>
</h3>
<div data-widget-loading class="space-y-3">
@for($i = 0; $i < 5; $i++)
<div class="h-10 rounded bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
<div data-widget-content class="hidden space-y-3" id="recent-activity-container"></div>
</div>
</div>
<!-- Recent Payments Widget (deferred) -->
@if(! empty($hasRecentPayments))
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-gray-200 dark:border-gray-700"
data-widget="recent-payments">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4 flex items-center justify-between">
<span>
<i class="fas fa-credit-card mr-2 text-emerald-600 dark:text-emerald-400"></i>
Last 5 Payments
</span>
<a href="{{ route('admin.payment-list') }}" class="text-xs text-blue-600 dark:text-blue-400 hover:underline font-normal">View all &rarr;</a>
</h3>
<div data-widget-loading class="space-y-3">
@for($i = 0; $i < 5; $i++)
<div class="h-12 rounded bg-gray-100 dark:bg-gray-900 animate-pulse"></div>
@endfor
</div>
<div data-widget-content class="hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Date</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">User</th>
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Item</th>
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Amount</th>
<th class="px-4 py-2 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700" data-payments-tbody></tbody>
</table>
</div>
</div>
</div>
@endif
<!-- Quick Links -->
<x-admin.card class="p-6">
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Quick Links</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<a href="{{ url('/admin/user-list') }}" class="flex flex-col items-center p-4 bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:bg-gray-800 rounded-lg transition">
<i class="fas fa-users text-3xl text-blue-600 dark:text-blue-400 mb-2"></i>
<span class="text-sm font-medium text-gray-700">Manage Users</span>
</a>
<a href="{{ url('/admin/release-list') }}" class="flex flex-col items-center p-4 bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:bg-gray-800 rounded-lg transition">
<i class="fas fa-download text-3xl text-green-600 mb-2"></i>
<span class="text-sm font-medium text-gray-700">Manage Releases</span>
</a>
<a href="{{ url('/admin/category-list') }}" class="flex flex-col items-center p-4 bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:bg-gray-800 rounded-lg transition">
<i class="fas fa-folder text-3xl text-purple-600 mb-2"></i>
<span class="text-sm font-medium text-gray-700">Categories</span>
</a>
<a href="{{ url('/admin/site-edit') }}" class="flex flex-col items-center p-4 bg-gray-50 dark:bg-gray-900 hover:bg-gray-100 dark:bg-gray-800 rounded-lg transition">
<i class="fas fa-cog text-3xl text-orange-600 mb-2"></i>
<span class="text-sm font-medium text-gray-700">Settings</span>
</a>
</div>
</x-admin.card>
</div>
</div>
@endsection
{{-- Chart.js is bundled via Vite (imported in resources/js/alpine/components/admin/dashboard.js) --}}