baseline
This commit is contained in:
166
pages/admin/stats/index().php
Normal file
166
pages/admin/stats/index().php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Service\TenantService;
|
||||
use MintyPHP\Service\DepartmentService;
|
||||
use MintyPHP\Service\RoleService;
|
||||
use MintyPHP\Service\UserService;
|
||||
use MintyPHP\Service\PermissionService;
|
||||
use MintyPHP\Repository\PermissionRepository;
|
||||
use MintyPHP\Repository\MailLogRepository;
|
||||
use MintyPHP\DB;
|
||||
|
||||
Guard::requirePermissionOrForbidden(PermissionService::STATS_VIEW);
|
||||
|
||||
// Basic counts
|
||||
$tenants = TenantService::list();
|
||||
$tenantCount = count($tenants);
|
||||
|
||||
$departments = DepartmentService::list();
|
||||
$departmentCount = count($departments);
|
||||
|
||||
$roles = RoleService::list();
|
||||
$roleCount = count($roles);
|
||||
|
||||
$users = UserService::list();
|
||||
$userCount = count($users);
|
||||
|
||||
$permissions = PermissionRepository::list();
|
||||
$permissionCount = count($permissions);
|
||||
|
||||
// User stats (active/inactive)
|
||||
$activeUserCount = 0;
|
||||
$inactiveUserCount = 0;
|
||||
foreach ($users as $user) {
|
||||
$isActive = (int) ($user['active'] ?? 1);
|
||||
if ($isActive === 1) {
|
||||
$activeUserCount++;
|
||||
} else {
|
||||
$inactiveUserCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Organization breakdown (per tenant)
|
||||
$tenantBreakdown = [];
|
||||
|
||||
// Load user-tenant assignments
|
||||
$userTenantAssignments = [];
|
||||
$userTenantRows = DB::select('select user_id, tenant_id from user_tenants');
|
||||
if (is_array($userTenantRows)) {
|
||||
foreach ($userTenantRows as $row) {
|
||||
$data = $row['user_tenants'] ?? $row;
|
||||
$userId = (int) ($data['user_id'] ?? 0);
|
||||
$tenantId = (int) ($data['tenant_id'] ?? 0);
|
||||
if ($userId > 0 && $tenantId > 0) {
|
||||
if (!isset($userTenantAssignments[$userId])) {
|
||||
$userTenantAssignments[$userId] = [];
|
||||
}
|
||||
$userTenantAssignments[$userId][] = $tenantId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load tenant-department assignments
|
||||
$tenantDepartmentAssignments = [];
|
||||
$tenantDepartmentRows = DB::select('select tenant_id, department_id from tenant_departments');
|
||||
if (is_array($tenantDepartmentRows)) {
|
||||
foreach ($tenantDepartmentRows as $row) {
|
||||
$data = $row['tenant_departments'] ?? $row;
|
||||
$tenantId = (int) ($data['tenant_id'] ?? 0);
|
||||
$departmentId = (int) ($data['department_id'] ?? 0);
|
||||
if ($tenantId > 0 && $departmentId > 0) {
|
||||
if (!isset($tenantDepartmentAssignments[$tenantId])) {
|
||||
$tenantDepartmentAssignments[$tenantId] = [];
|
||||
}
|
||||
$tenantDepartmentAssignments[$tenantId][] = $departmentId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tenants as $tenant) {
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
if ($tenantId === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Count departments for this tenant
|
||||
$deptCount = 0;
|
||||
$tenantDepartmentIds = $tenantDepartmentAssignments[$tenantId] ?? [];
|
||||
foreach ($departments as $dept) {
|
||||
$deptId = (int) ($dept['id'] ?? 0);
|
||||
if ($deptId > 0 && in_array($deptId, $tenantDepartmentIds, true)) {
|
||||
$deptCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Count users for this tenant
|
||||
$totalUsers = 0;
|
||||
$activeUsers = 0;
|
||||
$inactiveUsers = 0;
|
||||
foreach ($users as $user) {
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
if ($userId === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if user is assigned to this tenant
|
||||
$userTenantIds = $userTenantAssignments[$userId] ?? [];
|
||||
if (in_array($tenantId, $userTenantIds, true)) {
|
||||
$totalUsers++;
|
||||
$isActive = (int) ($user['active'] ?? 1);
|
||||
if ($isActive === 1) {
|
||||
$activeUsers++;
|
||||
} else {
|
||||
$inactiveUsers++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tenantBreakdown[] = [
|
||||
'id' => $tenantId,
|
||||
'uuid' => $tenant['uuid'] ?? '',
|
||||
'description' => $tenant['description'] ?? '',
|
||||
'departments' => $deptCount,
|
||||
'total_users' => $totalUsers,
|
||||
'active_users' => $activeUsers,
|
||||
'inactive_users' => $inactiveUsers,
|
||||
];
|
||||
}
|
||||
|
||||
// Sort by description
|
||||
usort($tenantBreakdown, function ($a, $b) {
|
||||
return strcmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? ''));
|
||||
});
|
||||
|
||||
// Mail log stats
|
||||
$mailLogTotalCount = DB::selectValue('select count(*) from mail_log');
|
||||
$mailLogTotalCount = $mailLogTotalCount ? (int) $mailLogTotalCount : 0;
|
||||
|
||||
$mailLogSentCount = DB::selectValue("select count(*) from mail_log where status = 'sent'");
|
||||
$mailLogSentCount = $mailLogSentCount ? (int) $mailLogSentCount : 0;
|
||||
|
||||
$mailLogFailedCount = DB::selectValue("select count(*) from mail_log where status = 'failed'");
|
||||
$mailLogFailedCount = $mailLogFailedCount ? (int) $mailLogFailedCount : 0;
|
||||
|
||||
$mailLogQueuedCount = DB::selectValue("select count(*) from mail_log where status = 'queued'");
|
||||
$mailLogQueuedCount = $mailLogQueuedCount ? (int) $mailLogQueuedCount : 0;
|
||||
|
||||
// Mail log stats (last 24h)
|
||||
$mailLogTotal24hCount = DB::selectValue("select count(*) from mail_log where created_at >= NOW() - INTERVAL 24 HOUR");
|
||||
$mailLogTotal24hCount = $mailLogTotal24hCount ? (int) $mailLogTotal24hCount : 0;
|
||||
|
||||
$mailLogSent24hCount = DB::selectValue("select count(*) from mail_log where status = 'sent' and created_at >= NOW() - INTERVAL 24 HOUR");
|
||||
$mailLogSent24hCount = $mailLogSent24hCount ? (int) $mailLogSent24hCount : 0;
|
||||
|
||||
$mailLogFailed24hCount = DB::selectValue("select count(*) from mail_log where status = 'failed' and created_at >= NOW() - INTERVAL 24 HOUR");
|
||||
$mailLogFailed24hCount = $mailLogFailed24hCount ? (int) $mailLogFailed24hCount : 0;
|
||||
|
||||
$mailLogQueued24hCount = DB::selectValue("select count(*) from mail_log where status = 'queued' and created_at >= NOW() - INTERVAL 24 HOUR");
|
||||
$mailLogQueued24hCount = $mailLogQueued24hCount ? (int) $mailLogQueued24hCount : 0;
|
||||
|
||||
// Calculate date range for last 24 hours
|
||||
$date24hAgo = gmdate('Y-m-d', strtotime('-24 hours'));
|
||||
$dateToday = gmdate('Y-m-d');
|
||||
|
||||
Buffer::set('title', t('Statistics'));
|
||||
283
pages/admin/stats/index(default).phtml
Normal file
283
pages/admin/stats/index(default).phtml
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @var int $tenantCount
|
||||
* @var int $departmentCount
|
||||
* @var int $roleCount
|
||||
* @var int $userCount
|
||||
* @var int $permissionCount
|
||||
* @var int $activeUserCount
|
||||
* @var int $inactiveUserCount
|
||||
* @var array $tenantBreakdown
|
||||
* @var int $mailLogTotalCount
|
||||
* @var int $mailLogSentCount
|
||||
* @var int $mailLogFailedCount
|
||||
* @var int $mailLogQueuedCount
|
||||
* @var int $mailLogTotal24hCount
|
||||
* @var int $mailLogSent24hCount
|
||||
* @var int $mailLogFailed24hCount
|
||||
* @var int $mailLogQueued24hCount
|
||||
*/
|
||||
|
||||
?>
|
||||
<div class="app-breadcrumb">
|
||||
<a href="/admin"><?php e(t('Home')); ?></a><i class="bi bi-chevron-right"></i><?php e(t('Statistics')); ?>
|
||||
</div>
|
||||
<div class="app-dashboard-titlebar">
|
||||
<h1><?php e(t('Statistics')); ?></h1>
|
||||
<div class="app-dashboard-titlebar-actions">
|
||||
<!-- Optional actions -->
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="app-dashboard">
|
||||
<div class="app-tabs" data-tabs id="stats-tabs">
|
||||
<!-- Tab Navigation -->
|
||||
<div class="app-tabs-nav">
|
||||
<button data-tab="organization" data-tab-default class="transparent tab-button">
|
||||
<?php e(t('Organization')); ?>
|
||||
</button>
|
||||
<button data-tab="users-roles" class="transparent tab-button">
|
||||
<?php e(t('Users & roles')); ?>
|
||||
</button>
|
||||
<?php if (can('mail_log.view')): ?>
|
||||
<button data-tab="system" class="transparent tab-button">
|
||||
<?php e(t('System')); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Tab Panel: Organization -->
|
||||
<div data-tab-panel="organization">
|
||||
<div class="app-tiles">
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/tenants',
|
||||
'label' => t('Tenants'),
|
||||
'count' => (string) $tenantCount,
|
||||
'icon' => 'bi bi-building',
|
||||
'iconBg' => '#e9f0ff',
|
||||
'iconColor' => '#264db3',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/departments',
|
||||
'label' => t('Departments'),
|
||||
'count' => (string) $departmentCount,
|
||||
'icon' => 'bi bi-diagram-3-fill',
|
||||
'iconBg' => '#fff2d9',
|
||||
'iconColor' => '#9a5a00',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/users',
|
||||
'label' => t('Users'),
|
||||
'count' => (string) $userCount,
|
||||
'icon' => 'bi bi-people-fill',
|
||||
'iconBg' => '#d9f2e6',
|
||||
'iconColor' => '#1f6a3a',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php if (!empty($tenantBreakdown)): ?>
|
||||
<div class="app-stats-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<?php e(t('Tenant')); ?>
|
||||
</th>
|
||||
<th>
|
||||
<?php e(t('Departments')); ?>
|
||||
</th>
|
||||
<th>
|
||||
<?php e(t('Assigned users (Active/Inactive)')); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($tenantBreakdown as $item): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (can('tenants.view') && !empty($item['uuid'])): ?>
|
||||
<a href="admin/tenants/edit/<?php e($item['uuid']); ?>">
|
||||
<?php e($item['description']); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<?php e($item['description']); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php e($item['departments']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php e($item['total_users']); ?> <small>(
|
||||
<?php e($item['active_users']); ?> /
|
||||
<?php e($item['inactive_users']); ?>)
|
||||
</small>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Tab Panel: Users & Roles -->
|
||||
<div data-tab-panel="users-roles">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<div class="app-tiles">
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/users',
|
||||
'label' => t('Active users'),
|
||||
'count' => (string) $activeUserCount,
|
||||
'icon' => 'bi bi-person-check-fill',
|
||||
'iconBg' => '#d9f2e6',
|
||||
'iconColor' => '#1f6a3a',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/users',
|
||||
'label' => t('Inactive users'),
|
||||
'count' => (string) $inactiveUserCount,
|
||||
'icon' => 'bi bi-person-x-fill',
|
||||
'iconBg' => '#ffe9e9',
|
||||
'iconColor' => '#a32e2e',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="app-tiles">
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/roles',
|
||||
'label' => t('Roles'),
|
||||
'count' => (string) $roleCount,
|
||||
'icon' => 'bi bi-shield-lock-fill',
|
||||
'iconBg' => '#f3e9ff',
|
||||
'iconColor' => '#5b2c83',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/permissions',
|
||||
'label' => t('Permissions'),
|
||||
'count' => (string) $permissionCount,
|
||||
'icon' => 'bi bi-key-fill',
|
||||
'iconBg' => '#fff2d9',
|
||||
'iconColor' => '#9a5a00',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Panel: System -->
|
||||
<?php if (can('mail_log.view')): ?>
|
||||
<div data-tab-panel="system">
|
||||
<div class="grid">
|
||||
<div>
|
||||
<h4><?php e(t('Mail logs')); ?></h4>
|
||||
<div class="app-tiles">
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log',
|
||||
'label' => t('Total emails'),
|
||||
'count' => (string) $mailLogTotalCount,
|
||||
'icon' => 'bi bi-envelope-fill',
|
||||
'iconBg' => '#e9f0ff',
|
||||
'iconColor' => '#264db3',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?status=sent',
|
||||
'label' => t('Sent emails'),
|
||||
'count' => (string) $mailLogSentCount,
|
||||
'icon' => 'bi bi-envelope-check-fill',
|
||||
'iconBg' => '#d9f2e6',
|
||||
'iconColor' => '#1f6a3a',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?status=failed',
|
||||
'label' => t('Failed emails'),
|
||||
'count' => (string) $mailLogFailedCount,
|
||||
'icon' => 'bi bi-envelope-x-fill',
|
||||
'iconBg' => '#ffe9e9',
|
||||
'iconColor' => '#a32e2e',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log',
|
||||
'label' => t('Queued emails'),
|
||||
'count' => (string) $mailLogQueuedCount,
|
||||
'icon' => 'bi bi-envelope-paper-fill',
|
||||
'iconBg' => '#fff2d9',
|
||||
'iconColor' => '#9a5a00',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>
|
||||
<?php e(t('Last 24 hours')); ?>
|
||||
</h4>
|
||||
<div class="app-tiles">
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?created_from=' . urlencode($date24hAgo ?? '') . '&created_to=' . urlencode($dateToday ?? ''),
|
||||
'label' => t('Total (24h)'),
|
||||
'count' => (string) $mailLogTotal24hCount,
|
||||
'icon' => 'bi bi-envelope-fill',
|
||||
'iconBg' => '#e9f0ff',
|
||||
'iconColor' => '#264db3',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?status=sent&created_from=' . urlencode($date24hAgo ?? '') . '&created_to=' . urlencode($dateToday ?? ''),
|
||||
'label' => t('Sent (24h)'),
|
||||
'count' => (string) $mailLogSent24hCount,
|
||||
'icon' => 'bi bi-envelope-check-fill',
|
||||
'iconBg' => '#d9f2e6',
|
||||
'iconColor' => '#1f6a3a',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?status=failed&created_from=' . urlencode($date24hAgo ?? '') . '&created_to=' . urlencode($dateToday ?? ''),
|
||||
'label' => t('Failed (24h)'),
|
||||
'count' => (string) $mailLogFailed24hCount,
|
||||
'icon' => 'bi bi-envelope-x-fill',
|
||||
'iconBg' => '#ffe9e9',
|
||||
'iconColor' => '#a32e2e',
|
||||
]);
|
||||
?>
|
||||
<?php
|
||||
MintyPHP\Support\Tile::render([
|
||||
'href' => 'admin/mail-log?status=queued&created_from=' . urlencode($date24hAgo ?? '') . '&created_to=' . urlencode($dateToday ?? ''),
|
||||
'label' => t('Queued (24h)'),
|
||||
'count' => (string) $mailLogQueued24hCount,
|
||||
'icon' => 'bi bi-envelope-paper-fill',
|
||||
'iconBg' => '#fff2d9',
|
||||
'iconColor' => '#9a5a00',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user