mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 23:01:29 +00:00
541 lines
34 KiB
PHP
541 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>
|
|
<!-- Welcome Section -->
|
|
<x-admin.card class="admin-dashboard-page__hero p-6">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div>
|
|
<p class="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-primary-600 dark:text-primary-300">Operations overview</p>
|
|
<h1 class="text-2xl font-semibold tracking-tight text-gray-950 dark:text-white sm:text-3xl">Admin Dashboard</h1>
|
|
<p class="mt-2 text-gray-600 dark:text-gray-300">Monitor index health, users, releases, and site activity from one workspace.</p>
|
|
</div>
|
|
<div class="rounded-lg bg-gray-50 dark:bg-gray-900 px-4 py-3 text-sm text-gray-600 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>
|
|
</div>
|
|
</x-admin.card>
|
|
|
|
<!-- 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 →</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 →</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) --}}
|